[9581] Fixed apply damage reduction to melee/ranged damage.
[getmangos.git] / src / game / SpellMgr.cpp
blob9fcf50f37c9e84f2a92f471d42f4e6737bfe9ffd
1 /*
2 * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "SpellMgr.h"
20 #include "ObjectMgr.h"
21 #include "SpellAuraDefines.h"
22 #include "ProgressBar.h"
23 #include "DBCStores.h"
24 #include "World.h"
25 #include "Chat.h"
26 #include "Spell.h"
27 #include "BattleGroundMgr.h"
28 #include "MapManager.h"
30 SpellMgr::SpellMgr()
34 SpellMgr::~SpellMgr()
38 SpellMgr& SpellMgr::Instance()
40 static SpellMgr spellMgr;
41 return spellMgr;
44 int32 GetSpellDuration(SpellEntry const *spellInfo)
46 if(!spellInfo)
47 return 0;
48 SpellDurationEntry const *du = sSpellDurationStore.LookupEntry(spellInfo->DurationIndex);
49 if(!du)
50 return 0;
51 return (du->Duration[0] == -1) ? -1 : abs(du->Duration[0]);
54 int32 GetSpellMaxDuration(SpellEntry const *spellInfo)
56 if(!spellInfo)
57 return 0;
58 SpellDurationEntry const *du = sSpellDurationStore.LookupEntry(spellInfo->DurationIndex);
59 if(!du)
60 return 0;
61 return (du->Duration[2] == -1) ? -1 : abs(du->Duration[2]);
64 uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell)
66 // some triggered spells have data only usable for client
67 if (spell && spell->IsTriggeredSpellWithRedundentData())
68 return 0;
70 SpellCastTimesEntry const *spellCastTimeEntry = sSpellCastTimesStore.LookupEntry(spellInfo->CastingTimeIndex);
72 // not all spells have cast time index and this is all is pasiive abilities
73 if (!spellCastTimeEntry)
74 return 0;
76 int32 castTime = spellCastTimeEntry->CastTime;
78 if (spell)
80 if (Player* modOwner = spell->GetCaster()->GetSpellModOwner())
81 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell);
83 if (!(spellInfo->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_TRADESPELL)))
84 castTime = int32(castTime * spell->GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED));
85 else
87 if (spell->IsRangedSpell() && !spell->IsAutoRepeat())
88 castTime = int32(castTime * spell->GetCaster()->m_modAttackSpeedPct[RANGED_ATTACK]);
92 if (spellInfo->Attributes & SPELL_ATTR_RANGED && (!spell || !spell->IsAutoRepeat()))
93 castTime += 500;
95 return (castTime > 0) ? uint32(castTime) : 0;
98 uint16 GetSpellAuraMaxTicks(SpellEntry const* spellInfo)
100 int32 DotDuration = GetSpellDuration(spellInfo);
101 if(DotDuration == 0)
102 return 1;
104 // 200% limit
105 if(DotDuration > 30000)
106 DotDuration = 30000;
108 for (int j = 0; j < MAX_EFFECT_INDEX; ++j)
110 if (spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
111 spellInfo->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
112 spellInfo->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_HEAL ||
113 spellInfo->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) )
115 if (spellInfo->EffectAmplitude[j] != 0)
116 return DotDuration / spellInfo->EffectAmplitude[j];
117 break;
121 return 6;
124 WeaponAttackType GetWeaponAttackType(SpellEntry const *spellInfo)
126 if(!spellInfo)
127 return BASE_ATTACK;
129 switch (spellInfo->DmgClass)
131 case SPELL_DAMAGE_CLASS_MELEE:
132 if (spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
133 return OFF_ATTACK;
134 else
135 return BASE_ATTACK;
136 break;
137 case SPELL_DAMAGE_CLASS_RANGED:
138 return RANGED_ATTACK;
139 break;
140 default:
141 // Wands
142 if (spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG)
143 return RANGED_ATTACK;
144 else
145 return BASE_ATTACK;
146 break;
150 bool IsPassiveSpell(uint32 spellId)
152 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
153 if (!spellInfo)
154 return false;
155 return (spellInfo->Attributes & SPELL_ATTR_PASSIVE) != 0;
158 bool IsNoStackAuraDueToAura(uint32 spellId_1, SpellEffectIndex effIndex_1, uint32 spellId_2, SpellEffectIndex effIndex_2)
160 SpellEntry const *spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
161 SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
162 if(!spellInfo_1 || !spellInfo_2) return false;
163 if(spellInfo_1->Id == spellId_2) return false;
165 if (spellInfo_1->Effect[effIndex_1] != spellInfo_2->Effect[effIndex_2] ||
166 spellInfo_1->EffectItemType[effIndex_1] != spellInfo_2->EffectItemType[effIndex_2] ||
167 spellInfo_1->EffectMiscValue[effIndex_1] != spellInfo_2->EffectMiscValue[effIndex_2] ||
168 spellInfo_1->EffectApplyAuraName[effIndex_1] != spellInfo_2->EffectApplyAuraName[effIndex_2])
169 return false;
171 return true;
174 int32 CompareAuraRanks(uint32 spellId_1, SpellEffectIndex effIndex_1, uint32 spellId_2, SpellEffectIndex effIndex_2)
176 SpellEntry const*spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
177 SpellEntry const*spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
178 if(!spellInfo_1 || !spellInfo_2) return 0;
179 if (spellId_1 == spellId_2) return 0;
181 int32 diff = spellInfo_1->EffectBasePoints[effIndex_1] - spellInfo_2->EffectBasePoints[effIndex_2];
182 if (spellInfo_1->CalculateSimpleValue(effIndex_1) < 0 && spellInfo_2->CalculateSimpleValue(effIndex_2) < 0)
183 return -diff;
184 else return diff;
187 SpellSpecific GetSpellSpecific(uint32 spellId)
189 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
190 if(!spellInfo)
191 return SPELL_NORMAL;
193 switch(spellInfo->SpellFamilyName)
195 case SPELLFAMILY_GENERIC:
197 // Food / Drinks (mostly)
198 if(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED)
200 bool food = false;
201 bool drink = false;
202 for(int i = 0; i < MAX_EFFECT_INDEX; ++i)
204 switch(spellInfo->EffectApplyAuraName[i])
206 // Food
207 case SPELL_AURA_MOD_REGEN:
208 case SPELL_AURA_OBS_MOD_HEALTH:
209 food = true;
210 break;
211 // Drink
212 case SPELL_AURA_MOD_POWER_REGEN:
213 case SPELL_AURA_OBS_MOD_MANA:
214 drink = true;
215 break;
216 default:
217 break;
221 if(food && drink)
222 return SPELL_FOOD_AND_DRINK;
223 else if(food)
224 return SPELL_FOOD;
225 else if(drink)
226 return SPELL_DRINK;
228 else
230 // Well Fed buffs (must be exclusive with Food / Drink replenishment effects, or else Well Fed will cause them to be removed)
231 // SpellIcon 2560 is Spell 46687, does not have this flag
232 if ((spellInfo->AttributesEx2 & SPELL_ATTR_EX2_FOOD_BUFF) || spellInfo->SpellIconID == 2560)
233 return SPELL_WELL_FED;
235 break;
237 case SPELLFAMILY_MAGE:
239 // family flags 18(Molten), 25(Frost/Ice), 28(Mage)
240 if (spellInfo->SpellFamilyFlags & UI64LIT(0x12040000))
241 return SPELL_MAGE_ARMOR;
243 if ((spellInfo->SpellFamilyFlags & UI64LIT(0x1000000)) && spellInfo->EffectApplyAuraName[EFFECT_INDEX_0] == SPELL_AURA_MOD_CONFUSE)
244 return SPELL_MAGE_POLYMORPH;
246 break;
248 case SPELLFAMILY_WARRIOR:
250 if (spellInfo->SpellFamilyFlags & UI64LIT(0x00008000010000))
251 return SPELL_POSITIVE_SHOUT;
253 break;
255 case SPELLFAMILY_WARLOCK:
257 // only warlock curses have this
258 if (spellInfo->Dispel == DISPEL_CURSE)
259 return SPELL_CURSE;
261 // Warlock (Demon Armor | Demon Skin | Fel Armor)
262 if (spellInfo->SpellFamilyFlags & UI64LIT(0x2000002000000000) || spellInfo->SpellFamilyFlags2 & 0x00000010)
263 return SPELL_WARLOCK_ARMOR;
265 break;
267 case SPELLFAMILY_PRIEST:
269 // "Well Fed" buff from Blessed Sunfruit, Blessed Sunfruit Juice, Alterac Spring Water
270 if ((spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_SITTING) &&
271 (spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK) &&
272 (spellInfo->SpellIconID == 52 || spellInfo->SpellIconID == 79))
273 return SPELL_WELL_FED;
274 break;
276 case SPELLFAMILY_HUNTER:
278 // only hunter stings have this
279 if (spellInfo->Dispel == DISPEL_POISON)
280 return SPELL_STING;
282 // only hunter aspects have this (but not all aspects in hunter family)
283 if( spellInfo->SpellFamilyFlags & UI64LIT(0x0044000000380000) || spellInfo->SpellFamilyFlags2 & 0x00001010)
284 return SPELL_ASPECT;
286 break;
288 case SPELLFAMILY_PALADIN:
290 if (IsSealSpell(spellInfo))
291 return SPELL_SEAL;
293 if (spellInfo->SpellFamilyFlags & UI64LIT(0x0000000011010002))
294 return SPELL_BLESSING;
296 if (spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000002190))
297 return SPELL_HAND;
299 // skip Heart of the Crusader that have also same spell family mask
300 if ((spellInfo->SpellFamilyFlags & UI64LIT(0x00000820180400)) && (spellInfo->AttributesEx3 & 0x200) && (spellInfo->SpellIconID != 237))
301 return SPELL_JUDGEMENT;
303 // only paladin auras have this (for palaldin class family)
304 if( spellInfo->SpellFamilyFlags2 & 0x00000020 )
305 return SPELL_AURA;
307 break;
309 case SPELLFAMILY_SHAMAN:
311 if (IsElementalShield(spellInfo))
312 return SPELL_ELEMENTAL_SHIELD;
314 break;
317 case SPELLFAMILY_POTION:
318 return sSpellMgr.GetSpellElixirSpecific(spellInfo->Id);
320 case SPELLFAMILY_DEATHKNIGHT:
321 if (spellInfo->Category == 47)
322 return SPELL_PRESENCE;
323 break;
326 // Tracking spells
327 if(IsSpellHaveAura(spellInfo, SPELL_AURA_TRACK_CREATURES) || IsSpellHaveAura(spellInfo, SPELL_AURA_TRACK_RESOURCES))
328 return SPELL_TRACKER;
330 // elixirs can have different families, but potion most ofc.
331 if(SpellSpecific sp = sSpellMgr.GetSpellElixirSpecific(spellInfo->Id))
332 return sp;
334 return SPELL_NORMAL;
338 // target not allow have more one spell specific from same caster
339 bool IsSingleFromSpellSpecificPerTargetPerCaster(SpellSpecific spellSpec1,SpellSpecific spellSpec2)
341 switch(spellSpec1)
343 case SPELL_BLESSING:
344 case SPELL_AURA:
345 case SPELL_STING:
346 case SPELL_CURSE:
347 case SPELL_ASPECT:
348 case SPELL_POSITIVE_SHOUT:
349 case SPELL_JUDGEMENT:
350 case SPELL_HAND:
351 return spellSpec1==spellSpec2;
352 default:
353 return false;
357 // target not allow have more one ranks from spell from spell specific per target
358 bool IsSingleFromSpellSpecificSpellRanksPerTarget(SpellSpecific spellSpec1,SpellSpecific spellSpec2)
360 switch(spellSpec1)
362 case SPELL_BLESSING:
363 case SPELL_AURA:
364 case SPELL_CURSE:
365 case SPELL_ASPECT:
366 case SPELL_HAND:
367 return spellSpec1==spellSpec2;
368 default:
369 return false;
373 // target not allow have more one spell specific per target from any caster
374 bool IsSingleFromSpellSpecificPerTarget(SpellSpecific spellSpec1,SpellSpecific spellSpec2)
376 switch(spellSpec1)
378 case SPELL_SEAL:
379 case SPELL_TRACKER:
380 case SPELL_WARLOCK_ARMOR:
381 case SPELL_MAGE_ARMOR:
382 case SPELL_ELEMENTAL_SHIELD:
383 case SPELL_MAGE_POLYMORPH:
384 case SPELL_PRESENCE:
385 case SPELL_WELL_FED:
386 return spellSpec1==spellSpec2;
387 case SPELL_BATTLE_ELIXIR:
388 return spellSpec2==SPELL_BATTLE_ELIXIR
389 || spellSpec2==SPELL_FLASK_ELIXIR;
390 case SPELL_GUARDIAN_ELIXIR:
391 return spellSpec2==SPELL_GUARDIAN_ELIXIR
392 || spellSpec2==SPELL_FLASK_ELIXIR;
393 case SPELL_FLASK_ELIXIR:
394 return spellSpec2==SPELL_BATTLE_ELIXIR
395 || spellSpec2==SPELL_GUARDIAN_ELIXIR
396 || spellSpec2==SPELL_FLASK_ELIXIR;
397 case SPELL_FOOD:
398 return spellSpec2==SPELL_FOOD
399 || spellSpec2==SPELL_FOOD_AND_DRINK;
400 case SPELL_DRINK:
401 return spellSpec2==SPELL_DRINK
402 || spellSpec2==SPELL_FOOD_AND_DRINK;
403 case SPELL_FOOD_AND_DRINK:
404 return spellSpec2==SPELL_FOOD
405 || spellSpec2==SPELL_DRINK
406 || spellSpec2==SPELL_FOOD_AND_DRINK;
407 default:
408 return false;
412 bool IsPositiveTarget(uint32 targetA, uint32 targetB)
414 // non-positive targets
415 switch(targetA)
417 case TARGET_CHAIN_DAMAGE:
418 case TARGET_ALL_ENEMY_IN_AREA:
419 case TARGET_ALL_ENEMY_IN_AREA_INSTANT:
420 case TARGET_IN_FRONT_OF_CASTER:
421 case TARGET_ALL_ENEMY_IN_AREA_CHANNELED:
422 case TARGET_CURRENT_ENEMY_COORDINATES:
423 case TARGET_SINGLE_ENEMY:
424 case TARGET_IN_FRONT_OF_CASTER_30:
425 return false;
426 case TARGET_CASTER_COORDINATES:
427 return (targetB == TARGET_ALL_PARTY || targetB == TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER);
428 default:
429 break;
431 if (targetB)
432 return IsPositiveTarget(targetB, 0);
433 return true;
436 bool IsExplicitPositiveTarget(uint32 targetA)
438 // positive targets that in target selection code expect target in m_targers, so not that auto-select target by spell data by m_caster and etc
439 switch(targetA)
441 case TARGET_SINGLE_FRIEND:
442 case TARGET_SINGLE_PARTY:
443 case TARGET_CHAIN_HEAL:
444 case TARGET_SINGLE_FRIEND_2:
445 case TARGET_AREAEFFECT_PARTY_AND_CLASS:
446 return true;
447 default:
448 break;
450 return false;
453 bool IsExplicitNegativeTarget(uint32 targetA)
455 // non-positive targets that in target selection code expect target in m_targers, so not that auto-select target by spell data by m_caster and etc
456 switch(targetA)
458 case TARGET_CHAIN_DAMAGE:
459 case TARGET_CURRENT_ENEMY_COORDINATES:
460 case TARGET_SINGLE_ENEMY:
461 return true;
462 default:
463 break;
465 return false;
468 bool IsPositiveEffect(uint32 spellId, SpellEffectIndex effIndex)
470 SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
471 if (!spellproto) return false;
473 switch(spellproto->Effect[effIndex])
475 case SPELL_EFFECT_DUMMY:
476 // some explicitly required dummy effect sets
477 switch(spellId)
479 case 28441: // AB Effect 000
480 return false;
481 default:
482 break;
484 break;
485 // always positive effects (check before target checks that provided non-positive result in some case for positive effects)
486 case SPELL_EFFECT_HEAL:
487 case SPELL_EFFECT_LEARN_SPELL:
488 case SPELL_EFFECT_SKILL_STEP:
489 case SPELL_EFFECT_HEAL_PCT:
490 case SPELL_EFFECT_ENERGIZE_PCT:
491 return true;
493 // non-positive aura use
494 case SPELL_EFFECT_APPLY_AURA:
495 case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
497 switch(spellproto->EffectApplyAuraName[effIndex])
499 case SPELL_AURA_DUMMY:
501 // dummy aura can be positive or negative dependent from casted spell
502 switch(spellproto->Id)
504 case 13139: // net-o-matic special effect
505 case 23445: // evil twin
506 case 35679: // Protectorate Demolitionist
507 case 38637: // Nether Exhaustion (red)
508 case 38638: // Nether Exhaustion (green)
509 case 38639: // Nether Exhaustion (blue)
510 case 11196: // Recently Bandaged
511 case 44689: // Relay Race Accept Hidden Debuff - DND
512 case 58600: // Restricted Flight Area
513 return false;
514 // some spells have unclear target modes for selection, so just make effect positive
515 case 27184:
516 case 27190:
517 case 27191:
518 case 27201:
519 case 27202:
520 case 27203:
521 return true;
522 default:
523 break;
525 } break;
526 case SPELL_AURA_MOD_DAMAGE_DONE: // dependent from base point sign (negative -> negative)
527 case SPELL_AURA_MOD_STAT:
528 case SPELL_AURA_MOD_SKILL:
529 case SPELL_AURA_MOD_HEALING_PCT:
530 case SPELL_AURA_MOD_HEALING_DONE:
531 if(spellproto->CalculateSimpleValue(effIndex) < 0)
532 return false;
533 break;
534 case SPELL_AURA_MOD_DAMAGE_TAKEN: // dependent from bas point sign (positive -> negative)
535 if(spellproto->CalculateSimpleValue(effIndex) > 0)
536 return false;
537 break;
538 case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
539 case SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT:
540 case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE:
541 if(spellproto->CalculateSimpleValue(effIndex) > 0)
542 return true; // some expected positive spells have SPELL_ATTR_EX_NEGATIVE or unclear target modes
543 break;
544 case SPELL_AURA_ADD_TARGET_TRIGGER:
545 return true;
546 case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
547 if (spellId != spellproto->EffectTriggerSpell[effIndex])
549 uint32 spellTriggeredId = spellproto->EffectTriggerSpell[effIndex];
550 SpellEntry const *spellTriggeredProto = sSpellStore.LookupEntry(spellTriggeredId);
552 if (spellTriggeredProto)
554 // non-positive targets of main spell return early
555 for(int i = 0; i < MAX_EFFECT_INDEX; ++i)
557 // if non-positive trigger cast targeted to positive target this main cast is non-positive
558 // this will place this spell auras as debuffs
559 if (IsPositiveTarget(spellTriggeredProto->EffectImplicitTargetA[effIndex],spellTriggeredProto->EffectImplicitTargetB[effIndex]) &&
560 !IsPositiveEffect(spellTriggeredId,SpellEffectIndex(i)))
561 return false;
565 break;
566 case SPELL_AURA_PROC_TRIGGER_SPELL:
567 // many positive auras have negative triggered spells at damage for example and this not make it negative (it can be canceled for example)
568 break;
569 case SPELL_AURA_MOD_STUN: //have positive and negative spells, we can't sort its correctly at this moment.
570 if (effIndex == EFFECT_INDEX_0 && spellproto->Effect[EFFECT_INDEX_1] == 0 && spellproto->Effect[EFFECT_INDEX_2] == 0)
571 return false; // but all single stun aura spells is negative
573 // Petrification
574 if(spellproto->Id == 17624)
575 return false;
576 break;
577 case SPELL_AURA_MOD_PACIFY_SILENCE:
578 switch(spellproto->Id)
580 case 24740: // Wisp Costume
581 case 47585: // Dispersion
582 return true;
583 default: break;
585 return false;
586 case SPELL_AURA_MOD_ROOT:
587 case SPELL_AURA_MOD_SILENCE:
588 case SPELL_AURA_GHOST:
589 case SPELL_AURA_PERIODIC_LEECH:
590 case SPELL_AURA_MOD_STALKED:
591 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
592 return false;
593 case SPELL_AURA_PERIODIC_DAMAGE: // used in positive spells also.
594 // part of negative spell if casted at self (prevent cancel)
595 if (spellproto->EffectImplicitTargetA[effIndex] == TARGET_SELF ||
596 spellproto->EffectImplicitTargetA[effIndex] == TARGET_SELF2)
597 return false;
598 break;
599 case SPELL_AURA_MOD_DECREASE_SPEED: // used in positive spells also
600 // part of positive spell if casted at self
601 if ((spellproto->EffectImplicitTargetA[effIndex] == TARGET_SELF ||
602 spellproto->EffectImplicitTargetA[effIndex] == TARGET_SELF2) &&
603 spellproto->SpellFamilyName == SPELLFAMILY_GENERIC)
604 return false;
605 // but not this if this first effect (don't found better check)
606 if (spellproto->Attributes & 0x4000000 && effIndex == EFFECT_INDEX_0)
607 return false;
608 break;
609 case SPELL_AURA_TRANSFORM:
610 // some spells negative
611 switch(spellproto->Id)
613 case 36897: // Transporter Malfunction (race mutation to horde)
614 case 36899: // Transporter Malfunction (race mutation to alliance)
615 return false;
617 break;
618 case SPELL_AURA_MOD_SCALE:
619 // some spells negative
620 switch(spellproto->Id)
622 case 802: // Mutate Bug, wrongly negative by target modes
623 return true;
624 case 36900: // Soul Split: Evil!
625 case 36901: // Soul Split: Good
626 case 36893: // Transporter Malfunction (decrease size case)
627 case 36895: // Transporter Malfunction (increase size case)
628 return false;
630 break;
631 case SPELL_AURA_MECHANIC_IMMUNITY:
633 // non-positive immunities
634 switch(spellproto->EffectMiscValue[effIndex])
636 case MECHANIC_BANDAGE:
637 case MECHANIC_SHIELD:
638 case MECHANIC_MOUNT:
639 case MECHANIC_INVULNERABILITY:
640 return false;
641 default:
642 break;
644 } break;
645 case SPELL_AURA_ADD_FLAT_MODIFIER: // mods
646 case SPELL_AURA_ADD_PCT_MODIFIER:
648 // non-positive mods
649 switch(spellproto->EffectMiscValue[effIndex])
651 case SPELLMOD_COST: // dependent from bas point sign (negative -> positive)
652 if(spellproto->CalculateSimpleValue(effIndex) > 0)
653 return false;
654 break;
655 default:
656 break;
658 } break;
659 case SPELL_AURA_FORCE_REACTION:
660 if(spellproto->Id==42792) // Recently Dropped Flag (prevent cancel)
661 return false;
662 break;
663 default:
664 break;
666 break;
668 default:
669 break;
672 // non-positive targets
673 if(!IsPositiveTarget(spellproto->EffectImplicitTargetA[effIndex],spellproto->EffectImplicitTargetB[effIndex]))
674 return false;
676 // AttributesEx check
677 if(spellproto->AttributesEx & SPELL_ATTR_EX_NEGATIVE)
678 return false;
680 // ok, positive
681 return true;
684 bool IsPositiveSpell(uint32 spellId)
686 SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
687 if (!spellproto)
688 return false;
690 // spells with atleast one negative effect are considered negative
691 // some self-applied spells have negative effects but in self casting case negative check ignored.
692 for (int i = 0; i < MAX_EFFECT_INDEX; ++i)
693 if (!IsPositiveEffect(spellId, SpellEffectIndex(i)))
694 return false;
695 return true;
698 bool IsSingleTargetSpell(SpellEntry const *spellInfo)
700 // all other single target spells have if it has AttributesEx5
701 if ( spellInfo->AttributesEx5 & SPELL_ATTR_EX5_SINGLE_TARGET_SPELL )
702 return true;
704 // TODO - need found Judgements rule
705 switch(GetSpellSpecific(spellInfo->Id))
707 case SPELL_JUDGEMENT:
708 return true;
709 default:
710 break;
713 // single target triggered spell.
714 // Not real client side single target spell, but it' not triggered until prev. aura expired.
715 // This is allow store it in single target spells list for caster for spell proc checking
716 if(spellInfo->Id==38324) // Regeneration (triggered by 38299 (HoTs on Heals))
717 return true;
719 return false;
722 bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellInfo2)
724 // TODO - need better check
725 // Equal icon and spellfamily
726 if( spellInfo1->SpellFamilyName == spellInfo2->SpellFamilyName &&
727 spellInfo1->SpellIconID == spellInfo2->SpellIconID )
728 return true;
730 // TODO - need found Judgements rule
731 SpellSpecific spec1 = GetSpellSpecific(spellInfo1->Id);
732 // spell with single target specific types
733 switch(spec1)
735 case SPELL_JUDGEMENT:
736 case SPELL_MAGE_POLYMORPH:
737 if(GetSpellSpecific(spellInfo2->Id) == spec1)
738 return true;
739 break;
740 default:
741 break;
744 return false;
747 SpellCastResult GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
749 // talents that learn spells can have stance requirements that need ignore
750 // (this requirement only for client-side stance show in talent description)
751 if( GetTalentSpellCost(spellInfo->Id) > 0 &&
752 (spellInfo->Effect[EFFECT_INDEX_0] == SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[EFFECT_INDEX_1] == SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[EFFECT_INDEX_2] == SPELL_EFFECT_LEARN_SPELL) )
753 return SPELL_CAST_OK;
755 uint32 stanceMask = (form ? 1 << (form - 1) : 0);
757 if (stanceMask & spellInfo->StancesNot) // can explicitly not be casted in this stance
758 return SPELL_FAILED_NOT_SHAPESHIFT;
760 if (stanceMask & spellInfo->Stances) // can explicitly be casted in this stance
761 return SPELL_CAST_OK;
763 bool actAsShifted = false;
764 if (form > 0)
766 SpellShapeshiftEntry const *shapeInfo = sSpellShapeshiftStore.LookupEntry(form);
767 if (!shapeInfo)
769 sLog.outError("GetErrorAtShapeshiftedCast: unknown shapeshift %u", form);
770 return SPELL_CAST_OK;
772 actAsShifted = !(shapeInfo->flags1 & 1); // shapeshift acts as normal form for spells
775 if(actAsShifted)
777 if (spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) // not while shapeshifted
778 return SPELL_FAILED_NOT_SHAPESHIFT;
779 else if (spellInfo->Stances != 0) // needs other shapeshift
780 return SPELL_FAILED_ONLY_SHAPESHIFT;
782 else
784 // needs shapeshift
785 if(!(spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT) && spellInfo->Stances != 0)
786 return SPELL_FAILED_ONLY_SHAPESHIFT;
789 return SPELL_CAST_OK;
792 void SpellMgr::LoadSpellTargetPositions()
794 mSpellTargetPositions.clear(); // need for reload case
796 uint32 count = 0;
798 // 0 1 2 3 4 5
799 QueryResult *result = WorldDatabase.Query("SELECT id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM spell_target_position");
800 if (!result)
803 barGoLink bar( 1 );
805 bar.step();
807 sLog.outString();
808 sLog.outString( ">> Loaded %u spell target coordinates", count );
809 return;
812 barGoLink bar((int)result->GetRowCount());
816 Field *fields = result->Fetch();
818 bar.step();
820 uint32 Spell_ID = fields[0].GetUInt32();
822 SpellTargetPosition st;
824 st.target_mapId = fields[1].GetUInt32();
825 st.target_X = fields[2].GetFloat();
826 st.target_Y = fields[3].GetFloat();
827 st.target_Z = fields[4].GetFloat();
828 st.target_Orientation = fields[5].GetFloat();
830 MapEntry const* mapEntry = sMapStore.LookupEntry(st.target_mapId);
831 if (!mapEntry)
833 sLog.outErrorDb("Spell (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Spell_ID,st.target_mapId);
834 continue;
837 if (st.target_X==0 && st.target_Y==0 && st.target_Z==0)
839 sLog.outErrorDb("Spell (ID:%u) target coordinates not provided.",Spell_ID);
840 continue;
843 SpellEntry const* spellInfo = sSpellStore.LookupEntry(Spell_ID);
844 if (!spellInfo)
846 sLog.outErrorDb("Spell (ID:%u) listed in `spell_target_position` does not exist.",Spell_ID);
847 continue;
850 bool found = false;
851 for(int i = 0; i < MAX_EFFECT_INDEX; ++i)
853 if (spellInfo->EffectImplicitTargetA[i]==TARGET_TABLE_X_Y_Z_COORDINATES || spellInfo->EffectImplicitTargetB[i]==TARGET_TABLE_X_Y_Z_COORDINATES)
855 // additional requirements
856 if (spellInfo->Effect[i]==SPELL_EFFECT_BIND && spellInfo->EffectMiscValue[i])
858 uint32 zone_id = sMapMgr.GetAreaId(st.target_mapId, st.target_X, st.target_Y, st.target_Z);
859 if (zone_id != spellInfo->EffectMiscValue[i])
861 sLog.outErrorDb("Spell (Id: %u) listed in `spell_target_position` expected point to zone %u bit point to zone %u.",Spell_ID, spellInfo->EffectMiscValue[i], zone_id);
862 break;
866 found = true;
867 break;
870 if (!found)
872 sLog.outErrorDb("Spell (Id: %u) listed in `spell_target_position` does not have target TARGET_TABLE_X_Y_Z_COORDINATES (17).",Spell_ID);
873 continue;
876 mSpellTargetPositions[Spell_ID] = st;
877 ++count;
879 } while( result->NextRow() );
881 delete result;
883 sLog.outString();
884 sLog.outString( ">> Loaded %u spell teleport coordinates", count );
887 struct DoSpellProcEvent
889 DoSpellProcEvent(SpellProcEventEntry const& _spe) : spe(_spe) {}
890 void operator() (uint32 spell_id) { sSpellMgr.mSpellProcEventMap[spell_id] = spe; }
891 SpellProcEventEntry const& spe;
894 void SpellMgr::LoadSpellProcEvents()
896 mSpellProcEventMap.clear(); // need for reload case
898 uint32 count = 0;
900 // 0 1 2 3 4 5 6 7 8 9 10
901 QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
902 if( !result )
904 barGoLink bar( 1 );
905 bar.step();
906 sLog.outString();
907 sLog.outString( ">> Loaded %u spell proc event conditions", count );
908 return;
911 barGoLink bar( (int)result->GetRowCount() );
912 uint32 customProc = 0;
915 Field *fields = result->Fetch();
917 bar.step();
919 uint32 entry = fields[0].GetUInt32();
921 const SpellEntry *spell = sSpellStore.LookupEntry(entry);
922 if (!spell)
924 sLog.outErrorDb("Spell %u listed in `spell_proc_event` does not exist", entry);
925 continue;
928 uint32 first_id = GetFirstSpellInChain(entry);
930 if ( first_id != entry )
932 sLog.outErrorDb("Spell %u listed in `spell_proc_event` is not first rank (%u) in chain", entry, first_id);
933 // prevent loading since it won't have an effect anyway
934 continue;
937 SpellProcEventEntry spe;
939 spe.schoolMask = fields[1].GetUInt32();
940 spe.spellFamilyName = fields[2].GetUInt32();
941 spe.spellFamilyMask = (uint64)fields[3].GetUInt32()|((uint64)fields[4].GetUInt32()<<32);
942 spe.spellFamilyMask2= fields[5].GetUInt32();
943 spe.procFlags = fields[6].GetUInt32();
944 spe.procEx = fields[7].GetUInt32();
945 spe.ppmRate = fields[8].GetFloat();
946 spe.customChance = fields[9].GetFloat();
947 spe.cooldown = fields[10].GetUInt32();
949 mSpellProcEventMap[entry] = spe;
951 // also add to high ranks
952 DoSpellProcEvent worker(spe);
953 doForHighRanks(entry,worker);
955 if (spell->procFlags==0)
957 if (spe.procFlags == 0)
959 sLog.outErrorDb("Spell %u listed in `spell_proc_event` probally not triggered spell", entry);
960 continue;
962 customProc++;
964 ++count;
965 } while( result->NextRow() );
967 delete result;
969 sLog.outString();
970 if (customProc)
971 sLog.outString( ">> Loaded %u extra spell proc event conditions +%u custom", count, customProc );
972 else
973 sLog.outString( ">> Loaded %u extra spell proc event conditions", count );
976 struct DoSpellProcItemEnchant
978 DoSpellProcItemEnchant(float _ppm) : ppm(_ppm) {}
979 void operator() (uint32 spell_id) { sSpellMgr.mSpellProcItemEnchantMap[spell_id] = ppm; }
980 float ppm;
983 void SpellMgr::LoadSpellProcItemEnchant()
985 mSpellProcItemEnchantMap.clear(); // need for reload case
987 uint32 count = 0;
989 // 0 1
990 QueryResult *result = WorldDatabase.Query("SELECT entry, ppmRate FROM spell_proc_item_enchant");
991 if( !result )
994 barGoLink bar( 1 );
996 bar.step();
998 sLog.outString();
999 sLog.outString( ">> Loaded %u proc item enchant definitions", count );
1000 return;
1003 barGoLink bar( (int)result->GetRowCount() );
1007 Field *fields = result->Fetch();
1009 bar.step();
1011 uint32 entry = fields[0].GetUInt32();
1012 float ppmRate = fields[1].GetFloat();
1014 SpellEntry const* spellInfo = sSpellStore.LookupEntry(entry);
1016 if (!spellInfo)
1018 sLog.outErrorDb("Spell %u listed in `spell_proc_item_enchant` does not exist", entry);
1019 continue;
1022 uint32 first_id = GetFirstSpellInChain(entry);
1024 if ( first_id != entry )
1026 sLog.outErrorDb("Spell %u listed in `spell_proc_item_enchant` is not first rank (%u) in chain", entry, first_id);
1027 // prevent loading since it won't have an effect anyway
1028 continue;
1031 mSpellProcItemEnchantMap[entry] = ppmRate;
1033 // also add to high ranks
1034 DoSpellProcItemEnchant worker(ppmRate);
1035 doForHighRanks(entry,worker);
1037 ++count;
1038 } while( result->NextRow() );
1040 delete result;
1042 sLog.outString();
1043 sLog.outString( ">> Loaded %u proc item enchant definitions", count );
1046 struct DoSpellBonusess
1048 DoSpellBonusess(SpellBonusEntry const& _spellBonus) : spellBonus(_spellBonus) {}
1049 void operator() (uint32 spell_id) { sSpellMgr.mSpellBonusMap[spell_id] = spellBonus; }
1050 SpellBonusEntry const& spellBonus;
1053 void SpellMgr::LoadSpellBonusess()
1055 mSpellBonusMap.clear(); // need for reload case
1056 uint32 count = 0;
1057 // 0 1 2 3
1058 QueryResult *result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus FROM spell_bonus_data");
1059 if( !result )
1061 barGoLink bar( 1 );
1062 bar.step();
1063 sLog.outString();
1064 sLog.outString( ">> Loaded %u spell bonus data", count);
1065 return;
1068 barGoLink bar( (int)result->GetRowCount() );
1071 Field *fields = result->Fetch();
1072 bar.step();
1073 uint32 entry = fields[0].GetUInt32();
1075 SpellEntry const* spell = sSpellStore.LookupEntry(entry);
1076 if (!spell)
1078 sLog.outErrorDb("Spell %u listed in `spell_bonus_data` does not exist", entry);
1079 continue;
1082 uint32 first_id = GetFirstSpellInChain(entry);
1084 if ( first_id != entry )
1086 sLog.outErrorDb("Spell %u listed in `spell_bonus_data` is not first rank (%u) in chain", entry, first_id);
1087 // prevent loading since it won't have an effect anyway
1088 continue;
1091 SpellBonusEntry sbe;
1093 sbe.direct_damage = fields[1].GetFloat();
1094 sbe.dot_damage = fields[2].GetFloat();
1095 sbe.ap_bonus = fields[3].GetFloat();
1097 mSpellBonusMap[entry] = sbe;
1099 // also add to high ranks
1100 DoSpellBonusess worker(sbe);
1101 doForHighRanks(entry,worker);
1103 ++count;
1105 } while( result->NextRow() );
1107 delete result;
1109 sLog.outString();
1110 sLog.outString( ">> Loaded %u extra spell bonus data", count);
1113 bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active)
1115 // No extra req need
1116 uint32 procEvent_procEx = PROC_EX_NONE;
1118 // check prockFlags for condition
1119 if((procFlags & EventProcFlag) == 0)
1120 return false;
1122 // Always trigger for this
1123 if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_ON_TRAP_ACTIVATION))
1124 return true;
1126 if (spellProcEvent) // Exist event data
1128 // Store extra req
1129 procEvent_procEx = spellProcEvent->procEx;
1131 // For melee triggers
1132 if (procSpell == NULL)
1134 // Check (if set) for school (melee attack have Normal school)
1135 if(spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
1136 return false;
1138 else // For spells need check school/spell family/family mask
1140 // Check (if set) for school
1141 if(spellProcEvent->schoolMask && (spellProcEvent->schoolMask & procSpell->SchoolMask) == 0)
1142 return false;
1144 // Check (if set) for spellFamilyName
1145 if(spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
1146 return false;
1148 // spellFamilyName is Ok need check for spellFamilyMask if present
1149 if(spellProcEvent->spellFamilyMask || spellProcEvent->spellFamilyMask2)
1151 if ((spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags ) == 0 &&
1152 (spellProcEvent->spellFamilyMask2 & procSpell->SpellFamilyFlags2) == 0)
1153 return false;
1154 active = true; // Spell added manualy -> so its active spell
1158 // Check for extra req (if none) and hit/crit
1159 if (procEvent_procEx == PROC_EX_NONE)
1161 // No extra req, so can trigger only for active (damage/healing present) and hit/crit
1162 if((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && active)
1163 return true;
1165 else // Passive spells hits here only if resist/reflect/immune/evade
1167 // Exist req for PROC_EX_EX_TRIGGER_ALWAYS
1168 if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS)
1169 return true;
1170 // Passive spells can`t trigger if need hit (exclude cases when procExtra include non-active flags)
1171 if ((procEvent_procEx & PROC_EX_NORMAL_HIT & procExtra) && !active)
1172 return false;
1173 // Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other)
1174 if (procEvent_procEx & procExtra)
1175 return true;
1177 return false;
1180 void SpellMgr::LoadSpellElixirs()
1182 mSpellElixirs.clear(); // need for reload case
1184 uint32 count = 0;
1186 // 0 1
1187 QueryResult *result = WorldDatabase.Query("SELECT entry, mask FROM spell_elixir");
1188 if( !result )
1191 barGoLink bar( 1 );
1193 bar.step();
1195 sLog.outString();
1196 sLog.outString( ">> Loaded %u spell elixir definitions", count );
1197 return;
1200 barGoLink bar( (int)result->GetRowCount() );
1204 Field *fields = result->Fetch();
1206 bar.step();
1208 uint32 entry = fields[0].GetUInt32();
1209 uint8 mask = fields[1].GetUInt8();
1211 SpellEntry const* spellInfo = sSpellStore.LookupEntry(entry);
1213 if (!spellInfo)
1215 sLog.outErrorDb("Spell %u listed in `spell_elixir` does not exist", entry);
1216 continue;
1219 mSpellElixirs[entry] = mask;
1221 ++count;
1222 } while( result->NextRow() );
1224 delete result;
1226 sLog.outString();
1227 sLog.outString( ">> Loaded %u spell elixir definitions", count );
1230 void SpellMgr::LoadSpellThreats()
1232 mSpellThreatMap.clear(); // need for reload case
1234 uint32 count = 0;
1236 // 0 1
1237 QueryResult *result = WorldDatabase.Query("SELECT entry, Threat FROM spell_threat");
1238 if( !result )
1241 barGoLink bar( 1 );
1243 bar.step();
1245 sLog.outString();
1246 sLog.outString( ">> Loaded %u aggro generating spells", count );
1247 return;
1250 barGoLink bar( (int)result->GetRowCount() );
1254 Field *fields = result->Fetch();
1256 bar.step();
1258 uint32 entry = fields[0].GetUInt32();
1259 uint16 Threat = fields[1].GetUInt16();
1261 if (!sSpellStore.LookupEntry(entry))
1263 sLog.outErrorDb("Spell %u listed in `spell_threat` does not exist", entry);
1264 continue;
1267 mSpellThreatMap[entry] = Threat;
1269 ++count;
1270 } while( result->NextRow() );
1272 delete result;
1274 sLog.outString();
1275 sLog.outString( ">> Loaded %u aggro generating spells", count );
1278 bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellId_2) const
1280 SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
1281 if(!spellInfo_1 || !spellInfo_2) return false;
1282 if(spellInfo_1->Id == spellId_2) return false;
1284 return GetFirstSpellInChain(spellInfo_1->Id)==GetFirstSpellInChain(spellId_2);
1287 bool SpellMgr::canStackSpellRanks(SpellEntry const *spellInfo)
1289 if(IsPassiveSpell(spellInfo->Id)) // ranked passive spell
1290 return false;
1291 if(spellInfo->powerType != POWER_MANA && spellInfo->powerType != POWER_HEALTH)
1292 return false;
1293 if(IsProfessionOrRidingSpell(spellInfo->Id))
1294 return false;
1296 if(sSpellMgr.IsSkillBonusSpell(spellInfo->Id))
1297 return false;
1299 // All stance spells. if any better way, change it.
1300 for (int i = 0; i < MAX_EFFECT_INDEX; ++i)
1302 switch(spellInfo->SpellFamilyName)
1304 case SPELLFAMILY_PALADIN:
1305 // Paladin aura Spell
1306 if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AREA_AURA_RAID)
1307 return false;
1308 break;
1309 case SPELLFAMILY_DRUID:
1310 // Druid form Spell
1311 if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA &&
1312 spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
1313 return false;
1314 break;
1315 case SPELLFAMILY_ROGUE:
1316 // Rogue Stealth
1317 if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA &&
1318 spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
1319 return false;
1320 break;
1323 return true;
1326 bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) const
1328 SpellEntry const *spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
1329 SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
1331 if(!spellInfo_1 || !spellInfo_2)
1332 return false;
1334 if(spellId_1 == spellId_2)
1335 return false;
1337 //I think we don't check this correctly because i need a exception for spell:
1338 //72,11327,18461...(called from 1856,1857...) Call Aura 16,31, after trigger another spell who call aura 77 and 77 remove 16 and 31, this should not happen.
1339 if(spellInfo_2->SpellFamilyFlags == 2048)
1340 return false;
1342 // Resurrection sickness
1343 if((spellInfo_1->Id == SPELL_ID_PASSIVE_RESURRECTION_SICKNESS) != (spellInfo_2->Id==SPELL_ID_PASSIVE_RESURRECTION_SICKNESS))
1344 return false;
1346 // Allow stack passive and not passive spells
1347 if ((spellInfo_1->Attributes & SPELL_ATTR_PASSIVE)!=(spellInfo_2->Attributes & SPELL_ATTR_PASSIVE))
1348 return false;
1350 // Specific spell family spells
1351 switch(spellInfo_1->SpellFamilyName)
1353 case SPELLFAMILY_GENERIC:
1354 switch(spellInfo_2->SpellFamilyName)
1356 case SPELLFAMILY_GENERIC: // same family case
1358 // Thunderfury
1359 if ((spellInfo_1->Id == 21992 && spellInfo_2->Id == 27648) ||
1360 (spellInfo_2->Id == 21992 && spellInfo_1->Id == 27648))
1361 return false;
1363 // Lightning Speed (Mongoose) and Fury of the Crashing Waves (Tsunami Talisman)
1364 if ((spellInfo_1->Id == 28093 && spellInfo_2->Id == 42084) ||
1365 (spellInfo_2->Id == 28093 && spellInfo_1->Id == 42084))
1366 return false;
1368 // Soulstone Resurrection and Twisting Nether (resurrector)
1369 if( spellInfo_1->SpellIconID == 92 && spellInfo_2->SpellIconID == 92 && (
1370 spellInfo_1->SpellVisual[0] == 99 && spellInfo_2->SpellVisual[0] == 0 ||
1371 spellInfo_2->SpellVisual[0] == 99 && spellInfo_1->SpellVisual[0] == 0 ) )
1372 return false;
1374 // Heart of the Wild, Agility and various Idol Triggers
1375 if(spellInfo_1->SpellIconID == 240 && spellInfo_2->SpellIconID == 240)
1376 return false;
1378 // Personalized Weather (thunder effect should overwrite rainy aura)
1379 if(spellInfo_1->SpellIconID == 2606 && spellInfo_2->SpellIconID == 2606)
1380 return false;
1382 // Brood Affliction: Bronze
1383 if( (spellInfo_1->Id == 23170 && spellInfo_2->Id == 23171) ||
1384 (spellInfo_2->Id == 23170 && spellInfo_1->Id == 23171) )
1385 return false;
1387 // Cool Down (See PeriodicAuraTick())
1388 if ((spellInfo_1->Id == 52441 && spellInfo_2->Id == 52443) ||
1389 (spellInfo_2->Id == 52441 && spellInfo_1->Id == 52443))
1390 return false;
1392 // See Chapel Invisibility and See Noth Invisibility
1393 if( (spellInfo_1->Id == 52950 && spellInfo_2->Id == 52707) ||
1394 (spellInfo_2->Id == 52950 && spellInfo_1->Id == 52707) )
1395 return false;
1397 // Regular and Night Elf Ghost
1398 if( (spellInfo_1->Id == 8326 && spellInfo_2->Id == 20584) ||
1399 (spellInfo_2->Id == 8326 && spellInfo_1->Id == 20584) )
1400 return false;
1402 break;
1404 case SPELLFAMILY_MAGE:
1405 // Arcane Intellect and Insight
1406 if( spellInfo_2->SpellIconID == 125 && spellInfo_1->Id == 18820 )
1407 return false;
1408 break;
1409 case SPELLFAMILY_WARRIOR:
1411 // Scroll of Protection and Defensive Stance (multi-family check)
1412 if( spellInfo_1->SpellIconID == 276 && spellInfo_1->SpellVisual[0] == 196 && spellInfo_2->Id == 71)
1413 return false;
1415 // Improved Hamstring -> Hamstring (multi-family check)
1416 if( (spellInfo_2->SpellFamilyFlags & UI64LIT(0x2)) && spellInfo_1->Id == 23694 )
1417 return false;
1419 break;
1421 case SPELLFAMILY_DRUID:
1423 // Scroll of Stamina and Leader of the Pack (multi-family check)
1424 if( spellInfo_1->SpellIconID == 312 && spellInfo_1->SpellVisual[0] == 216 && spellInfo_2->Id == 24932 )
1425 return false;
1427 // Dragonmaw Illusion (multi-family check)
1428 if (spellId_1 == 40216 && spellId_2 == 42016 )
1429 return false;
1431 break;
1433 case SPELLFAMILY_ROGUE:
1435 // Garrote-Silence -> Garrote (multi-family check)
1436 if( spellInfo_1->SpellIconID == 498 && spellInfo_1->SpellVisual[0] == 0 && spellInfo_2->SpellIconID == 498 )
1437 return false;
1439 break;
1441 case SPELLFAMILY_HUNTER:
1443 // Concussive Shot and Imp. Concussive Shot (multi-family check)
1444 if( spellInfo_1->Id == 19410 && spellInfo_2->Id == 5116 )
1445 return false;
1447 // Improved Wing Clip -> Wing Clip (multi-family check)
1448 if( (spellInfo_2->SpellFamilyFlags & UI64LIT(0x40)) && spellInfo_1->Id == 19229 )
1449 return false;
1450 break;
1452 case SPELLFAMILY_PALADIN:
1454 // Unstable Currents and other -> *Sanctity Aura (multi-family check)
1455 if( spellInfo_2->SpellIconID==502 && spellInfo_1->SpellIconID==502 && spellInfo_1->SpellVisual[0]==969 )
1456 return false;
1458 // *Band of Eternal Champion and Seal of Command(multi-family check)
1459 if( spellId_1 == 35081 && spellInfo_2->SpellIconID==561 && spellInfo_2->SpellVisual[0]==7992)
1460 return false;
1462 // Blessing of Sanctuary (multi-family check, some from 16 spell icon spells)
1463 if (spellInfo_1->Id == 67480 && spellInfo_2->Id == 20911)
1464 return false;
1466 break;
1469 // Dragonmaw Illusion, Blood Elf Illusion, Human Illusion, Illidari Agent Illusion, Scarlet Crusade Disguise
1470 if(spellInfo_1->SpellIconID == 1691 && spellInfo_2->SpellIconID == 1691)
1471 return false;
1472 break;
1473 case SPELLFAMILY_MAGE:
1474 if( spellInfo_2->SpellFamilyName == SPELLFAMILY_MAGE )
1476 // Blizzard & Chilled (and some other stacked with blizzard spells
1477 if( (spellInfo_1->SpellFamilyFlags & UI64LIT(0x80)) && (spellInfo_2->SpellFamilyFlags & UI64LIT(0x100000)) ||
1478 (spellInfo_2->SpellFamilyFlags & UI64LIT(0x80)) && (spellInfo_1->SpellFamilyFlags & UI64LIT(0x100000)) )
1479 return false;
1481 // Blink & Improved Blink
1482 if( (spellInfo_1->SpellFamilyFlags & UI64LIT(0x0000000000010000)) && (spellInfo_2->SpellVisual[0] == 72 && spellInfo_2->SpellIconID == 1499) ||
1483 (spellInfo_2->SpellFamilyFlags & UI64LIT(0x0000000000010000)) && (spellInfo_1->SpellVisual[0] == 72 && spellInfo_1->SpellIconID == 1499) )
1484 return false;
1486 // Living Bomb & Ignite (Dots)
1487 if( (spellInfo_1->SpellFamilyFlags & UI64LIT(0x2000000000000)) && (spellInfo_2->SpellFamilyFlags & UI64LIT(0x8000000)) ||
1488 (spellInfo_2->SpellFamilyFlags & UI64LIT(0x2000000000000)) && (spellInfo_1->SpellFamilyFlags & UI64LIT(0x8000000)) )
1489 return false;
1491 // Fireball & Pyroblast (Dots)
1492 if( (spellInfo_1->SpellFamilyFlags & UI64LIT(0x1)) && (spellInfo_2->SpellFamilyFlags & UI64LIT(0x400000)) ||
1493 (spellInfo_2->SpellFamilyFlags & UI64LIT(0x1)) && (spellInfo_1->SpellFamilyFlags & UI64LIT(0x400000)) )
1494 return false;
1496 // Detect Invisibility and Mana Shield (multi-family check)
1497 if( spellInfo_2->Id == 132 && spellInfo_1->SpellIconID == 209 && spellInfo_1->SpellVisual[0] == 968 )
1498 return false;
1500 // Combustion and Fire Protection Aura (multi-family check)
1501 if( spellInfo_1->Id == 11129 && spellInfo_2->SpellIconID == 33 && spellInfo_2->SpellVisual[0] == 321 )
1502 return false;
1504 // Arcane Intellect and Insight
1505 if( spellInfo_1->SpellIconID == 125 && spellInfo_2->Id == 18820 )
1506 return false;
1508 break;
1509 case SPELLFAMILY_WARLOCK:
1510 if( spellInfo_2->SpellFamilyName == SPELLFAMILY_WARLOCK )
1512 // Siphon Life and Drain Life
1513 if( spellInfo_1->SpellIconID == 152 && spellInfo_2->SpellIconID == 546 ||
1514 spellInfo_2->SpellIconID == 152 && spellInfo_1->SpellIconID == 546 )
1515 return false;
1517 //Corruption & Seed of corruption
1518 if( spellInfo_1->SpellIconID == 313 && spellInfo_2->SpellIconID == 1932 ||
1519 spellInfo_2->SpellIconID == 313 && spellInfo_1->SpellIconID == 1932 )
1520 if(spellInfo_1->SpellVisual[0] != 0 && spellInfo_2->SpellVisual[0] != 0)
1521 return true; // can't be stacked
1523 // Corruption and Unstable Affliction
1524 if( spellInfo_1->SpellIconID == 313 && spellInfo_2->SpellIconID == 2039 ||
1525 spellInfo_2->SpellIconID == 313 && spellInfo_1->SpellIconID == 2039 )
1526 return false;
1528 // (Corruption or Unstable Affliction) and (Curse of Agony or Curse of Doom)
1529 if( (spellInfo_1->SpellIconID == 313 || spellInfo_1->SpellIconID == 2039) && (spellInfo_2->SpellIconID == 544 || spellInfo_2->SpellIconID == 91) ||
1530 (spellInfo_2->SpellIconID == 313 || spellInfo_2->SpellIconID == 2039) && (spellInfo_1->SpellIconID == 544 || spellInfo_1->SpellIconID == 91) )
1531 return false;
1533 // Metamorphosis, diff effects
1534 if (spellInfo_1->SpellIconID == 3314 && spellInfo_2->SpellIconID == 3314)
1535 return false;
1537 // Detect Invisibility and Mana Shield (multi-family check)
1538 if( spellInfo_1->Id == 132 && spellInfo_2->SpellIconID == 209 && spellInfo_2->SpellVisual[0] == 968 )
1539 return false;
1540 break;
1541 case SPELLFAMILY_WARRIOR:
1542 if( spellInfo_2->SpellFamilyName == SPELLFAMILY_WARRIOR )
1544 // Rend and Deep Wound
1545 if( (spellInfo_1->SpellFamilyFlags & UI64LIT(0x20)) && (spellInfo_2->SpellFamilyFlags & UI64LIT(0x1000000000)) ||
1546 (spellInfo_2->SpellFamilyFlags & UI64LIT(0x20)) && (spellInfo_1->SpellFamilyFlags & UI64LIT(0x1000000000)) )
1547 return false;
1549 // Battle Shout and Rampage
1550 if( (spellInfo_1->SpellIconID == 456 && spellInfo_2->SpellIconID == 2006) ||
1551 (spellInfo_2->SpellIconID == 456 && spellInfo_1->SpellIconID == 2006) )
1552 return false;
1555 // Hamstring -> Improved Hamstring (multi-family check)
1556 if( (spellInfo_1->SpellFamilyFlags & UI64LIT(0x2)) && spellInfo_2->Id == 23694 )
1557 return false;
1559 // Defensive Stance and Scroll of Protection (multi-family check)
1560 if( spellInfo_1->Id == 71 && spellInfo_2->SpellIconID == 276 && spellInfo_2->SpellVisual[0] == 196 )
1561 return false;
1563 // Bloodlust and Bloodthirst (multi-family check)
1564 if( spellInfo_2->Id == 2825 && spellInfo_1->SpellIconID == 38 && spellInfo_1->SpellVisual[0] == 0 )
1565 return false;
1567 break;
1568 case SPELLFAMILY_PRIEST:
1569 if( spellInfo_2->SpellFamilyName == SPELLFAMILY_PRIEST )
1571 //Devouring Plague and Shadow Vulnerability
1572 if ((spellInfo_1->SpellFamilyFlags & UI64LIT(0x2000000)) && (spellInfo_2->SpellFamilyFlags & UI64LIT(0x800000000)) ||
1573 (spellInfo_2->SpellFamilyFlags & UI64LIT(0x2000000)) && (spellInfo_1->SpellFamilyFlags & UI64LIT(0x800000000)))
1574 return false;
1576 //StarShards and Shadow Word: Pain
1577 if ((spellInfo_1->SpellFamilyFlags & UI64LIT(0x200000)) && (spellInfo_2->SpellFamilyFlags & UI64LIT(0x8000)) ||
1578 (spellInfo_2->SpellFamilyFlags & UI64LIT(0x200000)) && (spellInfo_1->SpellFamilyFlags & UI64LIT(0x8000)))
1579 return false;
1580 // Dispersion
1581 if ((spellInfo_1->Id == 47585 && spellInfo_2->Id == 60069) ||
1582 (spellInfo_2->Id == 47585 && spellInfo_1->Id == 60069))
1583 return false;
1585 break;
1586 case SPELLFAMILY_DRUID:
1587 if( spellInfo_2->SpellFamilyName == SPELLFAMILY_DRUID )
1589 //Omen of Clarity and Blood Frenzy
1590 if( (spellInfo_1->SpellFamilyFlags == UI64LIT(0x0) && spellInfo_1->SpellIconID == 108) && (spellInfo_2->SpellFamilyFlags & UI64LIT(0x20000000000000)) ||
1591 (spellInfo_2->SpellFamilyFlags == UI64LIT(0x0) && spellInfo_2->SpellIconID == 108) && (spellInfo_1->SpellFamilyFlags & UI64LIT(0x20000000000000)) )
1592 return false;
1594 // Tree of Life (Shapeshift) and 34123 Tree of Life (Passive)
1595 if ((spellId_1 == 33891 && spellId_2 == 34123) ||
1596 (spellId_2 == 33891 && spellId_1 == 34123))
1597 return false;
1599 // Lifebloom and Wild Growth
1600 if (spellInfo_1->SpellIconID == 2101 && spellInfo_2->SpellIconID == 2864 ||
1601 spellInfo_2->SpellIconID == 2101 && spellInfo_1->SpellIconID == 2864 )
1602 return false;
1604 // Innervate and Glyph of Innervate and some other spells
1605 if (spellInfo_1->SpellIconID == 62 && spellInfo_2->SpellIconID == 62)
1606 return false;
1608 // Wrath of Elune and Nature's Grace
1609 if( spellInfo_1->Id == 16886 && spellInfo_2->Id == 46833 || spellInfo_2->Id == 16886 && spellInfo_1->Id == 46833 )
1610 return false;
1612 // Bear Rage (Feral T4 (2)) and Omen of Clarity
1613 if( spellInfo_1->Id == 16864 && spellInfo_2->Id == 37306 || spellInfo_2->Id == 16864 && spellInfo_1->Id == 37306 )
1614 return false;
1616 // Cat Energy (Feral T4 (2)) and Omen of Clarity
1617 if( spellInfo_1->Id == 16864 && spellInfo_2->Id == 37311 || spellInfo_2->Id == 16864 && spellInfo_1->Id == 37311 )
1618 return false;
1620 // Survival Instincts and Survival Instincts
1621 if( spellInfo_1->Id == 61336 && spellInfo_2->Id == 50322 || spellInfo_2->Id == 61336 && spellInfo_1->Id == 50322 )
1622 return false;
1624 // Savage Roar and Savage Roar (triggered)
1625 if (spellInfo_1->SpellIconID == 2865 && spellInfo_2->SpellIconID == 2865)
1626 return false;
1628 // Frenzied Regeneration and Savage Defense
1629 if( spellInfo_1->Id == 22842 && spellInfo_2->Id == 62606 || spellInfo_2->Id == 22842 && spellInfo_1->Id == 62606 )
1630 return false;
1633 // Leader of the Pack and Scroll of Stamina (multi-family check)
1634 if( spellInfo_1->Id == 24932 && spellInfo_2->SpellIconID == 312 && spellInfo_2->SpellVisual[0] == 216 )
1635 return false;
1637 // Dragonmaw Illusion (multi-family check)
1638 if (spellId_1 == 42016 && spellId_2 == 40216 )
1639 return false;
1641 break;
1642 case SPELLFAMILY_ROGUE:
1643 if( spellInfo_2->SpellFamilyName == SPELLFAMILY_ROGUE )
1645 // Master of Subtlety
1646 if (spellId_1 == 31665 && spellId_2 == 31666 || spellId_1 == 31666 && spellId_2 == 31665 )
1647 return false;
1649 // Sprint & Sprint (waterwalk)
1650 if( spellInfo_1->SpellIconID == 516 && spellInfo_2->SpellIconID == 516 &&
1651 (spellInfo_1->Category == 44 && spellInfo_2->Category == 0 ||
1652 spellInfo_2->Category == 44 && spellInfo_1->Category == 0))
1653 return false;
1656 //Overkill
1657 if( spellInfo_1->SpellIconID == 2285 && spellInfo_2->SpellIconID == 2285 )
1658 return false;
1660 // Garrote -> Garrote-Silence (multi-family check)
1661 if( spellInfo_1->SpellIconID == 498 && spellInfo_2->SpellIconID == 498 && spellInfo_2->SpellVisual[0] == 0 )
1662 return false;
1663 break;
1664 case SPELLFAMILY_HUNTER:
1665 if( spellInfo_2->SpellFamilyName == SPELLFAMILY_HUNTER )
1667 // Rapid Fire & Quick Shots
1668 if( (spellInfo_1->SpellFamilyFlags & UI64LIT(0x20)) && (spellInfo_2->SpellFamilyFlags & UI64LIT(0x20000000000)) ||
1669 (spellInfo_2->SpellFamilyFlags & UI64LIT(0x20)) && (spellInfo_1->SpellFamilyFlags & UI64LIT(0x20000000000)) )
1670 return false;
1672 // Serpent Sting & (Immolation/Explosive Trap Effect)
1673 if( (spellInfo_1->SpellFamilyFlags & UI64LIT(0x4)) && (spellInfo_2->SpellFamilyFlags & UI64LIT(0x00000004000)) ||
1674 (spellInfo_2->SpellFamilyFlags & UI64LIT(0x4)) && (spellInfo_1->SpellFamilyFlags & UI64LIT(0x00000004000)) )
1675 return false;
1677 // Bestial Wrath
1678 if( spellInfo_1->SpellIconID == 1680 && spellInfo_2->SpellIconID == 1680 )
1679 return false;
1682 // Wing Clip -> Improved Wing Clip (multi-family check)
1683 if( (spellInfo_1->SpellFamilyFlags & UI64LIT(0x40)) && spellInfo_2->Id == 19229 )
1684 return false;
1686 // Concussive Shot and Imp. Concussive Shot (multi-family check)
1687 if( spellInfo_2->Id == 19410 && spellInfo_1->Id == 5116 )
1688 return false;
1689 break;
1690 case SPELLFAMILY_PALADIN:
1691 if( spellInfo_2->SpellFamilyName == SPELLFAMILY_PALADIN )
1693 // Paladin Seals
1694 if (IsSealSpell(spellInfo_1) && IsSealSpell(spellInfo_2))
1695 return true;
1697 // Swift Retribution / Improved Devotion Aura (talents) and Paladin Auras
1698 if ((spellInfo_1->SpellFamilyFlags2 & 0x00000020) && (spellInfo_2->SpellIconID == 291 || spellInfo_2->SpellIconID == 3028) ||
1699 (spellInfo_2->SpellFamilyFlags2 & 0x00000020) && (spellInfo_1->SpellIconID == 291 || spellInfo_1->SpellIconID == 3028))
1700 return false;
1702 // Beacon of Light and Light's Beacon
1703 if ((spellInfo_1->SpellIconID == 3032) && (spellInfo_2->SpellIconID == 3032))
1704 return false;
1706 // Concentration Aura and Improved Concentration Aura and Aura Mastery
1707 if ((spellInfo_1->SpellIconID == 1487) && (spellInfo_2->SpellIconID == 1487))
1708 return false;
1710 // Seal of Corruption (caster/target parts stacking allow, other stacking checked by spell specs)
1711 if (spellInfo_1->SpellIconID == 2292 && spellInfo_2->SpellIconID == 2292)
1712 return false;
1714 // Divine Sacrifice and Divine Guardian
1715 if (spellInfo_1->SpellIconID == 3837 && spellInfo_2->SpellIconID == 3837)
1716 return false;
1719 // Blessing of Sanctuary (multi-family check, some from 16 spell icon spells)
1720 if (spellInfo_2->Id == 67480 && spellInfo_1->Id == 20911)
1721 return false;
1723 // Combustion and Fire Protection Aura (multi-family check)
1724 if( spellInfo_2->Id == 11129 && spellInfo_1->SpellIconID == 33 && spellInfo_1->SpellVisual[0] == 321 )
1725 return false;
1727 // *Sanctity Aura -> Unstable Currents and other (multi-family check)
1728 if( spellInfo_1->SpellIconID==502 && spellInfo_2->SpellFamilyName == SPELLFAMILY_GENERIC && spellInfo_2->SpellIconID==502 && spellInfo_2->SpellVisual[0]==969 )
1729 return false;
1731 // *Seal of Command and Band of Eternal Champion (multi-family check)
1732 if( spellInfo_1->SpellIconID==561 && spellInfo_1->SpellVisual[0]==7992 && spellId_2 == 35081)
1733 return false;
1734 break;
1735 case SPELLFAMILY_SHAMAN:
1736 if( spellInfo_2->SpellFamilyName == SPELLFAMILY_SHAMAN )
1738 // Windfury weapon
1739 if( spellInfo_1->SpellIconID==220 && spellInfo_2->SpellIconID==220 &&
1740 spellInfo_1->SpellFamilyFlags != spellInfo_2->SpellFamilyFlags )
1741 return false;
1743 // Ghost Wolf
1744 if (spellInfo_1->SpellIconID == 67 && spellInfo_2->SpellIconID == 67)
1745 return false;
1747 // Totem of Wrath (positive/negative), ranks checked early
1748 if (spellInfo_1->SpellIconID == 2019 && spellInfo_2->SpellIconID == 2019)
1749 return false;
1751 // Bloodlust and Bloodthirst (multi-family check)
1752 if( spellInfo_1->Id == 2825 && spellInfo_2->SpellIconID == 38 && spellInfo_2->SpellVisual[0] == 0 )
1753 return false;
1754 break;
1755 case SPELLFAMILY_DEATHKNIGHT:
1756 if (spellInfo_2->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT)
1758 // Lichborne and Lichborne (triggered)
1759 if (spellInfo_1->SpellIconID == 61 && spellInfo_2->SpellIconID == 61)
1760 return false;
1762 // Frost Presence and Frost Presence (triggered)
1763 if (spellInfo_1->SpellIconID == 2632 && spellInfo_2->SpellIconID == 2632)
1764 return false;
1766 // Unholy Presence and Unholy Presence (triggered)
1767 if (spellInfo_1->SpellIconID == 2633 && spellInfo_2->SpellIconID == 2633)
1768 return false;
1770 // Blood Presence and Blood Presence (triggered)
1771 if (spellInfo_1->SpellIconID == 2636 && spellInfo_2->SpellIconID == 2636)
1772 return false;
1774 break;
1775 default:
1776 break;
1779 // more generic checks
1780 if (spellInfo_1->SpellIconID == spellInfo_2->SpellIconID &&
1781 spellInfo_1->SpellIconID != 0 && spellInfo_2->SpellIconID != 0)
1783 bool isModifier = false;
1784 for (int i = 0; i < MAX_EFFECT_INDEX; ++i)
1786 if (spellInfo_1->EffectApplyAuraName[i] == SPELL_AURA_ADD_FLAT_MODIFIER ||
1787 spellInfo_1->EffectApplyAuraName[i] == SPELL_AURA_ADD_PCT_MODIFIER ||
1788 spellInfo_2->EffectApplyAuraName[i] == SPELL_AURA_ADD_FLAT_MODIFIER ||
1789 spellInfo_2->EffectApplyAuraName[i] == SPELL_AURA_ADD_PCT_MODIFIER )
1790 isModifier = true;
1793 if (!isModifier)
1794 return true;
1797 if (IsRankSpellDueToSpell(spellInfo_1, spellId_2))
1798 return true;
1800 if (spellInfo_1->SpellFamilyName == 0 || spellInfo_2->SpellFamilyName == 0)
1801 return false;
1803 if (spellInfo_1->SpellFamilyName != spellInfo_2->SpellFamilyName)
1804 return false;
1806 bool dummy_only = true;
1807 for (int i = 0; i < MAX_EFFECT_INDEX; ++i)
1809 if (spellInfo_1->Effect[i] != spellInfo_2->Effect[i] ||
1810 spellInfo_1->EffectItemType[i] != spellInfo_2->EffectItemType[i] ||
1811 spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i] ||
1812 spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i])
1813 return false;
1815 // ignore dummy only spells
1816 if(spellInfo_1->Effect[i] && spellInfo_1->Effect[i] != SPELL_EFFECT_DUMMY && spellInfo_1->EffectApplyAuraName[i] != SPELL_AURA_DUMMY)
1817 dummy_only = false;
1819 if (dummy_only)
1820 return false;
1822 return true;
1825 bool SpellMgr::IsProfessionOrRidingSpell(uint32 spellId)
1827 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
1828 if(!spellInfo)
1829 return false;
1831 if (spellInfo->Effect[EFFECT_INDEX_1] != SPELL_EFFECT_SKILL)
1832 return false;
1834 uint32 skill = spellInfo->EffectMiscValue[EFFECT_INDEX_1];
1836 return IsProfessionOrRidingSkill(skill);
1839 bool SpellMgr::IsProfessionSpell(uint32 spellId)
1841 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
1842 if(!spellInfo)
1843 return false;
1845 if (spellInfo->Effect[EFFECT_INDEX_1] != SPELL_EFFECT_SKILL)
1846 return false;
1848 uint32 skill = spellInfo->EffectMiscValue[EFFECT_INDEX_1];
1850 return IsProfessionSkill(skill);
1853 bool SpellMgr::IsPrimaryProfessionSpell(uint32 spellId)
1855 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
1856 if(!spellInfo)
1857 return false;
1859 if (spellInfo->Effect[EFFECT_INDEX_1] != SPELL_EFFECT_SKILL)
1860 return false;
1862 uint32 skill = spellInfo->EffectMiscValue[EFFECT_INDEX_1];
1864 return IsPrimaryProfessionSkill(skill);
1867 bool SpellMgr::IsPrimaryProfessionFirstRankSpell(uint32 spellId) const
1869 return IsPrimaryProfessionSpell(spellId) && GetSpellRank(spellId)==1;
1872 bool SpellMgr::IsSkillBonusSpell(uint32 spellId) const
1874 SkillLineAbilityMapBounds bounds = GetSkillLineAbilityMapBounds(spellId);
1876 for(SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
1878 SkillLineAbilityEntry const *pAbility = _spell_idx->second;
1879 if (!pAbility || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL)
1880 continue;
1882 if (pAbility->req_skill_value > 0)
1883 return true;
1886 return false;
1889 SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spellInfo, uint32 playerLevel) const
1891 // ignore passive spells
1892 if(IsPassiveSpell(spellInfo->Id))
1893 return spellInfo;
1895 bool needRankSelection = false;
1896 for(int i = 0; i < MAX_EFFECT_INDEX; ++i)
1898 if (IsPositiveEffect(spellInfo->Id, SpellEffectIndex(i)) && (
1899 spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA ||
1900 spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY ||
1901 spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_RAID))
1903 needRankSelection = true;
1904 break;
1908 // not required
1909 if(!needRankSelection)
1910 return spellInfo;
1912 for(uint32 nextSpellId = spellInfo->Id; nextSpellId != 0; nextSpellId = GetPrevSpellInChain(nextSpellId))
1914 SpellEntry const *nextSpellInfo = sSpellStore.LookupEntry(nextSpellId);
1915 if(!nextSpellInfo)
1916 break;
1918 // if found appropriate level
1919 if(playerLevel + 10 >= nextSpellInfo->spellLevel)
1920 return nextSpellInfo;
1922 // one rank less then
1925 // not found
1926 return NULL;
1929 void SpellMgr::LoadSpellChains()
1931 mSpellChains.clear(); // need for reload case
1932 mSpellChainsNext.clear(); // need for reload case
1934 QueryResult *result = WorldDatabase.Query("SELECT spell_id, prev_spell, first_spell, rank, req_spell FROM spell_chain");
1935 if(result == NULL)
1937 barGoLink bar( 1 );
1938 bar.step();
1940 sLog.outString();
1941 sLog.outString( ">> Loaded 0 spell chain records" );
1942 sLog.outErrorDb("`spell_chains` table is empty!");
1943 return;
1946 uint32 count = 0;
1948 barGoLink bar( (int)result->GetRowCount() );
1951 bar.step();
1952 Field *fields = result->Fetch();
1954 uint32 spell_id = fields[0].GetUInt32();
1956 SpellChainNode node;
1957 node.prev = fields[1].GetUInt32();
1958 node.first = fields[2].GetUInt32();
1959 node.rank = fields[3].GetUInt8();
1960 node.req = fields[4].GetUInt32();
1962 if(!sSpellStore.LookupEntry(spell_id))
1964 sLog.outErrorDb("Spell %u listed in `spell_chain` does not exist",spell_id);
1965 continue;
1968 if(node.prev!=0 && !sSpellStore.LookupEntry(node.prev))
1970 sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not existed previous rank spell.",
1971 spell_id,node.prev,node.first,node.rank,node.req);
1972 continue;
1975 if(!sSpellStore.LookupEntry(node.first))
1977 sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not existing first rank spell.",
1978 spell_id,node.prev,node.first,node.rank,node.req);
1979 continue;
1982 // check basic spell chain data integrity (note: rank can be equal 0 or 1 for first/single spell)
1983 if( (spell_id == node.first) != (node.rank <= 1) ||
1984 (spell_id == node.first) != (node.prev == 0) ||
1985 (node.rank <= 1) != (node.prev == 0) )
1987 sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not compatible chain data.",
1988 spell_id,node.prev,node.first,node.rank,node.req);
1989 continue;
1992 if(node.req!=0 && !sSpellStore.LookupEntry(node.req))
1994 sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not existing required spell.",
1995 spell_id,node.prev,node.first,node.rank,node.req);
1996 continue;
1999 // talents not required data in spell chain for work, but must be checked if present for intergrity
2000 if(TalentSpellPos const* pos = GetTalentSpellPos(spell_id))
2002 if(node.rank!=pos->rank+1)
2004 sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong rank.",
2005 spell_id,node.prev,node.first,node.rank,node.req);
2006 continue;
2009 if(TalentEntry const* talentEntry = sTalentStore.LookupEntry(pos->talent_id))
2011 if(node.first!=talentEntry->RankID[0])
2013 sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong first rank spell.",
2014 spell_id,node.prev,node.first,node.rank,node.req);
2015 continue;
2018 if(node.rank > 1 && node.prev != talentEntry->RankID[node.rank-1-1])
2020 sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong prev rank spell.",
2021 spell_id,node.prev,node.first,node.rank,node.req);
2022 continue;
2025 /*if(node.req!=talentEntry->DependsOnSpell)
2027 sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong required spell.",
2028 spell_id,node.prev,node.first,node.rank,node.req);
2029 continue;
2034 mSpellChains[spell_id] = node;
2036 if(node.prev)
2037 mSpellChainsNext.insert(SpellChainMapNext::value_type(node.prev,spell_id));
2039 if(node.req)
2040 mSpellChainsNext.insert(SpellChainMapNext::value_type(node.req,spell_id));
2042 ++count;
2043 } while( result->NextRow() );
2045 delete result;
2047 // additional integrity checks
2048 for(SpellChainMap::const_iterator i = mSpellChains.begin(); i != mSpellChains.end(); ++i)
2050 if(i->second.prev)
2052 SpellChainMap::const_iterator i_prev = mSpellChains.find(i->second.prev);
2053 if(i_prev == mSpellChains.end())
2055 sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not found previous rank spell in table.",
2056 i->first,i->second.prev,i->second.first,i->second.rank,i->second.req);
2058 else if( i_prev->second.first != i->second.first )
2060 sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has different first spell in chain compared to previous rank spell (prev: %u, first: %u, rank: %d, req: %u).",
2061 i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
2062 i_prev->second.prev,i_prev->second.first,i_prev->second.rank,i_prev->second.req);
2064 else if( i_prev->second.rank+1 != i->second.rank )
2066 sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has different rank compared to previous rank spell (prev: %u, first: %u, rank: %d, req: %u).",
2067 i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
2068 i_prev->second.prev,i_prev->second.first,i_prev->second.rank,i_prev->second.req);
2072 if(i->second.req)
2074 SpellChainMap::const_iterator i_req = mSpellChains.find(i->second.req);
2075 if(i_req == mSpellChains.end())
2077 sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not found required rank spell in table.",
2078 i->first,i->second.prev,i->second.first,i->second.rank,i->second.req);
2080 else if( i_req->second.first == i->second.first )
2082 sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has required rank spell from same spell chain (prev: %u, first: %u, rank: %d, req: %u).",
2083 i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
2084 i_req->second.prev,i_req->second.first,i_req->second.rank,i_req->second.req);
2086 else if( i_req->second.req )
2088 sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has required rank spell with required spell (prev: %u, first: %u, rank: %d, req: %u).",
2089 i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
2090 i_req->second.prev,i_req->second.first,i_req->second.rank,i_req->second.req);
2095 sLog.outString();
2096 sLog.outString( ">> Loaded %u spell chain records", count );
2099 void SpellMgr::LoadSpellLearnSkills()
2101 mSpellLearnSkills.clear(); // need for reload case
2103 // search auto-learned skills and add its to map also for use in unlearn spells/talents
2104 uint32 dbc_count = 0;
2105 barGoLink bar( sSpellStore.GetNumRows() );
2106 for(uint32 spell = 0; spell < sSpellStore.GetNumRows(); ++spell)
2108 bar.step();
2109 SpellEntry const* entry = sSpellStore.LookupEntry(spell);
2111 if(!entry)
2112 continue;
2114 for(int i = 0; i < MAX_EFFECT_INDEX; ++i)
2116 if(entry->Effect[i]==SPELL_EFFECT_SKILL)
2118 SpellLearnSkillNode dbc_node;
2119 dbc_node.skill = entry->EffectMiscValue[i];
2120 if ( dbc_node.skill != SKILL_RIDING )
2121 dbc_node.value = 1;
2122 else
2123 dbc_node.value = entry->CalculateSimpleValue(SpellEffectIndex(i))*75;
2124 dbc_node.maxvalue = entry->CalculateSimpleValue(SpellEffectIndex(i))*75;
2126 mSpellLearnSkills[spell] = dbc_node;
2127 ++dbc_count;
2128 break;
2133 sLog.outString();
2134 sLog.outString( ">> Loaded %u Spell Learn Skills from DBC", dbc_count );
2137 void SpellMgr::LoadSpellLearnSpells()
2139 mSpellLearnSpells.clear(); // need for reload case
2141 // 0 1 2
2142 QueryResult *result = WorldDatabase.Query("SELECT entry, SpellID, Active FROM spell_learn_spell");
2143 if (!result)
2145 barGoLink bar( 1 );
2146 bar.step();
2148 sLog.outString();
2149 sLog.outString( ">> Loaded 0 spell learn spells" );
2150 sLog.outErrorDb("`spell_learn_spell` table is empty!");
2151 return;
2154 uint32 count = 0;
2156 barGoLink bar( (int)result->GetRowCount() );
2159 bar.step();
2160 Field *fields = result->Fetch();
2162 uint32 spell_id = fields[0].GetUInt32();
2164 SpellLearnSpellNode node;
2165 node.spell = fields[1].GetUInt32();
2166 node.active = fields[2].GetBool();
2167 node.autoLearned= false;
2169 if (!sSpellStore.LookupEntry(spell_id))
2171 sLog.outErrorDb("Spell %u listed in `spell_learn_spell` does not exist",spell_id);
2172 continue;
2175 if (!sSpellStore.LookupEntry(node.spell))
2177 sLog.outErrorDb("Spell %u listed in `spell_learn_spell` learning not existed spell %u",spell_id,node.spell);
2178 continue;
2181 if (GetTalentSpellCost(node.spell))
2183 sLog.outErrorDb("Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped",spell_id,node.spell);
2184 continue;
2187 mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell_id,node));
2189 ++count;
2190 } while( result->NextRow() );
2192 delete result;
2194 // search auto-learned spells and add its to map also for use in unlearn spells/talents
2195 uint32 dbc_count = 0;
2196 for(uint32 spell = 0; spell < sSpellStore.GetNumRows(); ++spell)
2198 SpellEntry const* entry = sSpellStore.LookupEntry(spell);
2200 if (!entry)
2201 continue;
2203 for(int i = 0; i < MAX_EFFECT_INDEX; ++i)
2205 if(entry->Effect[i]==SPELL_EFFECT_LEARN_SPELL)
2207 SpellLearnSpellNode dbc_node;
2208 dbc_node.spell = entry->EffectTriggerSpell[i];
2209 dbc_node.active = true; // all dbc based learned spells is active (show in spell book or hide by client itself)
2211 // ignore learning not existed spells (broken/outdated/or generic learnig spell 483
2212 if (!sSpellStore.LookupEntry(dbc_node.spell))
2213 continue;
2215 // talent or passive spells or skill-step spells auto-casted and not need dependent learning,
2216 // pet teaching spells don't must be dependent learning (casted)
2217 // other required explicit dependent learning
2218 dbc_node.autoLearned = entry->EffectImplicitTargetA[i]==TARGET_PET || GetTalentSpellCost(spell) > 0 || IsPassiveSpell(spell) || IsSpellHaveEffect(entry,SPELL_EFFECT_SKILL_STEP);
2220 SpellLearnSpellMapBounds db_node_bounds = GetSpellLearnSpellMapBounds(spell);
2222 bool found = false;
2223 for(SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
2225 if (itr->second.spell == dbc_node.spell)
2227 sLog.outErrorDb("Spell %u auto-learn spell %u in spell.dbc then the record in `spell_learn_spell` is redundant, please fix DB.",
2228 spell,dbc_node.spell);
2229 found = true;
2230 break;
2234 if (!found) // add new spell-spell pair if not found
2236 mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell,dbc_node));
2237 ++dbc_count;
2243 sLog.outString();
2244 sLog.outString( ">> Loaded %u spell learn spells + %u found in DBC", count, dbc_count );
2247 void SpellMgr::LoadSpellScriptTarget()
2249 mSpellScriptTarget.clear(); // need for reload case
2251 uint32 count = 0;
2253 QueryResult *result = WorldDatabase.Query("SELECT entry,type,targetEntry FROM spell_script_target");
2255 if (!result)
2257 barGoLink bar(1);
2259 bar.step();
2261 sLog.outString();
2262 sLog.outErrorDb(">> Loaded 0 SpellScriptTarget. DB table `spell_script_target` is empty.");
2263 return;
2266 barGoLink bar((int)result->GetRowCount());
2270 Field *fields = result->Fetch();
2271 bar.step();
2273 uint32 spellId = fields[0].GetUInt32();
2274 uint32 type = fields[1].GetUInt32();
2275 uint32 targetEntry = fields[2].GetUInt32();
2277 SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId);
2279 if (!spellProto)
2281 sLog.outErrorDb("Table `spell_script_target`: spellId %u listed for TargetEntry %u does not exist.",spellId,targetEntry);
2282 continue;
2285 bool targetfound = false;
2286 for (int i = 0; i < MAX_EFFECT_INDEX; ++i)
2288 if( spellProto->EffectImplicitTargetA[i] == TARGET_SCRIPT ||
2289 spellProto->EffectImplicitTargetB[i] == TARGET_SCRIPT ||
2290 spellProto->EffectImplicitTargetA[i] == TARGET_SCRIPT_COORDINATES ||
2291 spellProto->EffectImplicitTargetB[i] == TARGET_SCRIPT_COORDINATES ||
2292 spellProto->EffectImplicitTargetA[i] == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT ||
2293 spellProto->EffectImplicitTargetB[i] == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT )
2295 targetfound = true;
2296 break;
2299 if (!targetfound)
2301 sLog.outErrorDb("Table `spell_script_target`: spellId %u listed for TargetEntry %u does not have any implicit target TARGET_SCRIPT(38) or TARGET_SCRIPT_COORDINATES (46) or TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT (40).", spellId, targetEntry);
2302 continue;
2305 if (type >= MAX_SPELL_TARGET_TYPE)
2307 sLog.outErrorDb("Table `spell_script_target`: target type %u for TargetEntry %u is incorrect.",type,targetEntry);
2308 continue;
2311 // Checks by target type
2312 switch (type)
2314 case SPELL_TARGET_TYPE_GAMEOBJECT:
2316 if (!targetEntry)
2317 break;
2319 if (!sGOStorage.LookupEntry<GameObjectInfo>(targetEntry))
2321 sLog.outErrorDb("Table `spell_script_target`: gameobject template entry %u does not exist.",targetEntry);
2322 continue;
2324 break;
2326 default:
2327 if (!targetEntry)
2329 sLog.outErrorDb("Table `spell_script_target`: target entry == 0 for not GO target type (%u).",type);
2330 continue;
2332 if (const CreatureInfo* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(targetEntry))
2334 if (spellId == 30427 && !cInfo->SkinLootId)
2336 sLog.outErrorDb("Table `spell_script_target` has creature %u as a target of spellid 30427, but this creature has no skinlootid. Gas extraction will not work!", cInfo->Entry);
2337 continue;
2340 else
2342 sLog.outErrorDb("Table `spell_script_target`: creature template entry %u does not exist.",targetEntry);
2343 continue;
2345 break;
2348 mSpellScriptTarget.insert(SpellScriptTarget::value_type(spellId,SpellTargetEntry(SpellTargetType(type),targetEntry)));
2350 ++count;
2351 } while (result->NextRow());
2353 delete result;
2355 // Check all spells
2356 /* Disabled (lot errors at this moment)
2357 for(uint32 i = 1; i < sSpellStore.nCount; ++i)
2359 SpellEntry const * spellInfo = sSpellStore.LookupEntry(i);
2360 if(!spellInfo)
2361 continue;
2363 bool found = false;
2364 for(int j = 0; j < MAX_EFFECT_INDEX; ++j)
2366 if( spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT || spellInfo->EffectImplicitTargetA[j] != TARGET_SELF && spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT )
2368 SpellScriptTarget::const_iterator lower = GetBeginSpellScriptTarget(spellInfo->Id);
2369 SpellScriptTarget::const_iterator upper = GetEndSpellScriptTarget(spellInfo->Id);
2370 if(lower==upper)
2372 sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = %u (TARGET_SCRIPT), but does not have record in `spell_script_target`",spellInfo->Id,TARGET_SCRIPT);
2373 break; // effects of spell
2380 sLog.outString();
2381 sLog.outString(">> Loaded %u Spell Script Targets", count);
2384 void SpellMgr::LoadSpellPetAuras()
2386 mSpellPetAuraMap.clear(); // need for reload case
2388 uint32 count = 0;
2390 // 0 1 2 3
2391 QueryResult *result = WorldDatabase.Query("SELECT spell, effectId, pet, aura FROM spell_pet_auras");
2392 if( !result )
2395 barGoLink bar( 1 );
2397 bar.step();
2399 sLog.outString();
2400 sLog.outString( ">> Loaded %u spell pet auras", count );
2401 return;
2404 barGoLink bar( (int)result->GetRowCount() );
2408 Field *fields = result->Fetch();
2410 bar.step();
2412 uint32 spell = fields[0].GetUInt32();
2413 SpellEffectIndex eff = SpellEffectIndex(fields[1].GetUInt32());
2414 uint32 pet = fields[2].GetUInt32();
2415 uint32 aura = fields[3].GetUInt32();
2417 if (eff >= MAX_EFFECT_INDEX)
2419 sLog.outErrorDb("Spell %u listed in `spell_pet_auras` with wrong spell effect index (%u)", spell, eff);
2420 continue;
2423 SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find((spell<<8) + eff);
2424 if(itr != mSpellPetAuraMap.end())
2426 itr->second.AddAura(pet, aura);
2428 else
2430 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell);
2431 if (!spellInfo)
2433 sLog.outErrorDb("Spell %u listed in `spell_pet_auras` does not exist", spell);
2434 continue;
2437 if (spellInfo->Effect[eff] != SPELL_EFFECT_DUMMY &&
2438 (spellInfo->Effect[eff] != SPELL_EFFECT_APPLY_AURA ||
2439 spellInfo->EffectApplyAuraName[eff] != SPELL_AURA_DUMMY))
2441 sLog.outError("Spell %u listed in `spell_pet_auras` does not have dummy aura or dummy effect", spell);
2442 continue;
2445 SpellEntry const* spellInfo2 = sSpellStore.LookupEntry(aura);
2446 if (!spellInfo2)
2448 sLog.outErrorDb("Aura %u listed in `spell_pet_auras` does not exist", aura);
2449 continue;
2452 PetAura pa(pet, aura, spellInfo->EffectImplicitTargetA[eff] == TARGET_PET, spellInfo->CalculateSimpleValue(eff));
2453 mSpellPetAuraMap[(spell<<8) + eff] = pa;
2456 ++count;
2457 } while( result->NextRow() );
2459 delete result;
2461 sLog.outString();
2462 sLog.outString( ">> Loaded %u spell pet auras", count );
2465 void SpellMgr::LoadPetLevelupSpellMap()
2467 uint32 count = 0;
2468 uint32 family_count = 0;
2470 for (uint32 i = 0; i < sCreatureFamilyStore.GetNumRows(); ++i)
2472 CreatureFamilyEntry const *creatureFamily = sCreatureFamilyStore.LookupEntry(i);
2473 if(!creatureFamily) // not exist
2474 continue;
2476 for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
2478 SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j);
2479 if( !skillLine )
2480 continue;
2482 if (skillLine->skillId!=creatureFamily->skillLine[0] &&
2483 (!creatureFamily->skillLine[1] || skillLine->skillId!=creatureFamily->skillLine[1]))
2484 continue;
2486 if(skillLine->learnOnGetSkill != ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL)
2487 continue;
2489 SpellEntry const *spell = sSpellStore.LookupEntry(skillLine->spellId);
2490 if(!spell) // not exist
2491 continue;
2493 PetLevelupSpellSet& spellSet = mPetLevelupSpellMap[creatureFamily->ID];
2494 if(spellSet.empty())
2495 ++family_count;
2497 spellSet.insert(PetLevelupSpellSet::value_type(spell->spellLevel,spell->Id));
2498 count++;
2502 sLog.outString();
2503 sLog.outString( ">> Loaded %u pet levelup and default spells for %u families", count, family_count );
2506 bool LoadPetDefaultSpells_helper(CreatureInfo const* cInfo, PetDefaultSpellsEntry& petDefSpells)
2508 // skip empty list;
2509 bool have_spell = false;
2510 for(int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2512 if(petDefSpells.spellid[j])
2514 have_spell = true;
2515 break;
2518 if(!have_spell)
2519 return false;
2521 // remove duplicates with levelupSpells if any
2522 if(PetLevelupSpellSet const *levelupSpells = cInfo->family ? sSpellMgr.GetPetLevelupSpellList(cInfo->family) : NULL)
2524 for(int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2526 if(!petDefSpells.spellid[j])
2527 continue;
2529 for(PetLevelupSpellSet::const_iterator itr = levelupSpells->begin(); itr != levelupSpells->end(); ++itr)
2531 if (itr->second == petDefSpells.spellid[j])
2533 petDefSpells.spellid[j] = 0;
2534 break;
2540 // skip empty list;
2541 have_spell = false;
2542 for(int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2544 if(petDefSpells.spellid[j])
2546 have_spell = true;
2547 break;
2551 return have_spell;
2554 void SpellMgr::LoadPetDefaultSpells()
2556 assert(MAX_CREATURE_SPELL_DATA_SLOT==CREATURE_MAX_SPELLS);
2558 mPetDefaultSpellsMap.clear();
2560 uint32 countCreature = 0;
2561 uint32 countData = 0;
2563 for(uint32 i = 0; i < sCreatureStorage.MaxEntry; ++i )
2565 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i);
2566 if(!cInfo)
2567 continue;
2569 if(!cInfo->PetSpellDataId)
2570 continue;
2572 // for creature with PetSpellDataId get default pet spells from dbc
2573 CreatureSpellDataEntry const* spellDataEntry = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId);
2574 if(!spellDataEntry)
2575 continue;
2577 int32 petSpellsId = -(int32)cInfo->PetSpellDataId;
2578 PetDefaultSpellsEntry petDefSpells;
2579 for(int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2580 petDefSpells.spellid[j] = spellDataEntry->spellId[j];
2582 if(LoadPetDefaultSpells_helper(cInfo, petDefSpells))
2584 mPetDefaultSpellsMap[petSpellsId] = petDefSpells;
2585 ++countData;
2589 // different summon spells
2590 for(uint32 i = 0; i < sSpellStore.GetNumRows(); ++i )
2592 SpellEntry const* spellEntry = sSpellStore.LookupEntry(i);
2593 if(!spellEntry)
2594 continue;
2596 for(int k = 0; k < MAX_EFFECT_INDEX; ++k)
2598 if(spellEntry->Effect[k]==SPELL_EFFECT_SUMMON || spellEntry->Effect[k]==SPELL_EFFECT_SUMMON_PET)
2600 uint32 creature_id = spellEntry->EffectMiscValue[k];
2601 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(creature_id);
2602 if(!cInfo)
2603 continue;
2605 // already loaded
2606 if(cInfo->PetSpellDataId)
2607 continue;
2609 // for creature without PetSpellDataId get default pet spells from creature_template
2610 int32 petSpellsId = cInfo->Entry;
2611 if(mPetDefaultSpellsMap.find(cInfo->Entry) != mPetDefaultSpellsMap.end())
2612 continue;
2614 PetDefaultSpellsEntry petDefSpells;
2615 for(int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2616 petDefSpells.spellid[j] = cInfo->spells[j];
2618 if(LoadPetDefaultSpells_helper(cInfo, petDefSpells))
2620 mPetDefaultSpellsMap[petSpellsId] = petDefSpells;
2621 ++countCreature;
2627 sLog.outString();
2628 sLog.outString( ">> Loaded addition spells for %u pet spell data entries and %u summonable creature templates", countData, countCreature );
2631 /// Some checks for spells, to prevent adding deprecated/broken spells for trainers, spell book, etc
2632 bool SpellMgr::IsSpellValid(SpellEntry const* spellInfo, Player* pl, bool msg)
2634 // not exist
2635 if(!spellInfo)
2636 return false;
2638 bool need_check_reagents = false;
2640 // check effects
2641 for(int i = 0; i < MAX_EFFECT_INDEX; ++i)
2643 switch(spellInfo->Effect[i])
2645 case 0:
2646 continue;
2648 // craft spell for crafting non-existed item (break client recipes list show)
2649 case SPELL_EFFECT_CREATE_ITEM:
2650 case SPELL_EFFECT_CREATE_ITEM_2:
2652 if (spellInfo->EffectItemType[i] == 0)
2654 // skip auto-loot crafting spells, its not need explicit item info (but have special fake items sometime)
2655 if (!IsLootCraftingSpell(spellInfo))
2657 if(msg)
2659 if(pl)
2660 ChatHandler(pl).PSendSysMessage("Craft spell %u not have create item entry.",spellInfo->Id);
2661 else
2662 sLog.outErrorDb("Craft spell %u not have create item entry.",spellInfo->Id);
2664 return false;
2668 // also possible IsLootCraftingSpell case but fake item must exist anyway
2669 else if (!ObjectMgr::GetItemPrototype( spellInfo->EffectItemType[i] ))
2671 if(msg)
2673 if(pl)
2674 ChatHandler(pl).PSendSysMessage("Craft spell %u create item (Entry: %u) but item does not exist in item_template.",spellInfo->Id,spellInfo->EffectItemType[i]);
2675 else
2676 sLog.outErrorDb("Craft spell %u create item (Entry: %u) but item does not exist in item_template.",spellInfo->Id,spellInfo->EffectItemType[i]);
2678 return false;
2681 need_check_reagents = true;
2682 break;
2684 case SPELL_EFFECT_LEARN_SPELL:
2686 SpellEntry const* spellInfo2 = sSpellStore.LookupEntry(spellInfo->EffectTriggerSpell[i]);
2687 if( !IsSpellValid(spellInfo2,pl,msg) )
2689 if(msg)
2691 if(pl)
2692 ChatHandler(pl).PSendSysMessage("Spell %u learn to broken spell %u, and then...",spellInfo->Id,spellInfo->EffectTriggerSpell[i]);
2693 else
2694 sLog.outErrorDb("Spell %u learn to invalid spell %u, and then...",spellInfo->Id,spellInfo->EffectTriggerSpell[i]);
2696 return false;
2698 break;
2703 if(need_check_reagents)
2705 for(int j = 0; j < 8; ++j)
2707 if(spellInfo->Reagent[j] > 0 && !ObjectMgr::GetItemPrototype( spellInfo->Reagent[j] ))
2709 if(msg)
2711 if(pl)
2712 ChatHandler(pl).PSendSysMessage("Craft spell %u requires reagent item (Entry: %u) but item does not exist in item_template.",spellInfo->Id,spellInfo->Reagent[j]);
2713 else
2714 sLog.outErrorDb("Craft spell %u requires reagent item (Entry: %u) but item does not exist in item_template.",spellInfo->Id,spellInfo->Reagent[j]);
2716 return false;
2721 return true;
2724 void SpellMgr::LoadSpellAreas()
2726 mSpellAreaMap.clear(); // need for reload case
2727 mSpellAreaForQuestMap.clear();
2728 mSpellAreaForActiveQuestMap.clear();
2729 mSpellAreaForQuestEndMap.clear();
2730 mSpellAreaForAuraMap.clear();
2732 uint32 count = 0;
2734 // 0 1 2 3 4 5 6 7 8
2735 QueryResult *result = WorldDatabase.Query("SELECT spell, area, quest_start, quest_start_active, quest_end, aura_spell, racemask, gender, autocast FROM spell_area");
2737 if( !result )
2739 barGoLink bar( 1 );
2741 bar.step();
2743 sLog.outString();
2744 sLog.outString( ">> Loaded %u spell area requirements", count );
2745 return;
2748 barGoLink bar( (int)result->GetRowCount() );
2752 Field *fields = result->Fetch();
2754 bar.step();
2756 uint32 spell = fields[0].GetUInt32();
2757 SpellArea spellArea;
2758 spellArea.spellId = spell;
2759 spellArea.areaId = fields[1].GetUInt32();
2760 spellArea.questStart = fields[2].GetUInt32();
2761 spellArea.questStartCanActive = fields[3].GetBool();
2762 spellArea.questEnd = fields[4].GetUInt32();
2763 spellArea.auraSpell = fields[5].GetInt32();
2764 spellArea.raceMask = fields[6].GetUInt32();
2765 spellArea.gender = Gender(fields[7].GetUInt8());
2766 spellArea.autocast = fields[8].GetBool();
2768 if(!sSpellStore.LookupEntry(spell))
2770 sLog.outErrorDb("Spell %u listed in `spell_area` does not exist", spell);
2771 continue;
2775 bool ok = true;
2776 SpellAreaMapBounds sa_bounds = GetSpellAreaMapBounds(spellArea.spellId);
2777 for(SpellAreaMap::const_iterator itr = sa_bounds.first; itr != sa_bounds.second; ++itr)
2779 if (spellArea.spellId != itr->second.spellId)
2780 continue;
2781 if (spellArea.areaId != itr->second.areaId)
2782 continue;
2783 if (spellArea.questStart != itr->second.questStart)
2784 continue;
2785 if (spellArea.auraSpell != itr->second.auraSpell)
2786 continue;
2787 if ((spellArea.raceMask & itr->second.raceMask) == 0)
2788 continue;
2789 if (spellArea.gender != itr->second.gender)
2790 continue;
2792 // duplicate by requirements
2793 ok =false;
2794 break;
2797 if(!ok)
2799 sLog.outErrorDb("Spell %u listed in `spell_area` already listed with similar requirements.", spell);
2800 continue;
2805 if(spellArea.areaId && !GetAreaEntryByAreaID(spellArea.areaId))
2807 sLog.outErrorDb("Spell %u listed in `spell_area` have wrong area (%u) requirement", spell,spellArea.areaId);
2808 continue;
2811 if(spellArea.questStart && !sObjectMgr.GetQuestTemplate(spellArea.questStart))
2813 sLog.outErrorDb("Spell %u listed in `spell_area` have wrong start quest (%u) requirement", spell,spellArea.questStart);
2814 continue;
2817 if(spellArea.questEnd)
2819 if(!sObjectMgr.GetQuestTemplate(spellArea.questEnd))
2821 sLog.outErrorDb("Spell %u listed in `spell_area` have wrong end quest (%u) requirement", spell,spellArea.questEnd);
2822 continue;
2825 if(spellArea.questEnd==spellArea.questStart && !spellArea.questStartCanActive)
2827 sLog.outErrorDb("Spell %u listed in `spell_area` have quest (%u) requirement for start and end in same time", spell,spellArea.questEnd);
2828 continue;
2832 if(spellArea.auraSpell)
2834 SpellEntry const* spellInfo = sSpellStore.LookupEntry(abs(spellArea.auraSpell));
2835 if(!spellInfo)
2837 sLog.outErrorDb("Spell %u listed in `spell_area` have wrong aura spell (%u) requirement", spell,abs(spellArea.auraSpell));
2838 continue;
2841 switch(spellInfo->EffectApplyAuraName[EFFECT_INDEX_0])
2843 case SPELL_AURA_DUMMY:
2844 case SPELL_AURA_PHASE:
2845 case SPELL_AURA_GHOST:
2846 break;
2847 default:
2848 sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell requirement (%u) without dummy/phase/ghost aura in effect 0", spell,abs(spellArea.auraSpell));
2849 continue;
2852 if(abs(spellArea.auraSpell)==spellArea.spellId)
2854 sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement for itself", spell,abs(spellArea.auraSpell));
2855 continue;
2858 // not allow autocast chains by auraSpell field (but allow use as alternative if not present)
2859 if(spellArea.autocast && spellArea.auraSpell > 0)
2861 bool chain = false;
2862 SpellAreaForAuraMapBounds saBound = GetSpellAreaForAuraMapBounds(spellArea.spellId);
2863 for(SpellAreaForAuraMap::const_iterator itr = saBound.first; itr != saBound.second; ++itr)
2865 if(itr->second->autocast && itr->second->auraSpell > 0)
2867 chain = true;
2868 break;
2872 if(chain)
2874 sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell,spellArea.auraSpell);
2875 continue;
2878 SpellAreaMapBounds saBound2 = GetSpellAreaMapBounds(spellArea.auraSpell);
2879 for(SpellAreaMap::const_iterator itr2 = saBound2.first; itr2 != saBound2.second; ++itr2)
2881 if(itr2->second.autocast && itr2->second.auraSpell > 0)
2883 chain = true;
2884 break;
2888 if(chain)
2890 sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell,spellArea.auraSpell);
2891 continue;
2896 if(spellArea.raceMask && (spellArea.raceMask & RACEMASK_ALL_PLAYABLE)==0)
2898 sLog.outErrorDb("Spell %u listed in `spell_area` have wrong race mask (%u) requirement", spell,spellArea.raceMask);
2899 continue;
2902 if(spellArea.gender!=GENDER_NONE && spellArea.gender!=GENDER_FEMALE && spellArea.gender!=GENDER_MALE)
2904 sLog.outErrorDb("Spell %u listed in `spell_area` have wrong gender (%u) requirement", spell,spellArea.gender);
2905 continue;
2908 SpellArea const* sa = &mSpellAreaMap.insert(SpellAreaMap::value_type(spell,spellArea))->second;
2910 // for search by current zone/subzone at zone/subzone change
2911 if(spellArea.areaId)
2912 mSpellAreaForAreaMap.insert(SpellAreaForAreaMap::value_type(spellArea.areaId,sa));
2914 // for search at quest start/reward
2915 if(spellArea.questStart)
2917 if(spellArea.questStartCanActive)
2918 mSpellAreaForActiveQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart,sa));
2919 else
2920 mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart,sa));
2923 // for search at quest start/reward
2924 if(spellArea.questEnd)
2925 mSpellAreaForQuestEndMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd,sa));
2927 // for search at aura apply
2928 if(spellArea.auraSpell)
2929 mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(abs(spellArea.auraSpell),sa));
2931 ++count;
2932 } while( result->NextRow() );
2934 delete result;
2936 sLog.outString();
2937 sLog.outString( ">> Loaded %u spell area requirements", count );
2940 SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player)
2942 // normal case
2943 if (spellInfo->AreaGroupId > 0)
2945 bool found = false;
2946 AreaGroupEntry const* groupEntry = sAreaGroupStore.LookupEntry(spellInfo->AreaGroupId);
2947 while (groupEntry)
2949 for (uint32 i=0; i<6; ++i)
2950 if (groupEntry->AreaId[i] == zone_id || groupEntry->AreaId[i] == area_id)
2951 found = true;
2952 if (found || !groupEntry->nextGroup)
2953 break;
2954 // Try search in next group
2955 groupEntry = sAreaGroupStore.LookupEntry(groupEntry->nextGroup);
2958 if (!found)
2959 return SPELL_FAILED_INCORRECT_AREA;
2962 // continent limitation (virtual continent)
2963 if (spellInfo->AttributesEx4 & SPELL_ATTR_EX4_CAST_ONLY_IN_OUTLAND)
2965 uint32 v_map = GetVirtualMapForMapAndZone(map_id, zone_id);
2966 MapEntry const* mapEntry = sMapStore.LookupEntry(v_map);
2967 if (!mapEntry || mapEntry->addon < 1 || !mapEntry->IsContinent())
2968 return SPELL_FAILED_INCORRECT_AREA;
2971 // raid instance limitation
2972 if (spellInfo->AttributesEx6 & SPELL_ATTR_EX6_NOT_IN_RAID_INSTANCE)
2974 MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
2975 if (!mapEntry || mapEntry->IsRaid())
2976 return SPELL_FAILED_NOT_IN_RAID_INSTANCE;
2979 // DB base check (if non empty then must fit at least single for allow)
2980 SpellAreaMapBounds saBounds = GetSpellAreaMapBounds(spellInfo->Id);
2981 if (saBounds.first != saBounds.second)
2983 for(SpellAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
2985 if(itr->second.IsFitToRequirements(player,zone_id,area_id))
2986 return SPELL_CAST_OK;
2988 return SPELL_FAILED_INCORRECT_AREA;
2991 // bg spell checks
2993 // do not allow spells to be cast in arenas
2994 // - with SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA flag
2995 // - with greater than 15 min CD
2996 if ((spellInfo->AttributesEx4 & SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA) ||
2997 (GetSpellRecoveryTime(spellInfo) > 15 * MINUTE * IN_MILISECONDS && !(spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA)))
2998 if (player && player->InArena())
2999 return SPELL_FAILED_NOT_IN_ARENA;
3001 // Spell casted only on battleground
3002 if ((spellInfo->AttributesEx3 & SPELL_ATTR_EX3_BATTLEGROUND))
3003 if (!player || !player->InBattleGround())
3004 return SPELL_FAILED_ONLY_BATTLEGROUNDS;
3006 switch(spellInfo->Id)
3008 // a trinket in alterac valley allows to teleport to the boss
3009 case 22564: // recall
3010 case 22563: // recall
3012 if (!player)
3013 return SPELL_FAILED_REQUIRES_AREA;
3014 BattleGround* bg = player->GetBattleGround();
3015 return map_id == 30 && bg
3016 && bg->GetStatus() != STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
3018 case 23333: // Warsong Flag
3019 case 23335: // Silverwing Flag
3020 return map_id == 489 && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
3021 case 34976: // Netherstorm Flag
3022 return map_id == 566 && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
3023 case 2584: // Waiting to Resurrect
3024 case 42792: // Recently Dropped Flag
3025 case 43681: // Inactive
3027 return player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_ONLY_BATTLEGROUNDS;
3029 case 22011: // Spirit Heal Channel
3030 case 22012: // Spirit Heal
3031 case 24171: // Resurrection Impact Visual
3032 case 44535: // Spirit Heal (mana)
3034 MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
3035 if (!mapEntry)
3036 return SPELL_FAILED_INCORRECT_AREA;
3037 return mapEntry->IsBattleGround()? SPELL_CAST_OK : SPELL_FAILED_ONLY_BATTLEGROUNDS;
3039 case 44521: // Preparation
3041 if (!player)
3042 return SPELL_FAILED_REQUIRES_AREA;
3044 BattleGround* bg = player->GetBattleGround();
3045 return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_ONLY_BATTLEGROUNDS;
3047 case 32724: // Gold Team (Alliance)
3048 case 32725: // Green Team (Alliance)
3049 case 35774: // Gold Team (Horde)
3050 case 35775: // Green Team (Horde)
3052 return player && player->InArena() ? SPELL_CAST_OK : SPELL_FAILED_ONLY_IN_ARENA;
3054 case 32727: // Arena Preparation
3056 if (!player)
3057 return SPELL_FAILED_REQUIRES_AREA;
3058 if (!player->InArena())
3059 return SPELL_FAILED_REQUIRES_AREA;
3061 BattleGround* bg = player->GetBattleGround();
3062 return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_ONLY_IN_ARENA;
3066 return SPELL_CAST_OK;
3069 void SpellMgr::LoadSkillLineAbilityMap()
3071 mSkillLineAbilityMap.clear();
3073 barGoLink bar( (int)sSkillLineAbilityStore.GetNumRows() );
3074 uint32 count = 0;
3076 for (uint32 i = 0; i < sSkillLineAbilityStore.GetNumRows(); ++i)
3078 bar.step();
3079 SkillLineAbilityEntry const *SkillInfo = sSkillLineAbilityStore.LookupEntry(i);
3080 if(!SkillInfo)
3081 continue;
3083 mSkillLineAbilityMap.insert(SkillLineAbilityMap::value_type(SkillInfo->spellId,SkillInfo));
3084 ++count;
3087 sLog.outString();
3088 sLog.outString(">> Loaded %u SkillLineAbility MultiMap Data", count);
3091 void SpellMgr::CheckUsedSpells(char const* table)
3093 uint32 countSpells = 0;
3094 uint32 countMasks = 0;
3096 // 0 1 2 3 4 5 6 7 8 9 10 11
3097 QueryResult *result = WorldDatabase.PQuery("SELECT spellid,SpellFamilyName,SpellFamilyMaskA,SpellFamilyMaskB,SpellIcon,SpellVisual,SpellCategory,EffectType,EffectAura,EffectIdx,Name,Code FROM %s",table);
3099 if( !result )
3101 barGoLink bar( 1 );
3103 bar.step();
3105 sLog.outString();
3106 sLog.outErrorDb("`%s` table is empty!",table);
3107 return;
3110 barGoLink bar( (int)result->GetRowCount() );
3114 Field *fields = result->Fetch();
3116 bar.step();
3118 uint32 spell = fields[0].GetUInt32();
3119 int32 family = fields[1].GetInt32();
3120 uint64 familyMaskA = fields[2].GetUInt64();
3121 uint32 familyMaskB = fields[3].GetUInt32();
3122 int32 spellIcon = fields[4].GetInt32();
3123 int32 spellVisual = fields[5].GetInt32();
3124 int32 category = fields[6].GetInt32();
3125 int32 effectType = fields[7].GetInt32();
3126 int32 auraType = fields[8].GetInt32();
3127 int32 effectIdx = fields[9].GetInt32();
3128 std::string name = fields[10].GetCppString();
3129 std::string code = fields[11].GetCppString();
3131 // checks of correctness requirements itself
3133 if (family < -1 || family > SPELLFAMILY_PET)
3135 sLog.outError("Table '%s' for spell %u have wrong SpellFamily value(%u), skipped.",table,spell,family);
3136 continue;
3139 // TODO: spellIcon check need dbc loading
3140 if (spellIcon < -1)
3142 sLog.outError("Table '%s' for spell %u have wrong SpellIcon value(%u), skipped.",table,spell,spellIcon);
3143 continue;
3146 // TODO: spellVisual check need dbc loading
3147 if (spellVisual < -1)
3149 sLog.outError("Table '%s' for spell %u have wrong SpellVisual value(%u), skipped.",table,spell,spellVisual);
3150 continue;
3153 // TODO: for spellCategory better check need dbc loading
3154 if (category < -1 || category >=0 && sSpellCategoryStore.find(category) == sSpellCategoryStore.end())
3156 sLog.outError("Table '%s' for spell %u have wrong SpellCategory value(%u), skipped.",table,spell,category);
3157 continue;
3160 if (effectType < -1 || effectType >= TOTAL_SPELL_EFFECTS)
3162 sLog.outError("Table '%s' for spell %u have wrong SpellEffect type value(%u), skipped.",table,spell,effectType);
3163 continue;
3166 if (auraType < -1 || auraType >= TOTAL_AURAS)
3168 sLog.outError("Table '%s' for spell %u have wrong SpellAura type value(%u), skipped.",table,spell,auraType);
3169 continue;
3172 if (effectIdx < -1 || effectIdx >= 3)
3174 sLog.outError("Table '%s' for spell %u have wrong EffectIdx value(%u), skipped.",table,spell,effectIdx);
3175 continue;
3178 // now checks of requirements
3180 if(spell)
3182 ++countSpells;
3184 SpellEntry const* spellEntry = sSpellStore.LookupEntry(spell);
3185 if(!spellEntry)
3187 sLog.outError("Spell %u '%s' not exist but used in %s.",spell,name.c_str(),code.c_str());
3188 continue;
3191 if(family >= 0 && spellEntry->SpellFamilyName != family)
3193 sLog.outError("Spell %u '%s' family(%u) <> %u but used in %s.",spell,name.c_str(),spellEntry->SpellFamilyName,family,code.c_str());
3194 continue;
3197 if(familyMaskA != UI64LIT(0xFFFFFFFFFFFFFFFF) || familyMaskB != 0xFFFFFFFF)
3199 if(familyMaskA == UI64LIT(0x0000000000000000) && familyMaskB == 0x00000000)
3201 if(spellEntry->SpellFamilyFlags != 0 || spellEntry->SpellFamilyFlags2 != 0)
3203 sLog.outError("Spell %u '%s' not fit to (" I64FMT "," I32FMT ") but used in %s.",
3204 spell, name.c_str(), familyMaskA, familyMaskB, code.c_str());
3205 continue;
3209 else
3211 if((spellEntry->SpellFamilyFlags & familyMaskA)==0 && (spellEntry->SpellFamilyFlags2 & familyMaskB)==0)
3213 sLog.outError("Spell %u '%s' not fit to (" I64FMT "," I32FMT ") but used in %s.",spell,name.c_str(),familyMaskA,familyMaskB,code.c_str());
3214 continue;
3220 if(spellIcon >= 0 && spellEntry->SpellIconID != spellIcon)
3222 sLog.outError("Spell %u '%s' icon(%u) <> %u but used in %s.",spell,name.c_str(),spellEntry->SpellIconID,spellIcon,code.c_str());
3223 continue;
3226 if(spellVisual >= 0 && spellEntry->SpellVisual[0] != spellVisual)
3228 sLog.outError("Spell %u '%s' visual(%u) <> %u but used in %s.",spell,name.c_str(),spellEntry->SpellVisual[0],spellVisual,code.c_str());
3229 continue;
3232 if(category >= 0 && spellEntry->Category != category)
3234 sLog.outError("Spell %u '%s' category(%u) <> %u but used in %s.",spell,name.c_str(),spellEntry->Category,category,code.c_str());
3235 continue;
3238 if (effectIdx >= EFFECT_INDEX_0)
3240 if(effectType >= 0 && spellEntry->Effect[effectIdx] != effectType)
3242 sLog.outError("Spell %u '%s' effect%d <> %u but used in %s.",spell,name.c_str(),effectIdx+1,effectType,code.c_str());
3243 continue;
3246 if(auraType >= 0 && spellEntry->EffectApplyAuraName[effectIdx] != auraType)
3248 sLog.outError("Spell %u '%s' aura%d <> %u but used in %s.",spell,name.c_str(),effectIdx+1,auraType,code.c_str());
3249 continue;
3253 else
3255 if(effectType >= 0 && !IsSpellHaveEffect(spellEntry,SpellEffects(effectType)))
3257 sLog.outError("Spell %u '%s' not have effect %u but used in %s.",spell,name.c_str(),effectType,code.c_str());
3258 continue;
3261 if(auraType >= 0 && !IsSpellHaveAura(spellEntry,AuraType(auraType)))
3263 sLog.outError("Spell %u '%s' not have aura %u but used in %s.",spell,name.c_str(),auraType,code.c_str());
3264 continue;
3268 else
3270 ++countMasks;
3272 bool found = false;
3273 for(uint32 spellId = 1; spellId < sSpellStore.GetNumRows(); ++spellId)
3275 SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId);
3276 if(!spellEntry)
3277 continue;
3279 if(family >=0 && spellEntry->SpellFamilyName != family)
3280 continue;
3282 if(familyMaskA != UI64LIT(0xFFFFFFFFFFFFFFFF) || familyMaskB != 0xFFFFFFFF)
3284 if(familyMaskA == UI64LIT(0x0000000000000000) && familyMaskB == 0x00000000)
3286 if(spellEntry->SpellFamilyFlags != 0 || spellEntry->SpellFamilyFlags2 != 0)
3287 continue;
3289 else
3291 if((spellEntry->SpellFamilyFlags & familyMaskA)==0 && (spellEntry->SpellFamilyFlags2 & familyMaskB)==0)
3292 continue;
3296 if(spellIcon >= 0 && spellEntry->SpellIconID != spellIcon)
3297 continue;
3299 if(spellVisual >= 0 && spellEntry->SpellVisual[0] != spellVisual)
3300 continue;
3302 if(category >= 0 && spellEntry->Category != category)
3303 continue;
3305 if(effectIdx >= 0)
3307 if(effectType >=0 && spellEntry->Effect[effectIdx] != effectType)
3308 continue;
3310 if(auraType >=0 && spellEntry->EffectApplyAuraName[effectIdx] != auraType)
3311 continue;
3313 else
3315 if(effectType >=0 && !IsSpellHaveEffect(spellEntry,SpellEffects(effectType)))
3316 continue;
3318 if(auraType >=0 && !IsSpellHaveAura(spellEntry,AuraType(auraType)))
3319 continue;
3322 found = true;
3323 break;
3326 if(!found)
3328 if(effectIdx >= 0)
3329 sLog.outError("Spells '%s' not found for family %i (" I64FMT "," I32FMT ") icon(%i) visual(%i) category(%i) effect%d(%i) aura%d(%i) but used in %s",
3330 name.c_str(),family,familyMaskA,familyMaskB,spellIcon,spellVisual,category,effectIdx+1,effectType,effectIdx+1,auraType,code.c_str());
3331 else
3332 sLog.outError("Spells '%s' not found for family %i (" I64FMT "," I32FMT ") icon(%i) visual(%i) category(%i) effect(%i) aura(%i) but used in %s",
3333 name.c_str(),family,familyMaskA,familyMaskB,spellIcon,spellVisual,category,effectType,auraType,code.c_str());
3334 continue;
3338 } while( result->NextRow() );
3340 delete result;
3342 sLog.outString();
3343 sLog.outString( ">> Checked %u spells and %u spell masks", countSpells, countMasks );
3346 DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto, bool triggered)
3348 // Explicit Diminishing Groups
3349 switch(spellproto->SpellFamilyName)
3351 case SPELLFAMILY_GENERIC:
3352 // some generic arena related spells have by some strange reason MECHANIC_TURN
3353 if (spellproto->Mechanic == MECHANIC_TURN)
3354 return DIMINISHING_NONE;
3355 break;
3356 case SPELLFAMILY_MAGE:
3357 // Dragon's Breath
3358 if (spellproto->SpellIconID == 1548)
3359 return DIMINISHING_DISORIENT;
3360 break;
3361 case SPELLFAMILY_ROGUE:
3363 // Blind
3364 if (spellproto->SpellFamilyFlags & UI64LIT(0x00001000000))
3365 return DIMINISHING_FEAR_CHARM_BLIND;
3366 // Cheap Shot
3367 else if (spellproto->SpellFamilyFlags & UI64LIT(0x00000000400))
3368 return DIMINISHING_CHEAPSHOT_POUNCE;
3369 // Crippling poison - Limit to 10 seconds in PvP (No SpellFamilyFlags)
3370 else if (spellproto->SpellIconID == 163)
3371 return DIMINISHING_LIMITONLY;
3372 break;
3374 case SPELLFAMILY_HUNTER:
3376 // Freezing Trap & Freezing Arrow & Wyvern Sting
3377 if (spellproto->SpellIconID == 180 || spellproto->SpellIconID == 1721)
3378 return DIMINISHING_DISORIENT;
3379 break;
3381 case SPELLFAMILY_WARLOCK:
3383 // Curses/etc
3384 if (spellproto->SpellFamilyFlags & UI64LIT(0x00080000000))
3385 return DIMINISHING_LIMITONLY;
3386 break;
3388 case SPELLFAMILY_DRUID:
3390 // Cyclone
3391 if (spellproto->SpellFamilyFlags & UI64LIT(0x02000000000))
3392 return DIMINISHING_CYCLONE;
3393 // Pounce
3394 else if (spellproto->SpellFamilyFlags & UI64LIT(0x00000020000))
3395 return DIMINISHING_CHEAPSHOT_POUNCE;
3396 // Faerie Fire
3397 else if (spellproto->SpellFamilyFlags & UI64LIT(0x00000000400))
3398 return DIMINISHING_LIMITONLY;
3399 break;
3401 case SPELLFAMILY_WARRIOR:
3403 // Hamstring - limit duration to 10s in PvP
3404 if (spellproto->SpellFamilyFlags & UI64LIT(0x00000000002))
3405 return DIMINISHING_LIMITONLY;
3406 break;
3408 case SPELLFAMILY_PRIEST:
3410 // Vampiric Embrace
3411 if ((spellproto->SpellFamilyFlags & UI64LIT(0x00000000004)) && spellproto->SpellIconID == 150)
3412 return DIMINISHING_LIMITONLY;
3413 // Shackle Undead
3414 else if (spellproto->SpellIconID == 27)
3415 return DIMINISHING_DISORIENT;
3416 break;
3418 case SPELLFAMILY_DEATHKNIGHT:
3420 // Hungering Cold (no flags)
3421 if (spellproto->SpellIconID == 2797)
3422 return DIMINISHING_DISORIENT;
3423 break;
3425 default:
3426 break;
3429 // Get by mechanic
3430 uint32 mechanic = GetAllSpellMechanicMask(spellproto);
3431 if (!mechanic)
3432 return DIMINISHING_NONE;
3434 if (mechanic & ((1<<(MECHANIC_STUN-1))|(1<<(MECHANIC_SHACKLE-1))))
3435 return triggered ? DIMINISHING_TRIGGER_STUN : DIMINISHING_CONTROL_STUN;
3436 if (mechanic & ((1<<(MECHANIC_SLEEP-1))|(1<<(MECHANIC_FREEZE-1))))
3437 return DIMINISHING_FREEZE_SLEEP;
3438 if (mechanic & ((1<<(MECHANIC_KNOCKOUT-1))|(1<<(MECHANIC_POLYMORPH-1))|(1<<(MECHANIC_SAPPED-1))))
3439 return DIMINISHING_DISORIENT;
3440 if (mechanic & (1<<(MECHANIC_ROOT-1)))
3441 return triggered ? DIMINISHING_TRIGGER_ROOT : DIMINISHING_CONTROL_ROOT;
3442 if (mechanic & ((1<<(MECHANIC_FEAR-1))|(1<<(MECHANIC_CHARM-1))))
3443 return DIMINISHING_FEAR_CHARM_BLIND;
3444 if (mechanic & ((1<<(MECHANIC_SILENCE-1))|(1<<(MECHANIC_INTERRUPT-1))))
3445 return DIMINISHING_SILENCE;
3446 if (mechanic & (1<<(MECHANIC_DISARM-1)))
3447 return DIMINISHING_DISARM;
3448 if (mechanic & (1<<(MECHANIC_BANISH-1)))
3449 return DIMINISHING_BANISH;
3450 if (mechanic & (1<<(MECHANIC_HORROR-1)))
3451 return DIMINISHING_HORROR;
3453 return DIMINISHING_NONE;
3456 int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellEntry const* spellproto)
3458 if(!IsDiminishingReturnsGroupDurationLimited(group))
3459 return 0;
3461 // Explicit diminishing duration
3462 switch(spellproto->SpellFamilyName)
3464 case SPELLFAMILY_HUNTER:
3466 // Wyvern Sting
3467 if (spellproto->SpellFamilyFlags & UI64LIT(0x0000100000000000))
3468 return 6000;
3469 break;
3471 case SPELLFAMILY_PALADIN:
3473 // Repentance - limit to 6 seconds in PvP
3474 if (spellproto->SpellFamilyFlags & UI64LIT(0x00000000004))
3475 return 6000;
3476 break;
3478 case SPELLFAMILY_DRUID:
3480 // Faerie Fire - limit to 40 seconds in PvP (3.1)
3481 if (spellproto->SpellFamilyFlags & UI64LIT(0x00000000400))
3482 return 40000;
3483 break;
3485 case SPELLFAMILY_PRIEST:
3487 // Vampiric Embrace - limit to 60 seconds in PvP (3.1)
3488 if ((spellproto->SpellFamilyFlags & UI64LIT(0x00000000004)) && spellproto->SpellIconID == 150)
3489 return 60000;
3490 break;
3492 default:
3493 break;
3496 return 10000;
3499 bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group)
3501 switch(group)
3503 case DIMINISHING_CONTROL_STUN:
3504 case DIMINISHING_TRIGGER_STUN:
3505 case DIMINISHING_CONTROL_ROOT:
3506 case DIMINISHING_TRIGGER_ROOT:
3507 case DIMINISHING_FEAR_CHARM_BLIND:
3508 case DIMINISHING_DISORIENT:
3509 case DIMINISHING_CHEAPSHOT_POUNCE:
3510 case DIMINISHING_FREEZE_SLEEP:
3511 case DIMINISHING_CYCLONE:
3512 case DIMINISHING_BANISH:
3513 case DIMINISHING_LIMITONLY:
3514 return true;
3515 default:
3516 return false;
3518 return false;
3521 DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group)
3523 switch(group)
3525 case DIMINISHING_CYCLONE:
3526 case DIMINISHING_TRIGGER_STUN:
3527 case DIMINISHING_CONTROL_STUN:
3528 return DRTYPE_ALL;
3529 case DIMINISHING_CONTROL_ROOT:
3530 case DIMINISHING_TRIGGER_ROOT:
3531 case DIMINISHING_FEAR_CHARM_BLIND:
3532 case DIMINISHING_DISORIENT:
3533 case DIMINISHING_SILENCE:
3534 case DIMINISHING_DISARM:
3535 case DIMINISHING_HORROR:
3536 case DIMINISHING_FREEZE_SLEEP:
3537 case DIMINISHING_BANISH:
3538 case DIMINISHING_CHEAPSHOT_POUNCE:
3539 return DRTYPE_PLAYER;
3540 default:
3541 break;
3544 return DRTYPE_NONE;
3547 bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const
3549 if(gender!=GENDER_NONE)
3551 // not in expected gender
3552 if(!player || gender != player->getGender())
3553 return false;
3556 if(raceMask)
3558 // not in expected race
3559 if(!player || !(raceMask & player->getRaceMask()))
3560 return false;
3563 if(areaId)
3565 // not in expected zone
3566 if(newZone!=areaId && newArea!=areaId)
3567 return false;
3570 if(questStart)
3572 // not in expected required quest state
3573 if(!player || (!questStartCanActive || !player->IsActiveQuest(questStart)) && !player->GetQuestRewardStatus(questStart))
3574 return false;
3577 if(questEnd)
3579 // not in expected forbidden quest state
3580 if(!player || player->GetQuestRewardStatus(questEnd))
3581 return false;
3584 if(auraSpell)
3586 // not have expected aura
3587 if(!player)
3588 return false;
3589 if(auraSpell > 0)
3590 // have expected aura
3591 return player->HasAura(auraSpell, EFFECT_INDEX_0);
3592 else
3593 // not have expected aura
3594 return !player->HasAura(-auraSpell, EFFECT_INDEX_0);
3597 return true;