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
20 #include "ObjectMgr.h"
21 #include "SpellAuraDefines.h"
22 #include "ProgressBar.h"
23 #include "DBCStores.h"
27 #include "BattleGroundMgr.h"
28 #include "MapManager.h"
38 SpellMgr
& SpellMgr::Instance()
40 static SpellMgr spellMgr
;
44 int32
GetSpellDuration(SpellEntry
const *spellInfo
)
48 SpellDurationEntry
const *du
= sSpellDurationStore
.LookupEntry(spellInfo
->DurationIndex
);
51 return (du
->Duration
[0] == -1) ? -1 : abs(du
->Duration
[0]);
54 int32
GetSpellMaxDuration(SpellEntry
const *spellInfo
)
58 SpellDurationEntry
const *du
= sSpellDurationStore
.LookupEntry(spellInfo
->DurationIndex
);
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())
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
)
76 int32 castTime
= spellCastTimeEntry
->CastTime
;
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
));
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()))
95 return (castTime
> 0) ? uint32(castTime
) : 0;
98 uint16
GetSpellAuraMaxTicks(SpellEntry
const* spellInfo
)
100 int32 DotDuration
= GetSpellDuration(spellInfo
);
105 if(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
];
124 WeaponAttackType
GetWeaponAttackType(SpellEntry
const *spellInfo
)
129 switch (spellInfo
->DmgClass
)
131 case SPELL_DAMAGE_CLASS_MELEE
:
132 if (spellInfo
->AttributesEx3
& SPELL_ATTR_EX3_REQ_OFFHAND
)
137 case SPELL_DAMAGE_CLASS_RANGED
:
138 return RANGED_ATTACK
;
142 if (spellInfo
->AttributesEx2
& SPELL_ATTR_EX2_AUTOREPEAT_FLAG
)
143 return RANGED_ATTACK
;
150 bool IsPassiveSpell(uint32 spellId
)
152 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
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
])
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)
187 SpellSpecific
GetSpellSpecific(uint32 spellId
)
189 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
193 switch(spellInfo
->SpellFamilyName
)
195 case SPELLFAMILY_GENERIC
:
197 // Food / Drinks (mostly)
198 if(spellInfo
->AuraInterruptFlags
& AURA_INTERRUPT_FLAG_NOT_SEATED
)
202 for(int i
= 0; i
< MAX_EFFECT_INDEX
; ++i
)
204 switch(spellInfo
->EffectApplyAuraName
[i
])
207 case SPELL_AURA_MOD_REGEN
:
208 case SPELL_AURA_OBS_MOD_HEALTH
:
212 case SPELL_AURA_MOD_POWER_REGEN
:
213 case SPELL_AURA_OBS_MOD_MANA
:
222 return SPELL_FOOD_AND_DRINK
;
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
;
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
;
248 case SPELLFAMILY_WARRIOR
:
250 if (spellInfo
->SpellFamilyFlags
& UI64LIT(0x00008000010000))
251 return SPELL_POSITIVE_SHOUT
;
255 case SPELLFAMILY_WARLOCK
:
257 // only warlock curses have this
258 if (spellInfo
->Dispel
== DISPEL_CURSE
)
261 // Warlock (Demon Armor | Demon Skin | Fel Armor)
262 if (spellInfo
->SpellFamilyFlags
& UI64LIT(0x2000002000000000) || spellInfo
->SpellFamilyFlags2
& 0x00000010)
263 return SPELL_WARLOCK_ARMOR
;
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
;
276 case SPELLFAMILY_HUNTER
:
278 // only hunter stings have this
279 if (spellInfo
->Dispel
== DISPEL_POISON
)
282 // only hunter aspects have this (but not all aspects in hunter family)
283 if( spellInfo
->SpellFamilyFlags
& UI64LIT(0x0044000000380000) || spellInfo
->SpellFamilyFlags2
& 0x00001010)
288 case SPELLFAMILY_PALADIN
:
290 if (IsSealSpell(spellInfo
))
293 if (spellInfo
->SpellFamilyFlags
& UI64LIT(0x0000000011010002))
294 return SPELL_BLESSING
;
296 if (spellInfo
->SpellFamilyFlags
& UI64LIT(0x0000000000002190))
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 )
309 case SPELLFAMILY_SHAMAN
:
311 if (IsElementalShield(spellInfo
))
312 return SPELL_ELEMENTAL_SHIELD
;
317 case SPELLFAMILY_POTION
:
318 return sSpellMgr
.GetSpellElixirSpecific(spellInfo
->Id
);
320 case SPELLFAMILY_DEATHKNIGHT
:
321 if (spellInfo
->Category
== 47)
322 return SPELL_PRESENCE
;
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
))
338 // target not allow have more one spell specific from same caster
339 bool IsSingleFromSpellSpecificPerTargetPerCaster(SpellSpecific spellSpec1
,SpellSpecific spellSpec2
)
348 case SPELL_POSITIVE_SHOUT
:
349 case SPELL_JUDGEMENT
:
351 return spellSpec1
==spellSpec2
;
357 // target not allow have more one ranks from spell from spell specific per target
358 bool IsSingleFromSpellSpecificSpellRanksPerTarget(SpellSpecific spellSpec1
,SpellSpecific spellSpec2
)
367 return spellSpec1
==spellSpec2
;
373 // target not allow have more one spell specific per target from any caster
374 bool IsSingleFromSpellSpecificPerTarget(SpellSpecific spellSpec1
,SpellSpecific spellSpec2
)
380 case SPELL_WARLOCK_ARMOR
:
381 case SPELL_MAGE_ARMOR
:
382 case SPELL_ELEMENTAL_SHIELD
:
383 case SPELL_MAGE_POLYMORPH
:
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
;
398 return spellSpec2
==SPELL_FOOD
399 || spellSpec2
==SPELL_FOOD_AND_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
;
412 bool IsPositiveTarget(uint32 targetA
, uint32 targetB
)
414 // non-positive targets
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
:
426 case TARGET_CASTER_COORDINATES
:
427 return (targetB
== TARGET_ALL_PARTY
|| targetB
== TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER
);
432 return IsPositiveTarget(targetB
, 0);
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
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
:
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
458 case TARGET_CHAIN_DAMAGE
:
459 case TARGET_CURRENT_ENEMY_COORDINATES
:
460 case TARGET_SINGLE_ENEMY
:
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
479 case 28441: // AB Effect 000
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
:
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
514 // some spells have unclear target modes for selection, so just make effect positive
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)
534 case SPELL_AURA_MOD_DAMAGE_TAKEN
: // dependent from bas point sign (positive -> negative)
535 if(spellproto
->CalculateSimpleValue(effIndex
) > 0)
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
544 case SPELL_AURA_ADD_TARGET_TRIGGER
:
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
)))
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)
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
574 if(spellproto
->Id
== 17624)
577 case SPELL_AURA_MOD_PACIFY_SILENCE
:
578 switch(spellproto
->Id
)
580 case 24740: // Wisp Costume
581 case 47585: // Dispersion
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
:
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
)
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
)
605 // but not this if this first effect (don't found better check)
606 if (spellproto
->Attributes
& 0x4000000 && effIndex
== EFFECT_INDEX_0
)
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)
618 case SPELL_AURA_MOD_SCALE
:
619 // some spells negative
620 switch(spellproto
->Id
)
622 case 802: // Mutate Bug, wrongly negative by target modes
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)
631 case SPELL_AURA_MECHANIC_IMMUNITY
:
633 // non-positive immunities
634 switch(spellproto
->EffectMiscValue
[effIndex
])
636 case MECHANIC_BANDAGE
:
637 case MECHANIC_SHIELD
:
639 case MECHANIC_INVULNERABILITY
:
645 case SPELL_AURA_ADD_FLAT_MODIFIER
: // mods
646 case SPELL_AURA_ADD_PCT_MODIFIER
:
649 switch(spellproto
->EffectMiscValue
[effIndex
])
651 case SPELLMOD_COST
: // dependent from bas point sign (negative -> positive)
652 if(spellproto
->CalculateSimpleValue(effIndex
) > 0)
659 case SPELL_AURA_FORCE_REACTION
:
660 if(spellproto
->Id
==42792) // Recently Dropped Flag (prevent cancel)
672 // non-positive targets
673 if(!IsPositiveTarget(spellproto
->EffectImplicitTargetA
[effIndex
],spellproto
->EffectImplicitTargetB
[effIndex
]))
676 // AttributesEx check
677 if(spellproto
->AttributesEx
& SPELL_ATTR_EX_NEGATIVE
)
684 bool IsPositiveSpell(uint32 spellId
)
686 SpellEntry
const *spellproto
= sSpellStore
.LookupEntry(spellId
);
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
)))
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
)
704 // TODO - need found Judgements rule
705 switch(GetSpellSpecific(spellInfo
->Id
))
707 case SPELL_JUDGEMENT
:
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))
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
)
730 // TODO - need found Judgements rule
731 SpellSpecific spec1
= GetSpellSpecific(spellInfo1
->Id
);
732 // spell with single target specific types
735 case SPELL_JUDGEMENT
:
736 case SPELL_MAGE_POLYMORPH
:
737 if(GetSpellSpecific(spellInfo2
->Id
) == spec1
)
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;
766 SpellShapeshiftEntry
const *shapeInfo
= sSpellShapeshiftStore
.LookupEntry(form
);
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
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
;
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
799 QueryResult
*result
= WorldDatabase
.Query("SELECT id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM spell_target_position");
808 sLog
.outString( ">> Loaded %u spell target coordinates", count
);
812 barGoLink
bar((int)result
->GetRowCount());
816 Field
*fields
= result
->Fetch();
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
);
833 sLog
.outErrorDb("Spell (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Spell_ID
,st
.target_mapId
);
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
);
843 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(Spell_ID
);
846 sLog
.outErrorDb("Spell (ID:%u) listed in `spell_target_position` does not exist.",Spell_ID
);
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
);
872 sLog
.outErrorDb("Spell (Id: %u) listed in `spell_target_position` does not have target TARGET_TABLE_X_Y_Z_COORDINATES (17).",Spell_ID
);
876 mSpellTargetPositions
[Spell_ID
] = st
;
879 } while( result
->NextRow() );
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
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");
907 sLog
.outString( ">> Loaded %u spell proc event conditions", count
);
911 barGoLink
bar( (int)result
->GetRowCount() );
912 uint32 customProc
= 0;
915 Field
*fields
= result
->Fetch();
919 uint32 entry
= fields
[0].GetUInt32();
921 const SpellEntry
*spell
= sSpellStore
.LookupEntry(entry
);
924 sLog
.outErrorDb("Spell %u listed in `spell_proc_event` does not exist", entry
);
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
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
);
965 } while( result
->NextRow() );
971 sLog
.outString( ">> Loaded %u extra spell proc event conditions +%u custom", count
, customProc
);
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
; }
983 void SpellMgr::LoadSpellProcItemEnchant()
985 mSpellProcItemEnchantMap
.clear(); // need for reload case
990 QueryResult
*result
= WorldDatabase
.Query("SELECT entry, ppmRate FROM spell_proc_item_enchant");
999 sLog
.outString( ">> Loaded %u proc item enchant definitions", count
);
1003 barGoLink
bar( (int)result
->GetRowCount() );
1007 Field
*fields
= result
->Fetch();
1011 uint32 entry
= fields
[0].GetUInt32();
1012 float ppmRate
= fields
[1].GetFloat();
1014 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(entry
);
1018 sLog
.outErrorDb("Spell %u listed in `spell_proc_item_enchant` does not exist", entry
);
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
1031 mSpellProcItemEnchantMap
[entry
] = ppmRate
;
1033 // also add to high ranks
1034 DoSpellProcItemEnchant
worker(ppmRate
);
1035 doForHighRanks(entry
,worker
);
1038 } while( result
->NextRow() );
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
1058 QueryResult
*result
= WorldDatabase
.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus FROM spell_bonus_data");
1064 sLog
.outString( ">> Loaded %u spell bonus data", count
);
1068 barGoLink
bar( (int)result
->GetRowCount() );
1071 Field
*fields
= result
->Fetch();
1073 uint32 entry
= fields
[0].GetUInt32();
1075 SpellEntry
const* spell
= sSpellStore
.LookupEntry(entry
);
1078 sLog
.outErrorDb("Spell %u listed in `spell_bonus_data` does not exist", entry
);
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
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
);
1105 } while( result
->NextRow() );
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)
1122 // Always trigger for this
1123 if (EventProcFlag
& (PROC_FLAG_KILLED
| PROC_FLAG_KILL
| PROC_FLAG_ON_TRAP_ACTIVATION
))
1126 if (spellProcEvent
) // Exist event data
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)
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)
1144 // Check (if set) for spellFamilyName
1145 if(spellProcEvent
->spellFamilyName
&& (spellProcEvent
->spellFamilyName
!= procSpell
->SpellFamilyName
))
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)
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
)
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
)
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
)
1173 // Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other)
1174 if (procEvent_procEx
& procExtra
)
1180 void SpellMgr::LoadSpellElixirs()
1182 mSpellElixirs
.clear(); // need for reload case
1187 QueryResult
*result
= WorldDatabase
.Query("SELECT entry, mask FROM spell_elixir");
1196 sLog
.outString( ">> Loaded %u spell elixir definitions", count
);
1200 barGoLink
bar( (int)result
->GetRowCount() );
1204 Field
*fields
= result
->Fetch();
1208 uint32 entry
= fields
[0].GetUInt32();
1209 uint8 mask
= fields
[1].GetUInt8();
1211 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(entry
);
1215 sLog
.outErrorDb("Spell %u listed in `spell_elixir` does not exist", entry
);
1219 mSpellElixirs
[entry
] = mask
;
1222 } while( result
->NextRow() );
1227 sLog
.outString( ">> Loaded %u spell elixir definitions", count
);
1230 void SpellMgr::LoadSpellThreats()
1232 mSpellThreatMap
.clear(); // need for reload case
1237 QueryResult
*result
= WorldDatabase
.Query("SELECT entry, Threat FROM spell_threat");
1246 sLog
.outString( ">> Loaded %u aggro generating spells", count
);
1250 barGoLink
bar( (int)result
->GetRowCount() );
1254 Field
*fields
= result
->Fetch();
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
);
1267 mSpellThreatMap
[entry
] = Threat
;
1270 } while( result
->NextRow() );
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
1291 if(spellInfo
->powerType
!= POWER_MANA
&& spellInfo
->powerType
!= POWER_HEALTH
)
1293 if(IsProfessionOrRidingSpell(spellInfo
->Id
))
1296 if(sSpellMgr
.IsSkillBonusSpell(spellInfo
->Id
))
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
)
1309 case SPELLFAMILY_DRUID
:
1311 if (spellInfo
->Effect
[i
]==SPELL_EFFECT_APPLY_AURA
&&
1312 spellInfo
->EffectApplyAuraName
[i
] == SPELL_AURA_MOD_SHAPESHIFT
)
1315 case SPELLFAMILY_ROGUE
:
1317 if (spellInfo
->Effect
[i
]==SPELL_EFFECT_APPLY_AURA
&&
1318 spellInfo
->EffectApplyAuraName
[i
] == SPELL_AURA_MOD_SHAPESHIFT
)
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
)
1334 if(spellId_1
== spellId_2
)
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)
1342 // Resurrection sickness
1343 if((spellInfo_1
->Id
== SPELL_ID_PASSIVE_RESURRECTION_SICKNESS
) != (spellInfo_2
->Id
==SPELL_ID_PASSIVE_RESURRECTION_SICKNESS
))
1346 // Allow stack passive and not passive spells
1347 if ((spellInfo_1
->Attributes
& SPELL_ATTR_PASSIVE
)!=(spellInfo_2
->Attributes
& SPELL_ATTR_PASSIVE
))
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
1359 if ((spellInfo_1
->Id
== 21992 && spellInfo_2
->Id
== 27648) ||
1360 (spellInfo_2
->Id
== 21992 && spellInfo_1
->Id
== 27648))
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))
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 ) )
1374 // Heart of the Wild, Agility and various Idol Triggers
1375 if(spellInfo_1
->SpellIconID
== 240 && spellInfo_2
->SpellIconID
== 240)
1378 // Personalized Weather (thunder effect should overwrite rainy aura)
1379 if(spellInfo_1
->SpellIconID
== 2606 && spellInfo_2
->SpellIconID
== 2606)
1382 // Brood Affliction: Bronze
1383 if( (spellInfo_1
->Id
== 23170 && spellInfo_2
->Id
== 23171) ||
1384 (spellInfo_2
->Id
== 23170 && spellInfo_1
->Id
== 23171) )
1387 // Cool Down (See PeriodicAuraTick())
1388 if ((spellInfo_1
->Id
== 52441 && spellInfo_2
->Id
== 52443) ||
1389 (spellInfo_2
->Id
== 52441 && spellInfo_1
->Id
== 52443))
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) )
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) )
1404 case SPELLFAMILY_MAGE
:
1405 // Arcane Intellect and Insight
1406 if( spellInfo_2
->SpellIconID
== 125 && spellInfo_1
->Id
== 18820 )
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)
1415 // Improved Hamstring -> Hamstring (multi-family check)
1416 if( (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x2)) && spellInfo_1
->Id
== 23694 )
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 )
1427 // Dragonmaw Illusion (multi-family check)
1428 if (spellId_1
== 40216 && spellId_2
== 42016 )
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 )
1441 case SPELLFAMILY_HUNTER
:
1443 // Concussive Shot and Imp. Concussive Shot (multi-family check)
1444 if( spellInfo_1
->Id
== 19410 && spellInfo_2
->Id
== 5116 )
1447 // Improved Wing Clip -> Wing Clip (multi-family check)
1448 if( (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x40)) && spellInfo_1
->Id
== 19229 )
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 )
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)
1462 // Blessing of Sanctuary (multi-family check, some from 16 spell icon spells)
1463 if (spellInfo_1
->Id
== 67480 && spellInfo_2
->Id
== 20911)
1469 // Dragonmaw Illusion, Blood Elf Illusion, Human Illusion, Illidari Agent Illusion, Scarlet Crusade Disguise
1470 if(spellInfo_1
->SpellIconID
== 1691 && spellInfo_2
->SpellIconID
== 1691)
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)) )
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) )
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)) )
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)) )
1496 // Detect Invisibility and Mana Shield (multi-family check)
1497 if( spellInfo_2
->Id
== 132 && spellInfo_1
->SpellIconID
== 209 && spellInfo_1
->SpellVisual
[0] == 968 )
1500 // Combustion and Fire Protection Aura (multi-family check)
1501 if( spellInfo_1
->Id
== 11129 && spellInfo_2
->SpellIconID
== 33 && spellInfo_2
->SpellVisual
[0] == 321 )
1504 // Arcane Intellect and Insight
1505 if( spellInfo_1
->SpellIconID
== 125 && spellInfo_2
->Id
== 18820 )
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 )
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 )
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) )
1533 // Metamorphosis, diff effects
1534 if (spellInfo_1
->SpellIconID
== 3314 && spellInfo_2
->SpellIconID
== 3314)
1537 // Detect Invisibility and Mana Shield (multi-family check)
1538 if( spellInfo_1
->Id
== 132 && spellInfo_2
->SpellIconID
== 209 && spellInfo_2
->SpellVisual
[0] == 968 )
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)) )
1549 // Battle Shout and Rampage
1550 if( (spellInfo_1
->SpellIconID
== 456 && spellInfo_2
->SpellIconID
== 2006) ||
1551 (spellInfo_2
->SpellIconID
== 456 && spellInfo_1
->SpellIconID
== 2006) )
1555 // Hamstring -> Improved Hamstring (multi-family check)
1556 if( (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x2)) && spellInfo_2
->Id
== 23694 )
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 )
1563 // Bloodlust and Bloodthirst (multi-family check)
1564 if( spellInfo_2
->Id
== 2825 && spellInfo_1
->SpellIconID
== 38 && spellInfo_1
->SpellVisual
[0] == 0 )
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)))
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)))
1581 if ((spellInfo_1
->Id
== 47585 && spellInfo_2
->Id
== 60069) ||
1582 (spellInfo_2
->Id
== 47585 && spellInfo_1
->Id
== 60069))
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)) )
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))
1599 // Lifebloom and Wild Growth
1600 if (spellInfo_1
->SpellIconID
== 2101 && spellInfo_2
->SpellIconID
== 2864 ||
1601 spellInfo_2
->SpellIconID
== 2101 && spellInfo_1
->SpellIconID
== 2864 )
1604 // Innervate and Glyph of Innervate and some other spells
1605 if (spellInfo_1
->SpellIconID
== 62 && spellInfo_2
->SpellIconID
== 62)
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 )
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 )
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 )
1620 // Survival Instincts and Survival Instincts
1621 if( spellInfo_1
->Id
== 61336 && spellInfo_2
->Id
== 50322 || spellInfo_2
->Id
== 61336 && spellInfo_1
->Id
== 50322 )
1624 // Savage Roar and Savage Roar (triggered)
1625 if (spellInfo_1
->SpellIconID
== 2865 && spellInfo_2
->SpellIconID
== 2865)
1628 // Frenzied Regeneration and Savage Defense
1629 if( spellInfo_1
->Id
== 22842 && spellInfo_2
->Id
== 62606 || spellInfo_2
->Id
== 22842 && spellInfo_1
->Id
== 62606 )
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 )
1637 // Dragonmaw Illusion (multi-family check)
1638 if (spellId_1
== 42016 && spellId_2
== 40216 )
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 )
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))
1657 if( spellInfo_1
->SpellIconID
== 2285 && spellInfo_2
->SpellIconID
== 2285 )
1660 // Garrote -> Garrote-Silence (multi-family check)
1661 if( spellInfo_1
->SpellIconID
== 498 && spellInfo_2
->SpellIconID
== 498 && spellInfo_2
->SpellVisual
[0] == 0 )
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)) )
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)) )
1678 if( spellInfo_1
->SpellIconID
== 1680 && spellInfo_2
->SpellIconID
== 1680 )
1682 // Wing Clip -> Improved Wing Clip (multi-family check)
1683 if( (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x40)) && spellInfo_2
->Id
== 19229 )
1686 // Concussive Shot and Imp. Concussive Shot (multi-family check)
1687 if( spellInfo_2
->Id
== 19410 && spellInfo_1
->Id
== 5116 )
1690 case SPELLFAMILY_PALADIN
:
1691 if( spellInfo_2
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
1694 if (IsSealSpell(spellInfo_1
) && IsSealSpell(spellInfo_2
))
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))
1702 // Beacon of Light and Light's Beacon
1703 if ((spellInfo_1
->SpellIconID
== 3032) && (spellInfo_2
->SpellIconID
== 3032))
1706 // Concentration Aura and Improved Concentration Aura and Aura Mastery
1707 if ((spellInfo_1
->SpellIconID
== 1487) && (spellInfo_2
->SpellIconID
== 1487))
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)
1714 // Divine Sacrifice and Divine Guardian
1715 if (spellInfo_1
->SpellIconID
== 3837 && spellInfo_2
->SpellIconID
== 3837)
1719 // Blessing of Sanctuary (multi-family check, some from 16 spell icon spells)
1720 if (spellInfo_2
->Id
== 67480 && spellInfo_1
->Id
== 20911)
1723 // Combustion and Fire Protection Aura (multi-family check)
1724 if( spellInfo_2
->Id
== 11129 && spellInfo_1
->SpellIconID
== 33 && spellInfo_1
->SpellVisual
[0] == 321 )
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 )
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)
1735 case SPELLFAMILY_SHAMAN
:
1736 if( spellInfo_2
->SpellFamilyName
== SPELLFAMILY_SHAMAN
)
1739 if( spellInfo_1
->SpellIconID
==220 && spellInfo_2
->SpellIconID
==220 &&
1740 spellInfo_1
->SpellFamilyFlags
!= spellInfo_2
->SpellFamilyFlags
)
1744 if (spellInfo_1
->SpellIconID
== 67 && spellInfo_2
->SpellIconID
== 67)
1747 // Totem of Wrath (positive/negative), ranks checked early
1748 if (spellInfo_1
->SpellIconID
== 2019 && spellInfo_2
->SpellIconID
== 2019)
1751 // Bloodlust and Bloodthirst (multi-family check)
1752 if( spellInfo_1
->Id
== 2825 && spellInfo_2
->SpellIconID
== 38 && spellInfo_2
->SpellVisual
[0] == 0 )
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)
1762 // Frost Presence and Frost Presence (triggered)
1763 if (spellInfo_1
->SpellIconID
== 2632 && spellInfo_2
->SpellIconID
== 2632)
1766 // Unholy Presence and Unholy Presence (triggered)
1767 if (spellInfo_1
->SpellIconID
== 2633 && spellInfo_2
->SpellIconID
== 2633)
1770 // Blood Presence and Blood Presence (triggered)
1771 if (spellInfo_1
->SpellIconID
== 2636 && spellInfo_2
->SpellIconID
== 2636)
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
)
1797 if (IsRankSpellDueToSpell(spellInfo_1
, spellId_2
))
1800 if (spellInfo_1
->SpellFamilyName
== 0 || spellInfo_2
->SpellFamilyName
== 0)
1803 if (spellInfo_1
->SpellFamilyName
!= spellInfo_2
->SpellFamilyName
)
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
])
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
)
1825 bool SpellMgr::IsProfessionOrRidingSpell(uint32 spellId
)
1827 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
1831 if (spellInfo
->Effect
[EFFECT_INDEX_1
] != SPELL_EFFECT_SKILL
)
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
);
1845 if (spellInfo
->Effect
[EFFECT_INDEX_1
] != SPELL_EFFECT_SKILL
)
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
);
1859 if (spellInfo
->Effect
[EFFECT_INDEX_1
] != SPELL_EFFECT_SKILL
)
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
)
1882 if (pAbility
->req_skill_value
> 0)
1889 SpellEntry
const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry
const* spellInfo
, uint32 playerLevel
) const
1891 // ignore passive spells
1892 if(IsPassiveSpell(spellInfo
->Id
))
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;
1909 if(!needRankSelection
)
1912 for(uint32 nextSpellId
= spellInfo
->Id
; nextSpellId
!= 0; nextSpellId
= GetPrevSpellInChain(nextSpellId
))
1914 SpellEntry
const *nextSpellInfo
= sSpellStore
.LookupEntry(nextSpellId
);
1918 // if found appropriate level
1919 if(playerLevel
+ 10 >= nextSpellInfo
->spellLevel
)
1920 return nextSpellInfo
;
1922 // one rank less then
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");
1941 sLog
.outString( ">> Loaded 0 spell chain records" );
1942 sLog
.outErrorDb("`spell_chains` table is empty!");
1948 barGoLink
bar( (int)result
->GetRowCount() );
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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);
2034 mSpellChains
[spell_id
] = node
;
2037 mSpellChainsNext
.insert(SpellChainMapNext::value_type(node
.prev
,spell_id
));
2040 mSpellChainsNext
.insert(SpellChainMapNext::value_type(node
.req
,spell_id
));
2043 } while( result
->NextRow() );
2047 // additional integrity checks
2048 for(SpellChainMap::const_iterator i
= mSpellChains
.begin(); i
!= mSpellChains
.end(); ++i
)
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
);
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
);
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
)
2109 SpellEntry
const* entry
= sSpellStore
.LookupEntry(spell
);
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
)
2123 dbc_node
.value
= entry
->CalculateSimpleValue(SpellEffectIndex(i
))*75;
2124 dbc_node
.maxvalue
= entry
->CalculateSimpleValue(SpellEffectIndex(i
))*75;
2126 mSpellLearnSkills
[spell
] = dbc_node
;
2134 sLog
.outString( ">> Loaded %u Spell Learn Skills from DBC", dbc_count
);
2137 void SpellMgr::LoadSpellLearnSpells()
2139 mSpellLearnSpells
.clear(); // need for reload case
2142 QueryResult
*result
= WorldDatabase
.Query("SELECT entry, SpellID, Active FROM spell_learn_spell");
2149 sLog
.outString( ">> Loaded 0 spell learn spells" );
2150 sLog
.outErrorDb("`spell_learn_spell` table is empty!");
2156 barGoLink
bar( (int)result
->GetRowCount() );
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
);
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
);
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
);
2187 mSpellLearnSpells
.insert(SpellLearnSpellMap::value_type(spell_id
,node
));
2190 } while( result
->NextRow() );
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
);
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
))
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
);
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
);
2234 if (!found
) // add new spell-spell pair if not found
2236 mSpellLearnSpells
.insert(SpellLearnSpellMap::value_type(spell
,dbc_node
));
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
2253 QueryResult
*result
= WorldDatabase
.Query("SELECT entry,type,targetEntry FROM spell_script_target");
2262 sLog
.outErrorDb(">> Loaded 0 SpellScriptTarget. DB table `spell_script_target` is empty.");
2266 barGoLink
bar((int)result
->GetRowCount());
2270 Field
*fields
= result
->Fetch();
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
);
2281 sLog
.outErrorDb("Table `spell_script_target`: spellId %u listed for TargetEntry %u does not exist.",spellId
,targetEntry
);
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
)
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
);
2305 if (type
>= MAX_SPELL_TARGET_TYPE
)
2307 sLog
.outErrorDb("Table `spell_script_target`: target type %u for TargetEntry %u is incorrect.",type
,targetEntry
);
2311 // Checks by target type
2314 case SPELL_TARGET_TYPE_GAMEOBJECT
:
2319 if (!sGOStorage
.LookupEntry
<GameObjectInfo
>(targetEntry
))
2321 sLog
.outErrorDb("Table `spell_script_target`: gameobject template entry %u does not exist.",targetEntry
);
2329 sLog
.outErrorDb("Table `spell_script_target`: target entry == 0 for not GO target type (%u).",type
);
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
);
2342 sLog
.outErrorDb("Table `spell_script_target`: creature template entry %u does not exist.",targetEntry
);
2348 mSpellScriptTarget
.insert(SpellScriptTarget::value_type(spellId
,SpellTargetEntry(SpellTargetType(type
),targetEntry
)));
2351 } while (result
->NextRow());
2356 /* Disabled (lot errors at this moment)
2357 for(uint32 i = 1; i < sSpellStore.nCount; ++i)
2359 SpellEntry const * spellInfo = sSpellStore.LookupEntry(i);
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);
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
2381 sLog
.outString(">> Loaded %u Spell Script Targets", count
);
2384 void SpellMgr::LoadSpellPetAuras()
2386 mSpellPetAuraMap
.clear(); // need for reload case
2391 QueryResult
*result
= WorldDatabase
.Query("SELECT spell, effectId, pet, aura FROM spell_pet_auras");
2400 sLog
.outString( ">> Loaded %u spell pet auras", count
);
2404 barGoLink
bar( (int)result
->GetRowCount() );
2408 Field
*fields
= result
->Fetch();
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
);
2423 SpellPetAuraMap::iterator itr
= mSpellPetAuraMap
.find((spell
<<8) + eff
);
2424 if(itr
!= mSpellPetAuraMap
.end())
2426 itr
->second
.AddAura(pet
, aura
);
2430 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(spell
);
2433 sLog
.outErrorDb("Spell %u listed in `spell_pet_auras` does not exist", spell
);
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
);
2445 SpellEntry
const* spellInfo2
= sSpellStore
.LookupEntry(aura
);
2448 sLog
.outErrorDb("Aura %u listed in `spell_pet_auras` does not exist", aura
);
2452 PetAura
pa(pet
, aura
, spellInfo
->EffectImplicitTargetA
[eff
] == TARGET_PET
, spellInfo
->CalculateSimpleValue(eff
));
2453 mSpellPetAuraMap
[(spell
<<8) + eff
] = pa
;
2457 } while( result
->NextRow() );
2462 sLog
.outString( ">> Loaded %u spell pet auras", count
);
2465 void SpellMgr::LoadPetLevelupSpellMap()
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
2476 for (uint32 j
= 0; j
< sSkillLineAbilityStore
.GetNumRows(); ++j
)
2478 SkillLineAbilityEntry
const *skillLine
= sSkillLineAbilityStore
.LookupEntry(j
);
2482 if (skillLine
->skillId
!=creatureFamily
->skillLine
[0] &&
2483 (!creatureFamily
->skillLine
[1] || skillLine
->skillId
!=creatureFamily
->skillLine
[1]))
2486 if(skillLine
->learnOnGetSkill
!= ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
)
2489 SpellEntry
const *spell
= sSpellStore
.LookupEntry(skillLine
->spellId
);
2490 if(!spell
) // not exist
2493 PetLevelupSpellSet
& spellSet
= mPetLevelupSpellMap
[creatureFamily
->ID
];
2494 if(spellSet
.empty())
2497 spellSet
.insert(PetLevelupSpellSet::value_type(spell
->spellLevel
,spell
->Id
));
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
)
2509 bool have_spell
= false;
2510 for(int j
= 0; j
< MAX_CREATURE_SPELL_DATA_SLOT
; ++j
)
2512 if(petDefSpells
.spellid
[j
])
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
])
2529 for(PetLevelupSpellSet::const_iterator itr
= levelupSpells
->begin(); itr
!= levelupSpells
->end(); ++itr
)
2531 if (itr
->second
== petDefSpells
.spellid
[j
])
2533 petDefSpells
.spellid
[j
] = 0;
2542 for(int j
= 0; j
< MAX_CREATURE_SPELL_DATA_SLOT
; ++j
)
2544 if(petDefSpells
.spellid
[j
])
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
);
2569 if(!cInfo
->PetSpellDataId
)
2572 // for creature with PetSpellDataId get default pet spells from dbc
2573 CreatureSpellDataEntry
const* spellDataEntry
= sCreatureSpellDataStore
.LookupEntry(cInfo
->PetSpellDataId
);
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
;
2589 // different summon spells
2590 for(uint32 i
= 0; i
< sSpellStore
.GetNumRows(); ++i
)
2592 SpellEntry
const* spellEntry
= sSpellStore
.LookupEntry(i
);
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
);
2606 if(cInfo
->PetSpellDataId
)
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())
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
;
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
)
2638 bool need_check_reagents
= false;
2641 for(int i
= 0; i
< MAX_EFFECT_INDEX
; ++i
)
2643 switch(spellInfo
->Effect
[i
])
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
))
2660 ChatHandler(pl
).PSendSysMessage("Craft spell %u not have create item entry.",spellInfo
->Id
);
2662 sLog
.outErrorDb("Craft spell %u not have create item entry.",spellInfo
->Id
);
2668 // also possible IsLootCraftingSpell case but fake item must exist anyway
2669 else if (!ObjectMgr::GetItemPrototype( spellInfo
->EffectItemType
[i
] ))
2674 ChatHandler(pl
).PSendSysMessage("Craft spell %u create item (Entry: %u) but item does not exist in item_template.",spellInfo
->Id
,spellInfo
->EffectItemType
[i
]);
2676 sLog
.outErrorDb("Craft spell %u create item (Entry: %u) but item does not exist in item_template.",spellInfo
->Id
,spellInfo
->EffectItemType
[i
]);
2681 need_check_reagents
= true;
2684 case SPELL_EFFECT_LEARN_SPELL
:
2686 SpellEntry
const* spellInfo2
= sSpellStore
.LookupEntry(spellInfo
->EffectTriggerSpell
[i
]);
2687 if( !IsSpellValid(spellInfo2
,pl
,msg
) )
2692 ChatHandler(pl
).PSendSysMessage("Spell %u learn to broken spell %u, and then...",spellInfo
->Id
,spellInfo
->EffectTriggerSpell
[i
]);
2694 sLog
.outErrorDb("Spell %u learn to invalid spell %u, and then...",spellInfo
->Id
,spellInfo
->EffectTriggerSpell
[i
]);
2703 if(need_check_reagents
)
2705 for(int j
= 0; j
< 8; ++j
)
2707 if(spellInfo
->Reagent
[j
] > 0 && !ObjectMgr::GetItemPrototype( spellInfo
->Reagent
[j
] ))
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
]);
2714 sLog
.outErrorDb("Craft spell %u requires reagent item (Entry: %u) but item does not exist in item_template.",spellInfo
->Id
,spellInfo
->Reagent
[j
]);
2724 void SpellMgr::LoadSpellAreas()
2726 mSpellAreaMap
.clear(); // need for reload case
2727 mSpellAreaForQuestMap
.clear();
2728 mSpellAreaForActiveQuestMap
.clear();
2729 mSpellAreaForQuestEndMap
.clear();
2730 mSpellAreaForAuraMap
.clear();
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");
2744 sLog
.outString( ">> Loaded %u spell area requirements", count
);
2748 barGoLink
bar( (int)result
->GetRowCount() );
2752 Field
*fields
= result
->Fetch();
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
);
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
)
2781 if (spellArea
.areaId
!= itr
->second
.areaId
)
2783 if (spellArea
.questStart
!= itr
->second
.questStart
)
2785 if (spellArea
.auraSpell
!= itr
->second
.auraSpell
)
2787 if ((spellArea
.raceMask
& itr
->second
.raceMask
) == 0)
2789 if (spellArea
.gender
!= itr
->second
.gender
)
2792 // duplicate by requirements
2799 sLog
.outErrorDb("Spell %u listed in `spell_area` already listed with similar requirements.", spell
);
2805 if(spellArea
.areaId
&& !GetAreaEntryByAreaID(spellArea
.areaId
))
2807 sLog
.outErrorDb("Spell %u listed in `spell_area` have wrong area (%u) requirement", spell
,spellArea
.areaId
);
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
);
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
);
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
);
2832 if(spellArea
.auraSpell
)
2834 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(abs(spellArea
.auraSpell
));
2837 sLog
.outErrorDb("Spell %u listed in `spell_area` have wrong aura spell (%u) requirement", spell
,abs(spellArea
.auraSpell
));
2841 switch(spellInfo
->EffectApplyAuraName
[EFFECT_INDEX_0
])
2843 case SPELL_AURA_DUMMY
:
2844 case SPELL_AURA_PHASE
:
2845 case SPELL_AURA_GHOST
:
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
));
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
));
2858 // not allow autocast chains by auraSpell field (but allow use as alternative if not present)
2859 if(spellArea
.autocast
&& spellArea
.auraSpell
> 0)
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)
2874 sLog
.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell
,spellArea
.auraSpell
);
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)
2890 sLog
.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell
,spellArea
.auraSpell
);
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
);
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
);
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
));
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
));
2932 } while( result
->NextRow() );
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
)
2943 if (spellInfo
->AreaGroupId
> 0)
2946 AreaGroupEntry
const* groupEntry
= sAreaGroupStore
.LookupEntry(spellInfo
->AreaGroupId
);
2949 for (uint32 i
=0; i
<6; ++i
)
2950 if (groupEntry
->AreaId
[i
] == zone_id
|| groupEntry
->AreaId
[i
] == area_id
)
2952 if (found
|| !groupEntry
->nextGroup
)
2954 // Try search in next group
2955 groupEntry
= sAreaGroupStore
.LookupEntry(groupEntry
->nextGroup
);
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
;
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
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
);
3036 return SPELL_FAILED_INCORRECT_AREA
;
3037 return mapEntry
->IsBattleGround()? SPELL_CAST_OK
: SPELL_FAILED_ONLY_BATTLEGROUNDS
;
3039 case 44521: // Preparation
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
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() );
3076 for (uint32 i
= 0; i
< sSkillLineAbilityStore
.GetNumRows(); ++i
)
3079 SkillLineAbilityEntry
const *SkillInfo
= sSkillLineAbilityStore
.LookupEntry(i
);
3083 mSkillLineAbilityMap
.insert(SkillLineAbilityMap::value_type(SkillInfo
->spellId
,SkillInfo
));
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
);
3106 sLog
.outErrorDb("`%s` table is empty!",table
);
3110 barGoLink
bar( (int)result
->GetRowCount() );
3114 Field
*fields
= result
->Fetch();
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
);
3139 // TODO: spellIcon check need dbc loading
3142 sLog
.outError("Table '%s' for spell %u have wrong SpellIcon value(%u), skipped.",table
,spell
,spellIcon
);
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
);
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
);
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
);
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
);
3172 if (effectIdx
< -1 || effectIdx
>= 3)
3174 sLog
.outError("Table '%s' for spell %u have wrong EffectIdx value(%u), skipped.",table
,spell
,effectIdx
);
3178 // now checks of requirements
3184 SpellEntry
const* spellEntry
= sSpellStore
.LookupEntry(spell
);
3187 sLog
.outError("Spell %u '%s' not exist but used in %s.",spell
,name
.c_str(),code
.c_str());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
3273 for(uint32 spellId
= 1; spellId
< sSpellStore
.GetNumRows(); ++spellId
)
3275 SpellEntry
const* spellEntry
= sSpellStore
.LookupEntry(spellId
);
3279 if(family
>=0 && spellEntry
->SpellFamilyName
!= family
)
3282 if(familyMaskA
!= UI64LIT(0xFFFFFFFFFFFFFFFF) || familyMaskB
!= 0xFFFFFFFF)
3284 if(familyMaskA
== UI64LIT(0x0000000000000000) && familyMaskB
== 0x00000000)
3286 if(spellEntry
->SpellFamilyFlags
!= 0 || spellEntry
->SpellFamilyFlags2
!= 0)
3291 if((spellEntry
->SpellFamilyFlags
& familyMaskA
)==0 && (spellEntry
->SpellFamilyFlags2
& familyMaskB
)==0)
3296 if(spellIcon
>= 0 && spellEntry
->SpellIconID
!= spellIcon
)
3299 if(spellVisual
>= 0 && spellEntry
->SpellVisual
[0] != spellVisual
)
3302 if(category
>= 0 && spellEntry
->Category
!= category
)
3307 if(effectType
>=0 && spellEntry
->Effect
[effectIdx
] != effectType
)
3310 if(auraType
>=0 && spellEntry
->EffectApplyAuraName
[effectIdx
] != auraType
)
3315 if(effectType
>=0 && !IsSpellHaveEffect(spellEntry
,SpellEffects(effectType
)))
3318 if(auraType
>=0 && !IsSpellHaveAura(spellEntry
,AuraType(auraType
)))
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());
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());
3338 } while( result
->NextRow() );
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
;
3356 case SPELLFAMILY_MAGE
:
3358 if (spellproto
->SpellIconID
== 1548)
3359 return DIMINISHING_DISORIENT
;
3361 case SPELLFAMILY_ROGUE
:
3364 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00001000000))
3365 return DIMINISHING_FEAR_CHARM_BLIND
;
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
;
3374 case SPELLFAMILY_HUNTER
:
3376 // Freezing Trap & Freezing Arrow & Wyvern Sting
3377 if (spellproto
->SpellIconID
== 180 || spellproto
->SpellIconID
== 1721)
3378 return DIMINISHING_DISORIENT
;
3381 case SPELLFAMILY_WARLOCK
:
3384 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00080000000))
3385 return DIMINISHING_LIMITONLY
;
3388 case SPELLFAMILY_DRUID
:
3391 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x02000000000))
3392 return DIMINISHING_CYCLONE
;
3394 else if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00000020000))
3395 return DIMINISHING_CHEAPSHOT_POUNCE
;
3397 else if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000400))
3398 return DIMINISHING_LIMITONLY
;
3401 case SPELLFAMILY_WARRIOR
:
3403 // Hamstring - limit duration to 10s in PvP
3404 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000002))
3405 return DIMINISHING_LIMITONLY
;
3408 case SPELLFAMILY_PRIEST
:
3411 if ((spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000004)) && spellproto
->SpellIconID
== 150)
3412 return DIMINISHING_LIMITONLY
;
3414 else if (spellproto
->SpellIconID
== 27)
3415 return DIMINISHING_DISORIENT
;
3418 case SPELLFAMILY_DEATHKNIGHT
:
3420 // Hungering Cold (no flags)
3421 if (spellproto
->SpellIconID
== 2797)
3422 return DIMINISHING_DISORIENT
;
3430 uint32 mechanic
= GetAllSpellMechanicMask(spellproto
);
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
))
3461 // Explicit diminishing duration
3462 switch(spellproto
->SpellFamilyName
)
3464 case SPELLFAMILY_HUNTER
:
3467 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x0000100000000000))
3471 case SPELLFAMILY_PALADIN
:
3473 // Repentance - limit to 6 seconds in PvP
3474 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000004))
3478 case SPELLFAMILY_DRUID
:
3480 // Faerie Fire - limit to 40 seconds in PvP (3.1)
3481 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000400))
3485 case SPELLFAMILY_PRIEST
:
3487 // Vampiric Embrace - limit to 60 seconds in PvP (3.1)
3488 if ((spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000004)) && spellproto
->SpellIconID
== 150)
3499 bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup 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
:
3521 DiminishingReturnsType
GetDiminishingReturnsGroupType(DiminishingGroup group
)
3525 case DIMINISHING_CYCLONE
:
3526 case DIMINISHING_TRIGGER_STUN
:
3527 case DIMINISHING_CONTROL_STUN
:
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
;
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())
3558 // not in expected race
3559 if(!player
|| !(raceMask
& player
->getRaceMask()))
3565 // not in expected zone
3566 if(newZone
!=areaId
&& newArea
!=areaId
)
3572 // not in expected required quest state
3573 if(!player
|| (!questStartCanActive
|| !player
->IsActiveQuest(questStart
)) && !player
->GetQuestRewardStatus(questStart
))
3579 // not in expected forbidden quest state
3580 if(!player
|| player
->GetQuestRewardStatus(questEnd
))
3586 // not have expected aura
3590 // have expected aura
3591 return player
->HasAura(auraSpell
, EFFECT_INDEX_0
);
3593 // not have expected aura
3594 return !player
->HasAura(-auraSpell
, EFFECT_INDEX_0
);