2 * Copyright (C) 2005-2009 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"
37 SpellMgr
& SpellMgr::Instance()
39 static SpellMgr spellMgr
;
43 int32
GetSpellDuration(SpellEntry
const *spellInfo
)
47 SpellDurationEntry
const *du
= sSpellDurationStore
.LookupEntry(spellInfo
->DurationIndex
);
50 return (du
->Duration
[0] == -1) ? -1 : abs(du
->Duration
[0]);
53 int32
GetSpellMaxDuration(SpellEntry
const *spellInfo
)
57 SpellDurationEntry
const *du
= sSpellDurationStore
.LookupEntry(spellInfo
->DurationIndex
);
60 return (du
->Duration
[2] == -1) ? -1 : abs(du
->Duration
[2]);
63 uint32
GetSpellCastTime(SpellEntry
const* spellInfo
, Spell
const* spell
)
65 SpellCastTimesEntry
const *spellCastTimeEntry
= sSpellCastTimesStore
.LookupEntry(spellInfo
->CastingTimeIndex
);
67 // not all spells have cast time index and this is all is pasiive abilities
68 if(!spellCastTimeEntry
)
71 int32 castTime
= spellCastTimeEntry
->CastTime
;
75 if(Player
* modOwner
= spell
->GetCaster()->GetSpellModOwner())
76 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CASTING_TIME
, castTime
, spell
);
78 if( !(spellInfo
->Attributes
& (SPELL_ATTR_UNK4
|SPELL_ATTR_TRADESPELL
)) )
79 castTime
= int32(castTime
* spell
->GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED
));
82 if (spell
->IsRangedSpell() && !spell
->IsAutoRepeat())
83 castTime
= int32(castTime
* spell
->GetCaster()->m_modAttackSpeedPct
[RANGED_ATTACK
]);
87 if (spellInfo
->Attributes
& SPELL_ATTR_RANGED
&& (!spell
|| !(spell
->IsAutoRepeat())))
90 return (castTime
> 0) ? uint32(castTime
) : 0;
93 bool IsPassiveSpell(uint32 spellId
)
95 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
98 return (spellInfo
->Attributes
& SPELL_ATTR_PASSIVE
) != 0;
101 bool IsNoStackAuraDueToAura(uint32 spellId_1
, uint32 effIndex_1
, uint32 spellId_2
, uint32 effIndex_2
)
103 SpellEntry
const *spellInfo_1
= sSpellStore
.LookupEntry(spellId_1
);
104 SpellEntry
const *spellInfo_2
= sSpellStore
.LookupEntry(spellId_2
);
105 if(!spellInfo_1
|| !spellInfo_2
) return false;
106 if(spellInfo_1
->Id
== spellId_2
) return false;
108 if (spellInfo_1
->Effect
[effIndex_1
] != spellInfo_2
->Effect
[effIndex_2
] ||
109 spellInfo_1
->EffectItemType
[effIndex_1
] != spellInfo_2
->EffectItemType
[effIndex_2
] ||
110 spellInfo_1
->EffectMiscValue
[effIndex_1
] != spellInfo_2
->EffectMiscValue
[effIndex_2
] ||
111 spellInfo_1
->EffectApplyAuraName
[effIndex_1
] != spellInfo_2
->EffectApplyAuraName
[effIndex_2
])
117 int32
CompareAuraRanks(uint32 spellId_1
, uint32 effIndex_1
, uint32 spellId_2
, uint32 effIndex_2
)
119 SpellEntry
const*spellInfo_1
= sSpellStore
.LookupEntry(spellId_1
);
120 SpellEntry
const*spellInfo_2
= sSpellStore
.LookupEntry(spellId_2
);
121 if(!spellInfo_1
|| !spellInfo_2
) return 0;
122 if (spellId_1
== spellId_2
) return 0;
124 int32 diff
= spellInfo_1
->EffectBasePoints
[effIndex_1
] - spellInfo_2
->EffectBasePoints
[effIndex_2
];
125 if (spellInfo_1
->CalculateSimpleValue(effIndex_1
) < 0 && spellInfo_2
->CalculateSimpleValue(effIndex_2
) < 0)
130 SpellSpecific
GetSpellSpecific(uint32 spellId
)
132 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
136 switch(spellInfo
->SpellFamilyName
)
138 case SPELLFAMILY_GENERIC
:
140 // Food / Drinks (mostly)
141 if(spellInfo
->AuraInterruptFlags
& AURA_INTERRUPT_FLAG_NOT_SEATED
)
145 for(int i
= 0; i
< 3; ++i
)
147 switch(spellInfo
->EffectApplyAuraName
[i
])
150 case SPELL_AURA_MOD_REGEN
:
151 case SPELL_AURA_OBS_MOD_HEALTH
:
155 case SPELL_AURA_MOD_POWER_REGEN
:
156 case SPELL_AURA_OBS_MOD_MANA
:
165 return SPELL_FOOD_AND_DRINK
;
173 // Well Fed buffs (must be exclusive with Food / Drink replenishment effects, or else Well Fed will cause them to be removed)
174 // SpellIcon 2560 is Spell 46687, does not have this flag
175 if ((spellInfo
->AttributesEx2
& SPELL_ATTR_EX2_FOOD_BUFF
) || spellInfo
->SpellIconID
== 2560)
176 return SPELL_WELL_FED
;
180 case SPELLFAMILY_MAGE
:
182 // family flags 18(Molten), 25(Frost/Ice), 28(Mage)
183 if (spellInfo
->SpellFamilyFlags
& UI64LIT(0x12040000))
184 return SPELL_MAGE_ARMOR
;
186 if ((spellInfo
->SpellFamilyFlags
& UI64LIT(0x1000000)) && spellInfo
->EffectApplyAuraName
[0]==SPELL_AURA_MOD_CONFUSE
)
187 return SPELL_MAGE_POLYMORPH
;
191 case SPELLFAMILY_WARRIOR
:
193 if (spellInfo
->SpellFamilyFlags
& UI64LIT(0x00008000010000))
194 return SPELL_POSITIVE_SHOUT
;
198 case SPELLFAMILY_WARLOCK
:
200 // only warlock curses have this
201 if (spellInfo
->Dispel
== DISPEL_CURSE
)
204 // Warlock (Demon Armor | Demon Skin | Fel Armor)
205 if (spellInfo
->SpellFamilyFlags
& UI64LIT(0x2000002000000000) || spellInfo
->SpellFamilyFlags2
& 0x00000010)
206 return SPELL_WARLOCK_ARMOR
;
210 case SPELLFAMILY_PRIEST
:
212 // "Well Fed" buff from Blessed Sunfruit, Blessed Sunfruit Juice, Alterac Spring Water
213 if ((spellInfo
->Attributes
& SPELL_ATTR_CASTABLE_WHILE_SITTING
) &&
214 (spellInfo
->InterruptFlags
& SPELL_INTERRUPT_FLAG_AUTOATTACK
) &&
215 (spellInfo
->SpellIconID
== 52 || spellInfo
->SpellIconID
== 79))
216 return SPELL_WELL_FED
;
219 case SPELLFAMILY_HUNTER
:
221 // only hunter stings have this
222 if (spellInfo
->Dispel
== DISPEL_POISON
)
225 // only hunter aspects have this (but not all aspects in hunter family)
226 if( spellInfo
->SpellFamilyFlags
& UI64LIT(0x0044000000380000) || spellInfo
->SpellFamilyFlags2
& 0x00001010)
229 if( spellInfo
->SpellFamilyFlags2
& 0x00000002 )
230 return SPELL_TRACKER
;
234 case SPELLFAMILY_PALADIN
:
236 if (IsSealSpell(spellInfo
))
239 if (spellInfo
->SpellFamilyFlags
& UI64LIT(0x0000000011010002))
240 return SPELL_BLESSING
;
242 if (spellInfo
->SpellFamilyFlags
& UI64LIT(0x0000000000002190))
245 if ((spellInfo
->SpellFamilyFlags
& UI64LIT(0x00000820180400)) && (spellInfo
->AttributesEx3
& 0x200))
246 return SPELL_JUDGEMENT
;
248 // only paladin auras have this (for palaldin class family)
249 if( spellInfo
->SpellFamilyFlags2
& 0x00000020 )
254 case SPELLFAMILY_SHAMAN
:
256 if (IsElementalShield(spellInfo
))
257 return SPELL_ELEMENTAL_SHIELD
;
262 case SPELLFAMILY_POTION
:
263 return spellmgr
.GetSpellElixirSpecific(spellInfo
->Id
);
265 case SPELLFAMILY_DEATHKNIGHT
:
266 if (spellInfo
->Category
== 47)
267 return SPELL_PRESENCE
;
271 // elixirs can have different families, but potion most ofc.
272 if(SpellSpecific sp
= spellmgr
.GetSpellElixirSpecific(spellInfo
->Id
))
279 // target not allow have more one spell specific from same caster
280 bool IsSingleFromSpellSpecificPerTargetPerCaster(SpellSpecific spellSpec1
,SpellSpecific spellSpec2
)
288 case SPELL_POSITIVE_SHOUT
:
289 case SPELL_JUDGEMENT
:
291 return spellSpec1
==spellSpec2
;
297 // target not allow have more one ranks from spell from spell specific per target
298 bool IsSingleFromSpellSpecificSpellRanksPerTarget(SpellSpecific spellSpec1
,SpellSpecific spellSpec2
)
306 return spellSpec1
==spellSpec2
;
312 // target not allow have more one spell specific per target from any caster
313 bool IsSingleFromSpellSpecificPerTarget(SpellSpecific spellSpec1
,SpellSpecific spellSpec2
)
320 case SPELL_WARLOCK_ARMOR
:
321 case SPELL_MAGE_ARMOR
:
322 case SPELL_ELEMENTAL_SHIELD
:
323 case SPELL_MAGE_POLYMORPH
:
326 return spellSpec1
==spellSpec2
;
327 case SPELL_BATTLE_ELIXIR
:
328 return spellSpec2
==SPELL_BATTLE_ELIXIR
329 || spellSpec2
==SPELL_FLASK_ELIXIR
;
330 case SPELL_GUARDIAN_ELIXIR
:
331 return spellSpec2
==SPELL_GUARDIAN_ELIXIR
332 || spellSpec2
==SPELL_FLASK_ELIXIR
;
333 case SPELL_FLASK_ELIXIR
:
334 return spellSpec2
==SPELL_BATTLE_ELIXIR
335 || spellSpec2
==SPELL_GUARDIAN_ELIXIR
336 || spellSpec2
==SPELL_FLASK_ELIXIR
;
338 return spellSpec2
==SPELL_FOOD
339 || spellSpec2
==SPELL_FOOD_AND_DRINK
;
341 return spellSpec2
==SPELL_DRINK
342 || spellSpec2
==SPELL_FOOD_AND_DRINK
;
343 case SPELL_FOOD_AND_DRINK
:
344 return spellSpec2
==SPELL_FOOD
345 || spellSpec2
==SPELL_DRINK
346 || spellSpec2
==SPELL_FOOD_AND_DRINK
;
352 bool IsPositiveTarget(uint32 targetA
, uint32 targetB
)
354 // non-positive targets
357 case TARGET_CHAIN_DAMAGE
:
358 case TARGET_ALL_ENEMY_IN_AREA
:
359 case TARGET_ALL_ENEMY_IN_AREA_INSTANT
:
360 case TARGET_IN_FRONT_OF_CASTER
:
361 case TARGET_ALL_ENEMY_IN_AREA_CHANNELED
:
362 case TARGET_CURRENT_ENEMY_COORDINATES
:
363 case TARGET_SINGLE_ENEMY
:
364 case TARGET_IN_FRONT_OF_CASTER_30
:
366 case TARGET_CASTER_COORDINATES
:
367 return (targetB
== TARGET_ALL_PARTY
|| targetB
== TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER
);
372 return IsPositiveTarget(targetB
, 0);
376 bool IsPositiveEffect(uint32 spellId
, uint32 effIndex
)
378 SpellEntry
const *spellproto
= sSpellStore
.LookupEntry(spellId
);
379 if (!spellproto
) return false;
381 switch(spellproto
->Effect
[effIndex
])
383 case SPELL_EFFECT_DUMMY
:
384 // some explicitly required dummy effect sets
387 case 28441: return false; // AB Effect 000
392 // always positive effects (check before target checks that provided non-positive result in some case for positive effects)
393 case SPELL_EFFECT_HEAL
:
394 case SPELL_EFFECT_LEARN_SPELL
:
395 case SPELL_EFFECT_SKILL_STEP
:
396 case SPELL_EFFECT_HEAL_PCT
:
397 case SPELL_EFFECT_ENERGIZE_PCT
:
400 // non-positive aura use
401 case SPELL_EFFECT_APPLY_AURA
:
402 case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
:
404 switch(spellproto
->EffectApplyAuraName
[effIndex
])
406 case SPELL_AURA_DUMMY
:
408 // dummy aura can be positive or negative dependent from casted spell
409 switch(spellproto
->Id
)
411 case 13139: // net-o-matic special effect
412 case 23445: // evil twin
413 case 35679: // Protectorate Demolitionist
414 case 38637: // Nether Exhaustion (red)
415 case 38638: // Nether Exhaustion (green)
416 case 38639: // Nether Exhaustion (blue)
417 case 11196: // Recently Bandaged
419 // some spells have unclear target modes for selection, so just make effect positive
431 case SPELL_AURA_MOD_DAMAGE_DONE
: // dependent from bas point sign (negative -> negative)
432 case SPELL_AURA_MOD_STAT
:
433 case SPELL_AURA_MOD_SKILL
:
434 case SPELL_AURA_MOD_HEALING_PCT
:
435 case SPELL_AURA_MOD_HEALING_DONE
:
436 if(spellproto
->CalculateSimpleValue(effIndex
) < 0)
439 case SPELL_AURA_MOD_DAMAGE_TAKEN
: // dependent from bas point sign (positive -> negative)
440 if(spellproto
->CalculateSimpleValue(effIndex
) > 0)
443 case SPELL_AURA_MOD_SPELL_CRIT_CHANCE
:
444 if(spellproto
->CalculateSimpleValue(effIndex
) > 0)
445 return true; // some expected positive spells have SPELL_ATTR_EX_NEGATIVE
447 case SPELL_AURA_ADD_TARGET_TRIGGER
:
449 case SPELL_AURA_PERIODIC_TRIGGER_SPELL
:
450 if(spellId
!= spellproto
->EffectTriggerSpell
[effIndex
])
452 uint32 spellTriggeredId
= spellproto
->EffectTriggerSpell
[effIndex
];
453 SpellEntry
const *spellTriggeredProto
= sSpellStore
.LookupEntry(spellTriggeredId
);
455 if(spellTriggeredProto
)
457 // non-positive targets of main spell return early
458 for(int i
= 0; i
< 3; ++i
)
460 // if non-positive trigger cast targeted to positive target this main cast is non-positive
461 // this will place this spell auras as debuffs
462 if(IsPositiveTarget(spellTriggeredProto
->EffectImplicitTargetA
[effIndex
],spellTriggeredProto
->EffectImplicitTargetB
[effIndex
]) && !IsPositiveEffect(spellTriggeredId
,i
))
468 case SPELL_AURA_PROC_TRIGGER_SPELL
:
469 // many positive auras have negative triggered spells at damage for example and this not make it negative (it can be canceled for example)
471 case SPELL_AURA_MOD_STUN
: //have positive and negative spells, we can't sort its correctly at this moment.
472 if(effIndex
==0 && spellproto
->Effect
[1]==0 && spellproto
->Effect
[2]==0)
473 return false; // but all single stun aura spells is negative
476 if(spellproto
->Id
== 17624)
479 case SPELL_AURA_MOD_PACIFY_SILENCE
:
480 if(spellproto
->Id
== 24740) // Wisp Costume
483 case SPELL_AURA_MOD_ROOT
:
484 case SPELL_AURA_MOD_SILENCE
:
485 case SPELL_AURA_GHOST
:
486 case SPELL_AURA_PERIODIC_LEECH
:
487 case SPELL_AURA_MOD_STALKED
:
488 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT
:
490 case SPELL_AURA_PERIODIC_DAMAGE
: // used in positive spells also.
491 // part of negative spell if casted at self (prevent cancel)
492 if(spellproto
->EffectImplicitTargetA
[effIndex
] == TARGET_SELF
)
495 case SPELL_AURA_MOD_DECREASE_SPEED
: // used in positive spells also
496 // part of positive spell if casted at self
497 if(spellproto
->EffectImplicitTargetA
[effIndex
] != TARGET_SELF
)
499 // but not this if this first effect (don't found batter check)
500 if(spellproto
->Attributes
& 0x4000000 && effIndex
==0)
503 case SPELL_AURA_TRANSFORM
:
504 // some spells negative
505 switch(spellproto
->Id
)
507 case 36897: // Transporter Malfunction (race mutation to horde)
508 case 36899: // Transporter Malfunction (race mutation to alliance)
512 case SPELL_AURA_MOD_SCALE
:
513 // some spells negative
514 switch(spellproto
->Id
)
516 case 36900: // Soul Split: Evil!
517 case 36901: // Soul Split: Good
518 case 36893: // Transporter Malfunction (decrease size case)
519 case 36895: // Transporter Malfunction (increase size case)
523 case SPELL_AURA_MECHANIC_IMMUNITY
:
525 // non-positive immunities
526 switch(spellproto
->EffectMiscValue
[effIndex
])
528 case MECHANIC_BANDAGE
:
529 case MECHANIC_SHIELD
:
531 case MECHANIC_INVULNERABILITY
:
537 case SPELL_AURA_ADD_FLAT_MODIFIER
: // mods
538 case SPELL_AURA_ADD_PCT_MODIFIER
:
541 switch(spellproto
->EffectMiscValue
[effIndex
])
543 case SPELLMOD_COST
: // dependent from bas point sign (negative -> positive)
544 if(spellproto
->CalculateSimpleValue(effIndex
) > 0)
551 case SPELL_AURA_FORCE_REACTION
:
552 if(spellproto
->Id
==42792) // Recently Dropped Flag (prevent cancel)
564 // non-positive targets
565 if(!IsPositiveTarget(spellproto
->EffectImplicitTargetA
[effIndex
],spellproto
->EffectImplicitTargetB
[effIndex
]))
568 // AttributesEx check
569 if(spellproto
->AttributesEx
& SPELL_ATTR_EX_NEGATIVE
)
576 bool IsPositiveSpell(uint32 spellId
)
578 SpellEntry
const *spellproto
= sSpellStore
.LookupEntry(spellId
);
579 if (!spellproto
) return false;
581 // spells with atleast one negative effect are considered negative
582 // some self-applied spells have negative effects but in self casting case negative check ignored.
583 for (int i
= 0; i
< 3; ++i
)
584 if (!IsPositiveEffect(spellId
, i
))
589 bool IsSingleTargetSpell(SpellEntry
const *spellInfo
)
591 // all other single target spells have if it has AttributesEx5
592 if ( spellInfo
->AttributesEx5
& SPELL_ATTR_EX5_SINGLE_TARGET_SPELL
)
595 // TODO - need found Judgements rule
596 switch(GetSpellSpecific(spellInfo
->Id
))
598 case SPELL_JUDGEMENT
:
604 // single target triggered spell.
605 // Not real client side single target spell, but it' not triggered until prev. aura expired.
606 // This is allow store it in single target spells list for caster for spell proc checking
607 if(spellInfo
->Id
==38324) // Regeneration (triggered by 38299 (HoTs on Heals))
613 bool IsSingleTargetSpells(SpellEntry
const *spellInfo1
, SpellEntry
const *spellInfo2
)
615 // TODO - need better check
616 // Equal icon and spellfamily
617 if( spellInfo1
->SpellFamilyName
== spellInfo2
->SpellFamilyName
&&
618 spellInfo1
->SpellIconID
== spellInfo2
->SpellIconID
)
621 // TODO - need found Judgements rule
622 SpellSpecific spec1
= GetSpellSpecific(spellInfo1
->Id
);
623 // spell with single target specific types
626 case SPELL_JUDGEMENT
:
627 case SPELL_MAGE_POLYMORPH
:
628 if(GetSpellSpecific(spellInfo2
->Id
) == spec1
)
638 SpellCastResult
GetErrorAtShapeshiftedCast (SpellEntry
const *spellInfo
, uint32 form
)
640 // talents that learn spells can have stance requirements that need ignore
641 // (this requirement only for client-side stance show in talent description)
642 if( GetTalentSpellCost(spellInfo
->Id
) > 0 &&
643 (spellInfo
->Effect
[0]==SPELL_EFFECT_LEARN_SPELL
|| spellInfo
->Effect
[1]==SPELL_EFFECT_LEARN_SPELL
|| spellInfo
->Effect
[2]==SPELL_EFFECT_LEARN_SPELL
) )
644 return SPELL_CAST_OK
;
646 uint32 stanceMask
= (form
? 1 << (form
- 1) : 0);
648 if (stanceMask
& spellInfo
->StancesNot
) // can explicitly not be casted in this stance
649 return SPELL_FAILED_NOT_SHAPESHIFT
;
651 if (stanceMask
& spellInfo
->Stances
) // can explicitly be casted in this stance
652 return SPELL_CAST_OK
;
654 bool actAsShifted
= false;
657 SpellShapeshiftEntry
const *shapeInfo
= sSpellShapeshiftStore
.LookupEntry(form
);
660 sLog
.outError("GetErrorAtShapeshiftedCast: unknown shapeshift %u", form
);
661 return SPELL_CAST_OK
;
663 actAsShifted
= !(shapeInfo
->flags1
& 1); // shapeshift acts as normal form for spells
668 if (spellInfo
->Attributes
& SPELL_ATTR_NOT_SHAPESHIFT
) // not while shapeshifted
669 return SPELL_FAILED_NOT_SHAPESHIFT
;
670 else if (spellInfo
->Stances
!= 0) // needs other shapeshift
671 return SPELL_FAILED_ONLY_SHAPESHIFT
;
676 if(!(spellInfo
->AttributesEx2
& SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT
) && spellInfo
->Stances
!= 0)
677 return SPELL_FAILED_ONLY_SHAPESHIFT
;
680 return SPELL_CAST_OK
;
683 void SpellMgr::LoadSpellTargetPositions()
685 mSpellTargetPositions
.clear(); // need for reload case
690 QueryResult
*result
= WorldDatabase
.Query("SELECT id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM spell_target_position");
699 sLog
.outString( ">> Loaded %u spell target coordinates", count
);
703 barGoLink
bar( result
->GetRowCount() );
707 Field
*fields
= result
->Fetch();
711 uint32 Spell_ID
= fields
[0].GetUInt32();
713 SpellTargetPosition st
;
715 st
.target_mapId
= fields
[1].GetUInt32();
716 st
.target_X
= fields
[2].GetFloat();
717 st
.target_Y
= fields
[3].GetFloat();
718 st
.target_Z
= fields
[4].GetFloat();
719 st
.target_Orientation
= fields
[5].GetFloat();
721 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(Spell_ID
);
724 sLog
.outErrorDb("Spell (ID:%u) listed in `spell_target_position` does not exist.",Spell_ID
);
729 for(int i
= 0; i
< 3; ++i
)
731 if( spellInfo
->EffectImplicitTargetA
[i
]==TARGET_TABLE_X_Y_Z_COORDINATES
|| spellInfo
->EffectImplicitTargetB
[i
]==TARGET_TABLE_X_Y_Z_COORDINATES
)
739 sLog
.outErrorDb("Spell (Id: %u) listed in `spell_target_position` does not have target TARGET_TABLE_X_Y_Z_COORDINATES (17).",Spell_ID
);
743 MapEntry
const* mapEntry
= sMapStore
.LookupEntry(st
.target_mapId
);
746 sLog
.outErrorDb("Spell (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Spell_ID
,st
.target_mapId
);
750 if(st
.target_X
==0 && st
.target_Y
==0 && st
.target_Z
==0)
752 sLog
.outErrorDb("Spell (ID:%u) target coordinates not provided.",Spell_ID
);
756 mSpellTargetPositions
[Spell_ID
] = st
;
759 } while( result
->NextRow() );
764 sLog
.outString( ">> Loaded %u spell teleport coordinates", count
);
767 bool SpellMgr::IsAffectedByMod(SpellEntry
const *spellInfo
, SpellModifier
*mod
) const
769 // false for spellInfo == NULL
770 if (!spellInfo
|| !mod
)
773 SpellEntry
const *affect_spell
= sSpellStore
.LookupEntry(mod
->spellId
);
774 // False if affect_spell == NULL or spellFamily not equal
775 if (!affect_spell
|| affect_spell
->SpellFamilyName
!= spellInfo
->SpellFamilyName
)
779 if (mod
->mask
& spellInfo
->SpellFamilyFlags
||
780 mod
->mask2
& spellInfo
->SpellFamilyFlags2
)
786 struct DoSpellProcEvent
788 DoSpellProcEvent(SpellProcEventEntry
const& _spe
) : spe(_spe
) {}
789 void operator() (uint32 spell_id
) { spellmgr
.mSpellProcEventMap
[spell_id
] = spe
; }
790 SpellProcEventEntry
const& spe
;
793 void SpellMgr::LoadSpellProcEvents()
795 mSpellProcEventMap
.clear(); // need for reload case
799 // 0 1 2 3 4 5 6 7 8 9 10
800 QueryResult
*result
= WorldDatabase
.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
806 sLog
.outString( ">> Loaded %u spell proc event conditions", count
);
810 barGoLink
bar( result
->GetRowCount() );
811 uint32 customProc
= 0;
814 Field
*fields
= result
->Fetch();
818 uint32 entry
= fields
[0].GetUInt32();
820 const SpellEntry
*spell
= sSpellStore
.LookupEntry(entry
);
823 sLog
.outErrorDb("Spell %u listed in `spell_proc_event` does not exist", entry
);
827 uint32 first_id
= GetFirstSpellInChain(entry
);
829 if ( first_id
!= entry
)
831 sLog
.outErrorDb("Spell %u listed in `spell_proc_event` is not first rank (%u) in chain", entry
, first_id
);
832 // prevent loading since it won't have an effect anyway
836 SpellProcEventEntry spe
;
838 spe
.schoolMask
= fields
[1].GetUInt32();
839 spe
.spellFamilyName
= fields
[2].GetUInt32();
840 spe
.spellFamilyMask
= (uint64
)fields
[3].GetUInt32()|((uint64
)fields
[4].GetUInt32()<<32);
841 spe
.spellFamilyMask2
= fields
[5].GetUInt32();
842 spe
.procFlags
= fields
[6].GetUInt32();
843 spe
.procEx
= fields
[7].GetUInt32();
844 spe
.ppmRate
= fields
[8].GetFloat();
845 spe
.customChance
= fields
[9].GetFloat();
846 spe
.cooldown
= fields
[10].GetUInt32();
848 mSpellProcEventMap
[entry
] = spe
;
850 // also add to high ranks
851 DoSpellProcEvent
worker(spe
);
852 doForHighRanks(entry
,worker
);
854 if (spell
->procFlags
==0)
856 if (spe
.procFlags
== 0)
858 sLog
.outErrorDb("Spell %u listed in `spell_proc_event` probally not triggered spell", entry
);
864 } while( result
->NextRow() );
870 sLog
.outString( ">> Loaded %u extra spell proc event conditions +%u custom", count
, customProc
);
872 sLog
.outString( ">> Loaded %u extra spell proc event conditions", count
);
875 struct DoSpellProcItemEnchant
877 DoSpellProcItemEnchant(float _ppm
) : ppm(_ppm
) {}
878 void operator() (uint32 spell_id
) { spellmgr
.mSpellProcItemEnchantMap
[spell_id
] = ppm
; }
882 void SpellMgr::LoadSpellProcItemEnchant()
884 mSpellProcItemEnchantMap
.clear(); // need for reload case
889 QueryResult
*result
= WorldDatabase
.Query("SELECT entry, ppmRate FROM spell_proc_item_enchant");
898 sLog
.outString( ">> Loaded %u proc item enchant definitions", count
);
902 barGoLink
bar( result
->GetRowCount() );
906 Field
*fields
= result
->Fetch();
910 uint32 entry
= fields
[0].GetUInt32();
911 float ppmRate
= fields
[1].GetFloat();
913 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(entry
);
917 sLog
.outErrorDb("Spell %u listed in `spell_proc_item_enchant` does not exist", entry
);
921 uint32 first_id
= GetFirstSpellInChain(entry
);
923 if ( first_id
!= entry
)
925 sLog
.outErrorDb("Spell %u listed in `spell_proc_item_enchant` is not first rank (%u) in chain", entry
, first_id
);
926 // prevent loading since it won't have an effect anyway
930 mSpellProcItemEnchantMap
[entry
] = ppmRate
;
932 // also add to high ranks
933 DoSpellProcItemEnchant
worker(ppmRate
);
934 doForHighRanks(entry
,worker
);
937 } while( result
->NextRow() );
942 sLog
.outString( ">> Loaded %u proc item enchant definitions", count
);
945 struct DoSpellBonusess
947 DoSpellBonusess(SpellBonusEntry
const& _spellBonus
) : spellBonus(_spellBonus
) {}
948 void operator() (uint32 spell_id
) { spellmgr
.mSpellBonusMap
[spell_id
] = spellBonus
; }
949 SpellBonusEntry
const& spellBonus
;
952 void SpellMgr::LoadSpellBonusess()
954 mSpellBonusMap
.clear(); // need for reload case
957 QueryResult
*result
= WorldDatabase
.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus FROM spell_bonus_data");
963 sLog
.outString( ">> Loaded %u spell bonus data", count
);
967 barGoLink
bar( result
->GetRowCount() );
970 Field
*fields
= result
->Fetch();
972 uint32 entry
= fields
[0].GetUInt32();
974 SpellEntry
const* spell
= sSpellStore
.LookupEntry(entry
);
977 sLog
.outErrorDb("Spell %u listed in `spell_bonus_data` does not exist", entry
);
981 uint32 first_id
= GetFirstSpellInChain(entry
);
983 if ( first_id
!= entry
)
985 sLog
.outErrorDb("Spell %u listed in `spell_bonus_data` is not first rank (%u) in chain", entry
, first_id
);
986 // prevent loading since it won't have an effect anyway
992 sbe
.direct_damage
= fields
[1].GetFloat();
993 sbe
.dot_damage
= fields
[2].GetFloat();
994 sbe
.ap_bonus
= fields
[3].GetFloat();
996 mSpellBonusMap
[entry
] = sbe
;
998 // also add to high ranks
999 DoSpellBonusess
worker(sbe
);
1000 doForHighRanks(entry
,worker
);
1004 } while( result
->NextRow() );
1009 sLog
.outString( ">> Loaded %u extra spell bonus data", count
);
1012 bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry
const * spellProcEvent
, uint32 EventProcFlag
, SpellEntry
const * procSpell
, uint32 procFlags
, uint32 procExtra
, bool active
)
1014 // No extra req need
1015 uint32 procEvent_procEx
= PROC_EX_NONE
;
1017 // check prockFlags for condition
1018 if((procFlags
& EventProcFlag
) == 0)
1021 // Always trigger for this
1022 if (EventProcFlag
& (PROC_FLAG_KILLED
| PROC_FLAG_KILL
| PROC_FLAG_ON_TRAP_ACTIVATION
))
1025 if (spellProcEvent
) // Exist event data
1028 procEvent_procEx
= spellProcEvent
->procEx
;
1030 // For melee triggers
1031 if (procSpell
== NULL
)
1033 // Check (if set) for school (melee attack have Normal school)
1034 if(spellProcEvent
->schoolMask
&& (spellProcEvent
->schoolMask
& SPELL_SCHOOL_MASK_NORMAL
) == 0)
1037 else // For spells need check school/spell family/family mask
1039 // Check (if set) for school
1040 if(spellProcEvent
->schoolMask
&& (spellProcEvent
->schoolMask
& procSpell
->SchoolMask
) == 0)
1043 // Check (if set) for spellFamilyName
1044 if(spellProcEvent
->spellFamilyName
&& (spellProcEvent
->spellFamilyName
!= procSpell
->SpellFamilyName
))
1047 // spellFamilyName is Ok need check for spellFamilyMask if present
1048 if(spellProcEvent
->spellFamilyMask
|| spellProcEvent
->spellFamilyMask2
)
1050 if ((spellProcEvent
->spellFamilyMask
& procSpell
->SpellFamilyFlags
) == 0 &&
1051 (spellProcEvent
->spellFamilyMask2
& procSpell
->SpellFamilyFlags2
) == 0)
1053 active
= true; // Spell added manualy -> so its active spell
1057 // Check for extra req (if none) and hit/crit
1058 if (procEvent_procEx
== PROC_EX_NONE
)
1060 // No extra req, so can trigger only for active (damage/healing present) and hit/crit
1061 if((procExtra
& (PROC_EX_NORMAL_HIT
|PROC_EX_CRITICAL_HIT
)) && active
)
1064 else // Passive spells hits here only if resist/reflect/immune/evade
1066 // Exist req for PROC_EX_EX_TRIGGER_ALWAYS
1067 if (procEvent_procEx
& PROC_EX_EX_TRIGGER_ALWAYS
)
1069 // Passive spells can`t trigger if need hit
1070 if ((procEvent_procEx
& PROC_EX_NORMAL_HIT
) && !active
)
1072 // Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other)
1073 if (procEvent_procEx
& procExtra
)
1079 void SpellMgr::LoadSpellElixirs()
1081 mSpellElixirs
.clear(); // need for reload case
1086 QueryResult
*result
= WorldDatabase
.Query("SELECT entry, mask FROM spell_elixir");
1095 sLog
.outString( ">> Loaded %u spell elixir definitions", count
);
1099 barGoLink
bar( result
->GetRowCount() );
1103 Field
*fields
= result
->Fetch();
1107 uint32 entry
= fields
[0].GetUInt32();
1108 uint8 mask
= fields
[1].GetUInt8();
1110 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(entry
);
1114 sLog
.outErrorDb("Spell %u listed in `spell_elixir` does not exist", entry
);
1118 mSpellElixirs
[entry
] = mask
;
1121 } while( result
->NextRow() );
1126 sLog
.outString( ">> Loaded %u spell elixir definitions", count
);
1129 void SpellMgr::LoadSpellThreats()
1131 mSpellThreatMap
.clear(); // need for reload case
1136 QueryResult
*result
= WorldDatabase
.Query("SELECT entry, Threat FROM spell_threat");
1145 sLog
.outString( ">> Loaded %u aggro generating spells", count
);
1149 barGoLink
bar( result
->GetRowCount() );
1153 Field
*fields
= result
->Fetch();
1157 uint32 entry
= fields
[0].GetUInt32();
1158 uint16 Threat
= fields
[1].GetUInt16();
1160 if (!sSpellStore
.LookupEntry(entry
))
1162 sLog
.outErrorDb("Spell %u listed in `spell_threat` does not exist", entry
);
1166 mSpellThreatMap
[entry
] = Threat
;
1169 } while( result
->NextRow() );
1174 sLog
.outString( ">> Loaded %u aggro generating spells", count
);
1177 bool SpellMgr::IsRankSpellDueToSpell(SpellEntry
const *spellInfo_1
,uint32 spellId_2
) const
1179 SpellEntry
const *spellInfo_2
= sSpellStore
.LookupEntry(spellId_2
);
1180 if(!spellInfo_1
|| !spellInfo_2
) return false;
1181 if(spellInfo_1
->Id
== spellId_2
) return false;
1183 return GetFirstSpellInChain(spellInfo_1
->Id
)==GetFirstSpellInChain(spellId_2
);
1186 bool SpellMgr::canStackSpellRanks(SpellEntry
const *spellInfo
)
1188 if(IsPassiveSpell(spellInfo
->Id
)) // ranked passive spell
1190 if(spellInfo
->powerType
!= POWER_MANA
&& spellInfo
->powerType
!= POWER_HEALTH
)
1192 if(IsProfessionOrRidingSpell(spellInfo
->Id
))
1195 if(spellmgr
.IsSkillBonusSpell(spellInfo
->Id
))
1198 // All stance spells. if any better way, change it.
1199 for (int i
= 0; i
< 3; ++i
)
1201 switch(spellInfo
->SpellFamilyName
)
1203 case SPELLFAMILY_PALADIN
:
1204 // Paladin aura Spell
1205 if (spellInfo
->Effect
[i
]==SPELL_EFFECT_APPLY_AREA_AURA_RAID
)
1208 case SPELLFAMILY_DRUID
:
1210 if (spellInfo
->Effect
[i
]==SPELL_EFFECT_APPLY_AURA
&&
1211 spellInfo
->EffectApplyAuraName
[i
] == SPELL_AURA_MOD_SHAPESHIFT
)
1214 case SPELLFAMILY_ROGUE
:
1216 if (spellInfo
->Effect
[i
]==SPELL_EFFECT_APPLY_AURA
&&
1217 spellInfo
->EffectApplyAuraName
[i
] == SPELL_AURA_MOD_SHAPESHIFT
)
1224 bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1
, uint32 spellId_2
) const
1226 SpellEntry
const *spellInfo_1
= sSpellStore
.LookupEntry(spellId_1
);
1227 SpellEntry
const *spellInfo_2
= sSpellStore
.LookupEntry(spellId_2
);
1229 if(!spellInfo_1
|| !spellInfo_2
)
1232 if(spellId_1
== spellId_2
)
1235 //I think we don't check this correctly because i need a exception for spell:
1236 //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.
1237 if(spellInfo_2
->SpellFamilyFlags
== 2048)
1240 // Resurrection sickness
1241 if((spellInfo_1
->Id
== SPELL_ID_PASSIVE_RESURRECTION_SICKNESS
) != (spellInfo_2
->Id
==SPELL_ID_PASSIVE_RESURRECTION_SICKNESS
))
1244 // Allow stack passive and not passive spells
1245 if ((spellInfo_1
->Attributes
& SPELL_ATTR_PASSIVE
)!=(spellInfo_2
->Attributes
& SPELL_ATTR_PASSIVE
))
1248 // Specific spell family spells
1249 switch(spellInfo_1
->SpellFamilyName
)
1251 case SPELLFAMILY_GENERIC
:
1252 switch(spellInfo_2
->SpellFamilyName
)
1254 case SPELLFAMILY_GENERIC
: // same family case
1257 if ((spellInfo_1
->Id
== 21992 && spellInfo_2
->Id
== 27648) ||
1258 (spellInfo_2
->Id
== 21992 && spellInfo_1
->Id
== 27648))
1261 // Lightning Speed (Mongoose) and Fury of the Crashing Waves (Tsunami Talisman)
1262 if ((spellInfo_1
->Id
== 28093 && spellInfo_2
->Id
== 42084) ||
1263 (spellInfo_2
->Id
== 28093 && spellInfo_1
->Id
== 42084))
1266 // Soulstone Resurrection and Twisting Nether (resurrector)
1267 if( spellInfo_1
->SpellIconID
== 92 && spellInfo_2
->SpellIconID
== 92 && (
1268 spellInfo_1
->SpellVisual
[0] == 99 && spellInfo_2
->SpellVisual
[0] == 0 ||
1269 spellInfo_2
->SpellVisual
[0] == 99 && spellInfo_1
->SpellVisual
[0] == 0 ) )
1272 // Heart of the Wild and (Primal Instinct (Idol of Terror) triggering spell or Agility)
1273 if( spellInfo_1
->SpellIconID
== 240 && spellInfo_2
->SpellIconID
== 240 && (
1274 spellInfo_1
->SpellVisual
[0] == 0 && spellInfo_2
->SpellVisual
[0] == 78 ||
1275 spellInfo_2
->SpellVisual
[0] == 0 && spellInfo_1
->SpellVisual
[0] == 78 ) )
1278 // Personalized Weather (thunder effect should overwrite rainy aura)
1279 if(spellInfo_1
->SpellIconID
== 2606 && spellInfo_2
->SpellIconID
== 2606)
1282 // Brood Affliction: Bronze
1283 if( (spellInfo_1
->Id
== 23170 && spellInfo_2
->Id
== 23171) ||
1284 (spellInfo_2
->Id
== 23170 && spellInfo_1
->Id
== 23171) )
1287 // See Chapel Invisibility and See Noth Invisibility
1288 if( (spellInfo_1
->Id
== 52950 && spellInfo_2
->Id
== 52707) ||
1289 (spellInfo_2
->Id
== 52950 && spellInfo_1
->Id
== 52707) )
1292 // Regular and Night Elf Ghost
1293 if( (spellInfo_1
->Id
== 8326 && spellInfo_2
->Id
== 20584) ||
1294 (spellInfo_2
->Id
== 8326 && spellInfo_1
->Id
== 20584) )
1299 case SPELLFAMILY_MAGE
:
1300 // Arcane Intellect and Insight
1301 if( spellInfo_2
->SpellIconID
== 125 && spellInfo_1
->Id
== 18820 )
1304 case SPELLFAMILY_WARRIOR
:
1306 // Scroll of Protection and Defensive Stance (multi-family check)
1307 if( spellInfo_1
->SpellIconID
== 276 && spellInfo_1
->SpellVisual
[0] == 196 && spellInfo_2
->Id
== 71)
1310 // Improved Hamstring -> Hamstring (multi-family check)
1311 if( (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x2)) && spellInfo_1
->Id
== 23694 )
1316 case SPELLFAMILY_DRUID
:
1318 // Scroll of Stamina and Leader of the Pack (multi-family check)
1319 if( spellInfo_1
->SpellIconID
== 312 && spellInfo_1
->SpellVisual
[0] == 216 && spellInfo_2
->Id
== 24932 )
1322 // Dragonmaw Illusion (multi-family check)
1323 if (spellId_1
== 40216 && spellId_2
== 42016 )
1328 case SPELLFAMILY_ROGUE
:
1330 // Garrote-Silence -> Garrote (multi-family check)
1331 if( spellInfo_1
->SpellIconID
== 498 && spellInfo_1
->SpellVisual
[0] == 0 && spellInfo_2
->SpellIconID
== 498 )
1336 case SPELLFAMILY_HUNTER
:
1338 // Concussive Shot and Imp. Concussive Shot (multi-family check)
1339 if( spellInfo_1
->Id
== 19410 && spellInfo_2
->Id
== 5116 )
1342 // Improved Wing Clip -> Wing Clip (multi-family check)
1343 if( (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x40)) && spellInfo_1
->Id
== 19229 )
1347 case SPELLFAMILY_PALADIN
:
1349 // Unstable Currents and other -> *Sanctity Aura (multi-family check)
1350 if( spellInfo_2
->SpellIconID
==502 && spellInfo_1
->SpellIconID
==502 && spellInfo_1
->SpellVisual
[0]==969 )
1353 // *Band of Eternal Champion and Seal of Command(multi-family check)
1354 if( spellId_1
== 35081 && spellInfo_2
->SpellIconID
==561 && spellInfo_2
->SpellVisual
[0]==7992)
1360 // Dragonmaw Illusion, Blood Elf Illusion, Human Illusion, Illidari Agent Illusion, Scarlet Crusade Disguise
1361 if(spellInfo_1
->SpellIconID
== 1691 && spellInfo_2
->SpellIconID
== 1691)
1364 case SPELLFAMILY_MAGE
:
1365 if( spellInfo_2
->SpellFamilyName
== SPELLFAMILY_MAGE
)
1367 // Blizzard & Chilled (and some other stacked with blizzard spells
1368 if( (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x80)) && (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x100000)) ||
1369 (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x80)) && (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x100000)) )
1372 // Blink & Improved Blink
1373 if( (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x0000000000010000)) && (spellInfo_2
->SpellVisual
[0] == 72 && spellInfo_2
->SpellIconID
== 1499) ||
1374 (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x0000000000010000)) && (spellInfo_1
->SpellVisual
[0] == 72 && spellInfo_1
->SpellIconID
== 1499) )
1377 // Detect Invisibility and Mana Shield (multi-family check)
1378 if( spellInfo_2
->Id
== 132 && spellInfo_1
->SpellIconID
== 209 && spellInfo_1
->SpellVisual
[0] == 968 )
1381 // Combustion and Fire Protection Aura (multi-family check)
1382 if( spellInfo_1
->Id
== 11129 && spellInfo_2
->SpellIconID
== 33 && spellInfo_2
->SpellVisual
[0] == 321 )
1385 // Arcane Intellect and Insight
1386 if( spellInfo_1
->SpellIconID
== 125 && spellInfo_2
->Id
== 18820 )
1390 case SPELLFAMILY_WARLOCK
:
1391 if( spellInfo_2
->SpellFamilyName
== SPELLFAMILY_WARLOCK
)
1393 // Siphon Life and Drain Life
1394 if( spellInfo_1
->SpellIconID
== 152 && spellInfo_2
->SpellIconID
== 546 ||
1395 spellInfo_2
->SpellIconID
== 152 && spellInfo_1
->SpellIconID
== 546 )
1398 //Corruption & Seed of corruption
1399 if( spellInfo_1
->SpellIconID
== 313 && spellInfo_2
->SpellIconID
== 1932 ||
1400 spellInfo_2
->SpellIconID
== 313 && spellInfo_1
->SpellIconID
== 1932 )
1401 if(spellInfo_1
->SpellVisual
[0] != 0 && spellInfo_2
->SpellVisual
[0] != 0)
1402 return true; // can't be stacked
1404 // Corruption and Unstable Affliction
1405 if( spellInfo_1
->SpellIconID
== 313 && spellInfo_2
->SpellIconID
== 2039 ||
1406 spellInfo_2
->SpellIconID
== 313 && spellInfo_1
->SpellIconID
== 2039 )
1409 // (Corruption or Unstable Affliction) and (Curse of Agony or Curse of Doom)
1410 if( (spellInfo_1
->SpellIconID
== 313 || spellInfo_1
->SpellIconID
== 2039) && (spellInfo_2
->SpellIconID
== 544 || spellInfo_2
->SpellIconID
== 91) ||
1411 (spellInfo_2
->SpellIconID
== 313 || spellInfo_2
->SpellIconID
== 2039) && (spellInfo_1
->SpellIconID
== 544 || spellInfo_1
->SpellIconID
== 91) )
1414 // Metamorphosis, diff effects
1415 if (spellInfo_1
->SpellIconID
== 3314 && spellInfo_2
->SpellIconID
== 3314)
1418 // Detect Invisibility and Mana Shield (multi-family check)
1419 if( spellInfo_1
->Id
== 132 && spellInfo_2
->SpellIconID
== 209 && spellInfo_2
->SpellVisual
[0] == 968 )
1422 case SPELLFAMILY_WARRIOR
:
1423 if( spellInfo_2
->SpellFamilyName
== SPELLFAMILY_WARRIOR
)
1425 // Rend and Deep Wound
1426 if( (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x20)) && (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x1000000000)) ||
1427 (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x20)) && (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x1000000000)) )
1430 // Battle Shout and Rampage
1431 if( (spellInfo_1
->SpellIconID
== 456 && spellInfo_2
->SpellIconID
== 2006) ||
1432 (spellInfo_2
->SpellIconID
== 456 && spellInfo_1
->SpellIconID
== 2006) )
1436 // Hamstring -> Improved Hamstring (multi-family check)
1437 if( (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x2)) && spellInfo_2
->Id
== 23694 )
1440 // Defensive Stance and Scroll of Protection (multi-family check)
1441 if( spellInfo_1
->Id
== 71 && spellInfo_2
->SpellIconID
== 276 && spellInfo_2
->SpellVisual
[0] == 196 )
1444 // Bloodlust and Bloodthirst (multi-family check)
1445 if( spellInfo_2
->Id
== 2825 && spellInfo_1
->SpellIconID
== 38 && spellInfo_1
->SpellVisual
[0] == 0 )
1449 case SPELLFAMILY_PRIEST
:
1450 if( spellInfo_2
->SpellFamilyName
== SPELLFAMILY_PRIEST
)
1452 //Devouring Plague and Shadow Vulnerability
1453 if ((spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x2000000)) && (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x800000000)) ||
1454 (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x2000000)) && (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x800000000)))
1457 //StarShards and Shadow Word: Pain
1458 if ((spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x200000)) && (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x8000)) ||
1459 (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x200000)) && (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x8000)))
1462 if ((spellInfo_1
->Id
== 47585 && spellInfo_2
->Id
== 60069) ||
1463 (spellInfo_2
->Id
== 47585 && spellInfo_1
->Id
== 60069))
1467 case SPELLFAMILY_DRUID
:
1468 if( spellInfo_2
->SpellFamilyName
== SPELLFAMILY_DRUID
)
1470 //Omen of Clarity and Blood Frenzy
1471 if( (spellInfo_1
->SpellFamilyFlags
== UI64LIT(0x0) && spellInfo_1
->SpellIconID
== 108) && (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x20000000000000)) ||
1472 (spellInfo_2
->SpellFamilyFlags
== UI64LIT(0x0) && spellInfo_2
->SpellIconID
== 108) && (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x20000000000000)) )
1475 // Tree of Life (Shapeshift) and 34123 Tree of Life (Passive)
1476 if ((spellId_1
== 33891 && spellId_2
== 34123) ||
1477 (spellId_2
== 33891 && spellId_1
== 34123))
1480 // Wrath of Elune and Nature's Grace
1481 if( spellInfo_1
->Id
== 16886 && spellInfo_2
->Id
== 46833 || spellInfo_2
->Id
== 16886 && spellInfo_1
->Id
== 46833 )
1484 // Bear Rage (Feral T4 (2)) and Omen of Clarity
1485 if( spellInfo_1
->Id
== 16864 && spellInfo_2
->Id
== 37306 || spellInfo_2
->Id
== 16864 && spellInfo_1
->Id
== 37306 )
1488 // Cat Energy (Feral T4 (2)) and Omen of Clarity
1489 if( spellInfo_1
->Id
== 16864 && spellInfo_2
->Id
== 37311 || spellInfo_2
->Id
== 16864 && spellInfo_1
->Id
== 37311 )
1492 // Survival Instincts and Survival Instincts
1493 if( spellInfo_1
->Id
== 61336 && spellInfo_2
->Id
== 50322 || spellInfo_2
->Id
== 61336 && spellInfo_1
->Id
== 50322 )
1496 // Savage Roar and Savage Roar (triggered)
1497 if (spellInfo_1
->SpellIconID
== 2865 && spellInfo_2
->SpellIconID
== 2865)
1501 // Leader of the Pack and Scroll of Stamina (multi-family check)
1502 if( spellInfo_1
->Id
== 24932 && spellInfo_2
->SpellIconID
== 312 && spellInfo_2
->SpellVisual
[0] == 216 )
1505 // Dragonmaw Illusion (multi-family check)
1506 if (spellId_1
== 42016 && spellId_2
== 40216 )
1510 case SPELLFAMILY_ROGUE
:
1511 if( spellInfo_2
->SpellFamilyName
== SPELLFAMILY_ROGUE
)
1513 // Master of Subtlety
1514 if (spellId_1
== 31665 && spellId_2
== 31666 || spellId_1
== 31666 && spellId_2
== 31665 )
1517 // Sprint & Sprint (waterwalk)
1518 if( spellInfo_1
->SpellIconID
== 516 && spellInfo_2
->SpellIconID
== 516 &&
1519 (spellInfo_1
->Category
== 44 && spellInfo_2
->Category
== 0 ||
1520 spellInfo_2
->Category
== 44 && spellInfo_1
->Category
== 0))
1525 if( spellInfo_1
->SpellIconID
== 2285 && spellInfo_2
->SpellIconID
== 2285 )
1528 // Garrote -> Garrote-Silence (multi-family check)
1529 if( spellInfo_1
->SpellIconID
== 498 && spellInfo_2
->SpellIconID
== 498 && spellInfo_2
->SpellVisual
[0] == 0 )
1532 case SPELLFAMILY_HUNTER
:
1533 if( spellInfo_2
->SpellFamilyName
== SPELLFAMILY_HUNTER
)
1535 // Rapid Fire & Quick Shots
1536 if( (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x20)) && (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x20000000000)) ||
1537 (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x20)) && (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x20000000000)) )
1540 // Serpent Sting & (Immolation/Explosive Trap Effect)
1541 if( (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x4)) && (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x00000004000)) ||
1542 (spellInfo_2
->SpellFamilyFlags
& UI64LIT(0x4)) && (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x00000004000)) )
1546 if( spellInfo_1
->SpellIconID
== 1680 && spellInfo_2
->SpellIconID
== 1680 )
1550 // Wing Clip -> Improved Wing Clip (multi-family check)
1551 if( (spellInfo_1
->SpellFamilyFlags
& UI64LIT(0x40)) && spellInfo_2
->Id
== 19229 )
1554 // Concussive Shot and Imp. Concussive Shot (multi-family check)
1555 if( spellInfo_2
->Id
== 19410 && spellInfo_1
->Id
== 5116 )
1558 case SPELLFAMILY_PALADIN
:
1559 if( spellInfo_2
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
1562 if (IsSealSpell(spellInfo_1
) && IsSealSpell(spellInfo_2
))
1565 // Swift Retribution / Improved Devotion Aura (talents) and Paladin Auras
1566 if ((spellInfo_1
->SpellFamilyFlags2
& 0x00000020) && (spellInfo_2
->SpellIconID
== 291 || spellInfo_2
->SpellIconID
== 3028) ||
1567 (spellInfo_2
->SpellFamilyFlags2
& 0x00000020) && (spellInfo_1
->SpellIconID
== 291 || spellInfo_1
->SpellIconID
== 3028))
1571 // Combustion and Fire Protection Aura (multi-family check)
1572 if( spellInfo_2
->Id
== 11129 && spellInfo_1
->SpellIconID
== 33 && spellInfo_1
->SpellVisual
[0] == 321 )
1575 // *Sanctity Aura -> Unstable Currents and other (multi-family check)
1576 if( spellInfo_1
->SpellIconID
==502 && spellInfo_2
->SpellFamilyName
== SPELLFAMILY_GENERIC
&& spellInfo_2
->SpellIconID
==502 && spellInfo_2
->SpellVisual
[0]==969 )
1579 // *Seal of Command and Band of Eternal Champion (multi-family check)
1580 if( spellInfo_1
->SpellIconID
==561 && spellInfo_1
->SpellVisual
[0]==7992 && spellId_2
== 35081)
1583 case SPELLFAMILY_SHAMAN
:
1584 if( spellInfo_2
->SpellFamilyName
== SPELLFAMILY_SHAMAN
)
1587 if( spellInfo_1
->SpellIconID
==220 && spellInfo_2
->SpellIconID
==220 &&
1588 spellInfo_1
->SpellFamilyFlags
!= spellInfo_2
->SpellFamilyFlags
)
1591 // Bloodlust and Bloodthirst (multi-family check)
1592 if( spellInfo_1
->Id
== 2825 && spellInfo_2
->SpellIconID
== 38 && spellInfo_2
->SpellVisual
[0] == 0 )
1595 case SPELLFAMILY_DEATHKNIGHT
:
1596 if (spellInfo_2
->SpellFamilyName
== SPELLFAMILY_DEATHKNIGHT
)
1598 // Frost Presence and Frost Presence (triggered)
1599 if( spellInfo_1
->SpellIconID
== 2632 && spellInfo_2
->SpellIconID
== 2632 )
1602 // Unholy Presence and Unholy Presence (triggered)
1603 if( spellInfo_1
->SpellIconID
== 2633 && spellInfo_2
->SpellIconID
== 2633 )
1611 // more generic checks
1612 if (spellInfo_1
->SpellIconID
== spellInfo_2
->SpellIconID
&&
1613 spellInfo_1
->SpellIconID
!= 0 && spellInfo_2
->SpellIconID
!= 0)
1615 bool isModifier
= false;
1616 for (int i
= 0; i
< 3; ++i
)
1618 if (spellInfo_1
->EffectApplyAuraName
[i
] == SPELL_AURA_ADD_FLAT_MODIFIER
||
1619 spellInfo_1
->EffectApplyAuraName
[i
] == SPELL_AURA_ADD_PCT_MODIFIER
||
1620 spellInfo_2
->EffectApplyAuraName
[i
] == SPELL_AURA_ADD_FLAT_MODIFIER
||
1621 spellInfo_2
->EffectApplyAuraName
[i
] == SPELL_AURA_ADD_PCT_MODIFIER
)
1629 if (IsRankSpellDueToSpell(spellInfo_1
, spellId_2
))
1632 if (spellInfo_1
->SpellFamilyName
== 0 || spellInfo_2
->SpellFamilyName
== 0)
1635 if (spellInfo_1
->SpellFamilyName
!= spellInfo_2
->SpellFamilyName
)
1638 for (int i
= 0; i
< 3; ++i
)
1639 if (spellInfo_1
->Effect
[i
] != spellInfo_2
->Effect
[i
] ||
1640 spellInfo_1
->EffectItemType
[i
] != spellInfo_2
->EffectItemType
[i
] ||
1641 spellInfo_1
->EffectMiscValue
[i
] != spellInfo_2
->EffectMiscValue
[i
] ||
1642 spellInfo_1
->EffectApplyAuraName
[i
] != spellInfo_2
->EffectApplyAuraName
[i
])
1648 bool SpellMgr::IsProfessionOrRidingSpell(uint32 spellId
)
1650 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
1654 if(spellInfo
->Effect
[1] != SPELL_EFFECT_SKILL
)
1657 uint32 skill
= spellInfo
->EffectMiscValue
[1];
1659 return IsProfessionOrRidingSkill(skill
);
1662 bool SpellMgr::IsProfessionSpell(uint32 spellId
)
1664 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
1668 if(spellInfo
->Effect
[1] != SPELL_EFFECT_SKILL
)
1671 uint32 skill
= spellInfo
->EffectMiscValue
[1];
1673 return IsProfessionSkill(skill
);
1676 bool SpellMgr::IsPrimaryProfessionSpell(uint32 spellId
)
1678 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
1682 if(spellInfo
->Effect
[1] != SPELL_EFFECT_SKILL
)
1685 uint32 skill
= spellInfo
->EffectMiscValue
[1];
1687 return IsPrimaryProfessionSkill(skill
);
1690 bool SpellMgr::IsPrimaryProfessionFirstRankSpell(uint32 spellId
) const
1692 return IsPrimaryProfessionSpell(spellId
) && GetSpellRank(spellId
)==1;
1695 bool SpellMgr::IsSkillBonusSpell(uint32 spellId
) const
1697 SkillLineAbilityMapBounds bounds
= GetSkillLineAbilityMapBounds(spellId
);
1699 for(SkillLineAbilityMap::const_iterator _spell_idx
= bounds
.first
; _spell_idx
!= bounds
.second
; ++_spell_idx
)
1701 SkillLineAbilityEntry
const *pAbility
= _spell_idx
->second
;
1702 if (!pAbility
|| pAbility
->learnOnGetSkill
!= ABILITY_LEARNED_ON_GET_PROFESSION_SKILL
)
1705 if (pAbility
->req_skill_value
> 0)
1712 SpellEntry
const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry
const* spellInfo
, uint32 playerLevel
) const
1714 // ignore passive spells
1715 if(IsPassiveSpell(spellInfo
->Id
))
1718 bool needRankSelection
= false;
1719 for(int i
=0;i
<3;++i
)
1721 if( IsPositiveEffect(spellInfo
->Id
, i
) && (
1722 spellInfo
->Effect
[i
] == SPELL_EFFECT_APPLY_AURA
||
1723 spellInfo
->Effect
[i
] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY
||
1724 spellInfo
->Effect
[i
] == SPELL_EFFECT_APPLY_AREA_AURA_RAID
1727 needRankSelection
= true;
1733 if(!needRankSelection
)
1736 for(uint32 nextSpellId
= spellInfo
->Id
; nextSpellId
!= 0; nextSpellId
= GetPrevSpellInChain(nextSpellId
))
1738 SpellEntry
const *nextSpellInfo
= sSpellStore
.LookupEntry(nextSpellId
);
1742 // if found appropriate level
1743 if(playerLevel
+ 10 >= nextSpellInfo
->spellLevel
)
1744 return nextSpellInfo
;
1746 // one rank less then
1753 void SpellMgr::LoadSpellChains()
1755 mSpellChains
.clear(); // need for reload case
1756 mSpellChainsNext
.clear(); // need for reload case
1758 QueryResult
*result
= WorldDatabase
.Query("SELECT spell_id, prev_spell, first_spell, rank, req_spell FROM spell_chain");
1765 sLog
.outString( ">> Loaded 0 spell chain records" );
1766 sLog
.outErrorDb("`spell_chains` table is empty!");
1772 barGoLink
bar( result
->GetRowCount() );
1776 Field
*fields
= result
->Fetch();
1778 uint32 spell_id
= fields
[0].GetUInt32();
1780 SpellChainNode node
;
1781 node
.prev
= fields
[1].GetUInt32();
1782 node
.first
= fields
[2].GetUInt32();
1783 node
.rank
= fields
[3].GetUInt8();
1784 node
.req
= fields
[4].GetUInt32();
1786 if(!sSpellStore
.LookupEntry(spell_id
))
1788 sLog
.outErrorDb("Spell %u listed in `spell_chain` does not exist",spell_id
);
1792 if(node
.prev
!=0 && !sSpellStore
.LookupEntry(node
.prev
))
1794 sLog
.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not existed previous rank spell.",
1795 spell_id
,node
.prev
,node
.first
,node
.rank
,node
.req
);
1799 if(!sSpellStore
.LookupEntry(node
.first
))
1801 sLog
.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not existing first rank spell.",
1802 spell_id
,node
.prev
,node
.first
,node
.rank
,node
.req
);
1806 // check basic spell chain data integrity (note: rank can be equal 0 or 1 for first/single spell)
1807 if( (spell_id
== node
.first
) != (node
.rank
<= 1) ||
1808 (spell_id
== node
.first
) != (node
.prev
== 0) ||
1809 (node
.rank
<= 1) != (node
.prev
== 0) )
1811 sLog
.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not compatible chain data.",
1812 spell_id
,node
.prev
,node
.first
,node
.rank
,node
.req
);
1816 if(node
.req
!=0 && !sSpellStore
.LookupEntry(node
.req
))
1818 sLog
.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not existing required spell.",
1819 spell_id
,node
.prev
,node
.first
,node
.rank
,node
.req
);
1823 // talents not required data in spell chain for work, but must be checked if present for intergrity
1824 if(TalentSpellPos
const* pos
= GetTalentSpellPos(spell_id
))
1826 if(node
.rank
!=pos
->rank
+1)
1828 sLog
.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong rank.",
1829 spell_id
,node
.prev
,node
.first
,node
.rank
,node
.req
);
1833 if(TalentEntry
const* talentEntry
= sTalentStore
.LookupEntry(pos
->talent_id
))
1835 if(node
.first
!=talentEntry
->RankID
[0])
1837 sLog
.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong first rank spell.",
1838 spell_id
,node
.prev
,node
.first
,node
.rank
,node
.req
);
1842 if(node
.rank
> 1 && node
.prev
!= talentEntry
->RankID
[node
.rank
-1-1])
1844 sLog
.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong prev rank spell.",
1845 spell_id
,node
.prev
,node
.first
,node
.rank
,node
.req
);
1849 /*if(node.req!=talentEntry->DependsOnSpell)
1851 sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong required spell.",
1852 spell_id,node.prev,node.first,node.rank,node.req);
1858 mSpellChains
[spell_id
] = node
;
1861 mSpellChainsNext
.insert(SpellChainMapNext::value_type(node
.prev
,spell_id
));
1864 mSpellChainsNext
.insert(SpellChainMapNext::value_type(node
.req
,spell_id
));
1867 } while( result
->NextRow() );
1871 // additional integrity checks
1872 for(SpellChainMap::const_iterator i
= mSpellChains
.begin(); i
!= mSpellChains
.end(); ++i
)
1876 SpellChainMap::const_iterator i_prev
= mSpellChains
.find(i
->second
.prev
);
1877 if(i_prev
== mSpellChains
.end())
1879 sLog
.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not found previous rank spell in table.",
1880 i
->first
,i
->second
.prev
,i
->second
.first
,i
->second
.rank
,i
->second
.req
);
1882 else if( i_prev
->second
.first
!= i
->second
.first
)
1884 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).",
1885 i
->first
,i
->second
.prev
,i
->second
.first
,i
->second
.rank
,i
->second
.req
,
1886 i_prev
->second
.prev
,i_prev
->second
.first
,i_prev
->second
.rank
,i_prev
->second
.req
);
1888 else if( i_prev
->second
.rank
+1 != i
->second
.rank
)
1890 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).",
1891 i
->first
,i
->second
.prev
,i
->second
.first
,i
->second
.rank
,i
->second
.req
,
1892 i_prev
->second
.prev
,i_prev
->second
.first
,i_prev
->second
.rank
,i_prev
->second
.req
);
1898 SpellChainMap::const_iterator i_req
= mSpellChains
.find(i
->second
.req
);
1899 if(i_req
== mSpellChains
.end())
1901 sLog
.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not found required rank spell in table.",
1902 i
->first
,i
->second
.prev
,i
->second
.first
,i
->second
.rank
,i
->second
.req
);
1904 else if( i_req
->second
.first
== i
->second
.first
)
1906 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).",
1907 i
->first
,i
->second
.prev
,i
->second
.first
,i
->second
.rank
,i
->second
.req
,
1908 i_req
->second
.prev
,i_req
->second
.first
,i_req
->second
.rank
,i_req
->second
.req
);
1910 else if( i_req
->second
.req
)
1912 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).",
1913 i
->first
,i
->second
.prev
,i
->second
.first
,i
->second
.rank
,i
->second
.req
,
1914 i_req
->second
.prev
,i_req
->second
.first
,i_req
->second
.rank
,i_req
->second
.req
);
1920 sLog
.outString( ">> Loaded %u spell chain records", count
);
1923 void SpellMgr::LoadSpellLearnSkills()
1925 mSpellLearnSkills
.clear(); // need for reload case
1927 // search auto-learned skills and add its to map also for use in unlearn spells/talents
1928 uint32 dbc_count
= 0;
1929 barGoLink
bar( sSpellStore
.GetNumRows() );
1930 for(uint32 spell
= 0; spell
< sSpellStore
.GetNumRows(); ++spell
)
1933 SpellEntry
const* entry
= sSpellStore
.LookupEntry(spell
);
1938 for(int i
= 0; i
< 3; ++i
)
1940 if(entry
->Effect
[i
]==SPELL_EFFECT_SKILL
)
1942 SpellLearnSkillNode dbc_node
;
1943 dbc_node
.skill
= entry
->EffectMiscValue
[i
];
1944 if ( dbc_node
.skill
!= SKILL_RIDING
)
1947 dbc_node
.value
= entry
->CalculateSimpleValue(i
)*75;
1948 dbc_node
.maxvalue
= entry
->CalculateSimpleValue(i
)*75;
1950 mSpellLearnSkills
[spell
] = dbc_node
;
1958 sLog
.outString( ">> Loaded %u Spell Learn Skills from DBC", dbc_count
);
1961 void SpellMgr::LoadSpellLearnSpells()
1963 mSpellLearnSpells
.clear(); // need for reload case
1966 QueryResult
*result
= WorldDatabase
.Query("SELECT entry, SpellID, Active FROM spell_learn_spell");
1973 sLog
.outString( ">> Loaded 0 spell learn spells" );
1974 sLog
.outErrorDb("`spell_learn_spell` table is empty!");
1980 barGoLink
bar( result
->GetRowCount() );
1984 Field
*fields
= result
->Fetch();
1986 uint32 spell_id
= fields
[0].GetUInt32();
1988 SpellLearnSpellNode node
;
1989 node
.spell
= fields
[1].GetUInt32();
1990 node
.active
= fields
[2].GetBool();
1991 node
.autoLearned
= false;
1993 if (!sSpellStore
.LookupEntry(spell_id
))
1995 sLog
.outErrorDb("Spell %u listed in `spell_learn_spell` does not exist",spell_id
);
1999 if (!sSpellStore
.LookupEntry(node
.spell
))
2001 sLog
.outErrorDb("Spell %u listed in `spell_learn_spell` learning not existed spell %u",spell_id
,node
.spell
);
2005 if (GetTalentSpellCost(node
.spell
))
2007 sLog
.outErrorDb("Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped",spell_id
,node
.spell
);
2011 mSpellLearnSpells
.insert(SpellLearnSpellMap::value_type(spell_id
,node
));
2014 } while( result
->NextRow() );
2018 // search auto-learned spells and add its to map also for use in unlearn spells/talents
2019 uint32 dbc_count
= 0;
2020 for(uint32 spell
= 0; spell
< sSpellStore
.GetNumRows(); ++spell
)
2022 SpellEntry
const* entry
= sSpellStore
.LookupEntry(spell
);
2027 for(int i
= 0; i
< 3; ++i
)
2029 if(entry
->Effect
[i
]==SPELL_EFFECT_LEARN_SPELL
)
2031 SpellLearnSpellNode dbc_node
;
2032 dbc_node
.spell
= entry
->EffectTriggerSpell
[i
];
2033 dbc_node
.active
= true; // all dbc based learned spells is active (show in spell book or hide by client itself)
2035 // ignore learning not existed spells (broken/outdated/or generic learnig spell 483
2036 if (!sSpellStore
.LookupEntry(dbc_node
.spell
))
2039 // talent or passive spells or skill-step spells auto-casted and not need dependent learning,
2040 // pet teaching spells don't must be dependent learning (casted)
2041 // other required explicit dependent learning
2042 dbc_node
.autoLearned
= entry
->EffectImplicitTargetA
[i
]==TARGET_PET
|| GetTalentSpellCost(spell
) > 0 || IsPassiveSpell(spell
) || IsSpellHaveEffect(entry
,SPELL_EFFECT_SKILL_STEP
);
2044 SpellLearnSpellMapBounds db_node_bounds
= GetSpellLearnSpellMapBounds(spell
);
2047 for(SpellLearnSpellMap::const_iterator itr
= db_node_bounds
.first
; itr
!= db_node_bounds
.second
; ++itr
)
2049 if (itr
->second
.spell
== dbc_node
.spell
)
2051 sLog
.outErrorDb("Spell %u auto-learn spell %u in spell.dbc then the record in `spell_learn_spell` is redundant, please fix DB.",
2052 spell
,dbc_node
.spell
);
2058 if (!found
) // add new spell-spell pair if not found
2060 mSpellLearnSpells
.insert(SpellLearnSpellMap::value_type(spell
,dbc_node
));
2068 sLog
.outString( ">> Loaded %u spell learn spells + %u found in DBC", count
, dbc_count
);
2071 void SpellMgr::LoadSpellScriptTarget()
2073 mSpellScriptTarget
.clear(); // need for reload case
2077 QueryResult
*result
= WorldDatabase
.Query("SELECT entry,type,targetEntry FROM spell_script_target");
2086 sLog
.outErrorDb(">> Loaded 0 SpellScriptTarget. DB table `spell_script_target` is empty.");
2090 barGoLink
bar(result
->GetRowCount());
2094 Field
*fields
= result
->Fetch();
2097 uint32 spellId
= fields
[0].GetUInt32();
2098 uint32 type
= fields
[1].GetUInt32();
2099 uint32 targetEntry
= fields
[2].GetUInt32();
2101 SpellEntry
const* spellProto
= sSpellStore
.LookupEntry(spellId
);
2105 sLog
.outErrorDb("Table `spell_script_target`: spellId %u listed for TargetEntry %u does not exist.",spellId
,targetEntry
);
2109 bool targetfound
= false;
2110 for(int i
= 0; i
<3; ++i
)
2112 if( spellProto
->EffectImplicitTargetA
[i
]==TARGET_SCRIPT
||
2113 spellProto
->EffectImplicitTargetB
[i
]==TARGET_SCRIPT
||
2114 spellProto
->EffectImplicitTargetA
[i
]==TARGET_SCRIPT_COORDINATES
||
2115 spellProto
->EffectImplicitTargetB
[i
]==TARGET_SCRIPT_COORDINATES
)
2123 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).",spellId
,targetEntry
);
2127 if( type
>= MAX_SPELL_TARGET_TYPE
)
2129 sLog
.outErrorDb("Table `spell_script_target`: target type %u for TargetEntry %u is incorrect.",type
,targetEntry
);
2135 case SPELL_TARGET_TYPE_GAMEOBJECT
:
2137 if( targetEntry
==0 )
2140 if(!sGOStorage
.LookupEntry
<GameObjectInfo
>(targetEntry
))
2142 sLog
.outErrorDb("Table `spell_script_target`: gameobject template entry %u does not exist.",targetEntry
);
2149 if( targetEntry
==0 )
2151 sLog
.outErrorDb("Table `spell_script_target`: target entry == 0 for not GO target type (%u).",type
);
2154 if(!sCreatureStorage
.LookupEntry
<CreatureInfo
>(targetEntry
))
2156 sLog
.outErrorDb("Table `spell_script_target`: creature template entry %u does not exist.",targetEntry
);
2159 const CreatureInfo
* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(targetEntry
);
2161 if(spellId
== 30427 && !cInfo
->SkinLootId
)
2163 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
);
2170 mSpellScriptTarget
.insert(SpellScriptTarget::value_type(spellId
,SpellTargetEntry(SpellTargetType(type
),targetEntry
)));
2173 } while (result
->NextRow());
2178 /* Disabled (lot errors at this moment)
2179 for(uint32 i = 1; i < sSpellStore.nCount; ++i)
2181 SpellEntry const * spellInfo = sSpellStore.LookupEntry(i);
2186 for(int j=0; j<3; ++j)
2188 if( spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT || spellInfo->EffectImplicitTargetA[j] != TARGET_SELF && spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT )
2190 SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(spellInfo->Id);
2191 SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(spellInfo->Id);
2194 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);
2195 break; // effects of spell
2203 sLog
.outString(">> Loaded %u Spell Script Targets", count
);
2206 void SpellMgr::LoadSpellPetAuras()
2208 mSpellPetAuraMap
.clear(); // need for reload case
2213 QueryResult
*result
= WorldDatabase
.Query("SELECT spell, effectId, pet, aura FROM spell_pet_auras");
2222 sLog
.outString( ">> Loaded %u spell pet auras", count
);
2226 barGoLink
bar( result
->GetRowCount() );
2230 Field
*fields
= result
->Fetch();
2234 uint32 spell
= fields
[0].GetUInt32();
2235 uint8 eff
= fields
[1].GetUInt8();
2236 uint32 pet
= fields
[2].GetUInt32();
2237 uint32 aura
= fields
[3].GetUInt32();
2239 SpellPetAuraMap::iterator itr
= mSpellPetAuraMap
.find((spell
<<8) + eff
);
2240 if(itr
!= mSpellPetAuraMap
.end())
2242 itr
->second
.AddAura(pet
, aura
);
2246 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(spell
);
2249 sLog
.outErrorDb("Spell %u listed in `spell_pet_auras` does not exist", spell
);
2253 if (spellInfo
->Effect
[eff
] != SPELL_EFFECT_DUMMY
&&
2254 (spellInfo
->Effect
[eff
] != SPELL_EFFECT_APPLY_AURA
||
2255 spellInfo
->EffectApplyAuraName
[eff
] != SPELL_AURA_DUMMY
))
2257 sLog
.outError("Spell %u listed in `spell_pet_auras` does not have dummy aura or dummy effect", spell
);
2261 SpellEntry
const* spellInfo2
= sSpellStore
.LookupEntry(aura
);
2264 sLog
.outErrorDb("Aura %u listed in `spell_pet_auras` does not exist", aura
);
2268 PetAura
pa(pet
, aura
, spellInfo
->EffectImplicitTargetA
[eff
] == TARGET_PET
, spellInfo
->CalculateSimpleValue(eff
));
2269 mSpellPetAuraMap
[(spell
<<8) + eff
] = pa
;
2273 } while( result
->NextRow() );
2278 sLog
.outString( ">> Loaded %u spell pet auras", count
);
2281 void SpellMgr::LoadPetLevelupSpellMap()
2284 uint32 family_count
= 0;
2286 for (uint32 i
= 0; i
< sCreatureFamilyStore
.GetNumRows(); ++i
)
2288 CreatureFamilyEntry
const *creatureFamily
= sCreatureFamilyStore
.LookupEntry(i
);
2289 if(!creatureFamily
) // not exist
2292 for (uint32 j
= 0; j
< sSkillLineAbilityStore
.GetNumRows(); ++j
)
2294 SkillLineAbilityEntry
const *skillLine
= sSkillLineAbilityStore
.LookupEntry(j
);
2298 if (skillLine
->skillId
!=creatureFamily
->skillLine
[0] &&
2299 (!creatureFamily
->skillLine
[1] || skillLine
->skillId
!=creatureFamily
->skillLine
[1]))
2302 if(skillLine
->learnOnGetSkill
!= ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
)
2305 SpellEntry
const *spell
= sSpellStore
.LookupEntry(skillLine
->spellId
);
2306 if(!spell
) // not exist
2309 PetLevelupSpellSet
& spellSet
= mPetLevelupSpellMap
[creatureFamily
->ID
];
2310 if(spellSet
.empty())
2313 spellSet
.insert(PetLevelupSpellSet::value_type(spell
->spellLevel
,spell
->Id
));
2319 sLog
.outString( ">> Loaded %u pet levelup and default spells for %u families", count
, family_count
);
2322 bool LoadPetDefaultSpells_helper(CreatureInfo
const* cInfo
, PetDefaultSpellsEntry
& petDefSpells
)
2325 bool have_spell
= false;
2326 for(int j
= 0; j
< MAX_CREATURE_SPELL_DATA_SLOT
; ++j
)
2328 if(petDefSpells
.spellid
[j
])
2337 // remove duplicates with levelupSpells if any
2338 if(PetLevelupSpellSet
const *levelupSpells
= cInfo
->family
? spellmgr
.GetPetLevelupSpellList(cInfo
->family
) : NULL
)
2340 for(int j
= 0; j
< MAX_CREATURE_SPELL_DATA_SLOT
; ++j
)
2342 if(!petDefSpells
.spellid
[j
])
2345 for(PetLevelupSpellSet::const_iterator itr
= levelupSpells
->begin(); itr
!= levelupSpells
->end(); ++itr
)
2347 if (itr
->second
== petDefSpells
.spellid
[j
])
2349 petDefSpells
.spellid
[j
] = 0;
2358 for(int j
= 0; j
< MAX_CREATURE_SPELL_DATA_SLOT
; ++j
)
2360 if(petDefSpells
.spellid
[j
])
2370 void SpellMgr::LoadPetDefaultSpells()
2372 assert(MAX_CREATURE_SPELL_DATA_SLOT
==CREATURE_MAX_SPELLS
);
2374 mPetDefaultSpellsMap
.clear();
2376 uint32 countCreature
= 0;
2377 uint32 countData
= 0;
2379 for(uint32 i
= 0; i
< sCreatureStorage
.MaxEntry
; ++i
)
2381 CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(i
);
2385 if(!cInfo
->PetSpellDataId
)
2388 // for creature with PetSpellDataId get default pet spells from dbc
2389 CreatureSpellDataEntry
const* spellDataEntry
= sCreatureSpellDataStore
.LookupEntry(cInfo
->PetSpellDataId
);
2393 int32 petSpellsId
= -(int32
)cInfo
->PetSpellDataId
;
2394 PetDefaultSpellsEntry petDefSpells
;
2395 for(int j
= 0; j
< MAX_CREATURE_SPELL_DATA_SLOT
; ++j
)
2396 petDefSpells
.spellid
[j
] = spellDataEntry
->spellId
[j
];
2398 if(LoadPetDefaultSpells_helper(cInfo
, petDefSpells
))
2400 mPetDefaultSpellsMap
[petSpellsId
] = petDefSpells
;
2405 // different summon spells
2406 for(uint32 i
= 0; i
< sSpellStore
.GetNumRows(); ++i
)
2408 SpellEntry
const* spellEntry
= sSpellStore
.LookupEntry(i
);
2412 for(int k
= 0; k
< 3; ++k
)
2414 if(spellEntry
->Effect
[k
]==SPELL_EFFECT_SUMMON
|| spellEntry
->Effect
[k
]==SPELL_EFFECT_SUMMON_PET
)
2416 uint32 creature_id
= spellEntry
->EffectMiscValue
[k
];
2417 CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(creature_id
);
2422 if(cInfo
->PetSpellDataId
)
2425 // for creature without PetSpellDataId get default pet spells from creature_template
2426 int32 petSpellsId
= cInfo
->Entry
;
2427 if(mPetDefaultSpellsMap
.find(cInfo
->Entry
) != mPetDefaultSpellsMap
.end())
2430 PetDefaultSpellsEntry petDefSpells
;
2431 for(int j
= 0; j
< MAX_CREATURE_SPELL_DATA_SLOT
; ++j
)
2432 petDefSpells
.spellid
[j
] = cInfo
->spells
[j
];
2434 if(LoadPetDefaultSpells_helper(cInfo
, petDefSpells
))
2436 mPetDefaultSpellsMap
[petSpellsId
] = petDefSpells
;
2444 sLog
.outString( ">> Loaded addition spells for %u pet spell data entries and %u summonable creature templates", countData
, countCreature
);
2447 /// Some checks for spells, to prevent adding deprecated/broken spells for trainers, spell book, etc
2448 bool SpellMgr::IsSpellValid(SpellEntry
const* spellInfo
, Player
* pl
, bool msg
)
2454 bool need_check_reagents
= false;
2457 for(int i
=0; i
<3; ++i
)
2459 switch(spellInfo
->Effect
[i
])
2464 // craft spell for crafting non-existed item (break client recipes list show)
2465 case SPELL_EFFECT_CREATE_ITEM
:
2466 case SPELL_EFFECT_CREATE_ITEM_2
:
2468 if(!ObjectMgr::GetItemPrototype( spellInfo
->EffectItemType
[i
] ))
2473 ChatHandler(pl
).PSendSysMessage("Craft spell %u create not-exist in DB item (Entry: %u) and then...",spellInfo
->Id
,spellInfo
->EffectItemType
[i
]);
2475 sLog
.outErrorDb("Craft spell %u create not-exist in DB item (Entry: %u) and then...",spellInfo
->Id
,spellInfo
->EffectItemType
[i
]);
2480 need_check_reagents
= true;
2483 case SPELL_EFFECT_LEARN_SPELL
:
2485 SpellEntry
const* spellInfo2
= sSpellStore
.LookupEntry(spellInfo
->EffectTriggerSpell
[i
]);
2486 if( !IsSpellValid(spellInfo2
,pl
,msg
) )
2491 ChatHandler(pl
).PSendSysMessage("Spell %u learn to broken spell %u, and then...",spellInfo
->Id
,spellInfo
->EffectTriggerSpell
[i
]);
2493 sLog
.outErrorDb("Spell %u learn to invalid spell %u, and then...",spellInfo
->Id
,spellInfo
->EffectTriggerSpell
[i
]);
2502 if(need_check_reagents
)
2504 for(int j
= 0; j
< 8; ++j
)
2506 if(spellInfo
->Reagent
[j
] > 0 && !ObjectMgr::GetItemPrototype( spellInfo
->Reagent
[j
] ))
2511 ChatHandler(pl
).PSendSysMessage("Craft spell %u have not-exist reagent in DB item (Entry: %u) and then...",spellInfo
->Id
,spellInfo
->Reagent
[j
]);
2513 sLog
.outErrorDb("Craft spell %u have not-exist reagent in DB item (Entry: %u) and then...",spellInfo
->Id
,spellInfo
->Reagent
[j
]);
2523 void SpellMgr::LoadSpellAreas()
2525 mSpellAreaMap
.clear(); // need for reload case
2526 mSpellAreaForQuestMap
.clear();
2527 mSpellAreaForActiveQuestMap
.clear();
2528 mSpellAreaForQuestEndMap
.clear();
2529 mSpellAreaForAuraMap
.clear();
2533 // 0 1 2 3 4 5 6 7 8
2534 QueryResult
*result
= WorldDatabase
.Query("SELECT spell, area, quest_start, quest_start_active, quest_end, aura_spell, racemask, gender, autocast FROM spell_area");
2543 sLog
.outString( ">> Loaded %u spell area requirements", count
);
2547 barGoLink
bar( result
->GetRowCount() );
2551 Field
*fields
= result
->Fetch();
2555 uint32 spell
= fields
[0].GetUInt32();
2556 SpellArea spellArea
;
2557 spellArea
.spellId
= spell
;
2558 spellArea
.areaId
= fields
[1].GetUInt32();
2559 spellArea
.questStart
= fields
[2].GetUInt32();
2560 spellArea
.questStartCanActive
= fields
[3].GetBool();
2561 spellArea
.questEnd
= fields
[4].GetUInt32();
2562 spellArea
.auraSpell
= fields
[5].GetInt32();
2563 spellArea
.raceMask
= fields
[6].GetUInt32();
2564 spellArea
.gender
= Gender(fields
[7].GetUInt8());
2565 spellArea
.autocast
= fields
[8].GetBool();
2567 if(!sSpellStore
.LookupEntry(spell
))
2569 sLog
.outErrorDb("Spell %u listed in `spell_area` does not exist", spell
);
2575 SpellAreaMapBounds sa_bounds
= GetSpellAreaMapBounds(spellArea
.spellId
);
2576 for(SpellAreaMap::const_iterator itr
= sa_bounds
.first
; itr
!= sa_bounds
.second
; ++itr
)
2578 if (spellArea
.spellId
!= itr
->second
.spellId
)
2580 if (spellArea
.areaId
!= itr
->second
.areaId
)
2582 if (spellArea
.questStart
!= itr
->second
.questStart
)
2584 if (spellArea
.auraSpell
!= itr
->second
.auraSpell
)
2586 if ((spellArea
.raceMask
& itr
->second
.raceMask
) == 0)
2588 if (spellArea
.gender
!= itr
->second
.gender
)
2591 // duplicate by requirements
2598 sLog
.outErrorDb("Spell %u listed in `spell_area` already listed with similar requirements.", spell
);
2604 if(spellArea
.areaId
&& !GetAreaEntryByAreaID(spellArea
.areaId
))
2606 sLog
.outErrorDb("Spell %u listed in `spell_area` have wrong area (%u) requirement", spell
,spellArea
.areaId
);
2610 if(spellArea
.questStart
&& !objmgr
.GetQuestTemplate(spellArea
.questStart
))
2612 sLog
.outErrorDb("Spell %u listed in `spell_area` have wrong start quest (%u) requirement", spell
,spellArea
.questStart
);
2616 if(spellArea
.questEnd
)
2618 if(!objmgr
.GetQuestTemplate(spellArea
.questEnd
))
2620 sLog
.outErrorDb("Spell %u listed in `spell_area` have wrong end quest (%u) requirement", spell
,spellArea
.questEnd
);
2624 if(spellArea
.questEnd
==spellArea
.questStart
&& !spellArea
.questStartCanActive
)
2626 sLog
.outErrorDb("Spell %u listed in `spell_area` have quest (%u) requirement for start and end in same time", spell
,spellArea
.questEnd
);
2631 if(spellArea
.auraSpell
)
2633 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(abs(spellArea
.auraSpell
));
2636 sLog
.outErrorDb("Spell %u listed in `spell_area` have wrong aura spell (%u) requirement", spell
,abs(spellArea
.auraSpell
));
2640 switch(spellInfo
->EffectApplyAuraName
[0])
2642 case SPELL_AURA_DUMMY
:
2643 case SPELL_AURA_PHASE
:
2644 case SPELL_AURA_GHOST
:
2647 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
));
2651 if(abs(spellArea
.auraSpell
)==spellArea
.spellId
)
2653 sLog
.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement for itself", spell
,abs(spellArea
.auraSpell
));
2657 // not allow autocast chains by auraSpell field (but allow use as alternative if not present)
2658 if(spellArea
.autocast
&& spellArea
.auraSpell
> 0)
2661 SpellAreaForAuraMapBounds saBound
= GetSpellAreaForAuraMapBounds(spellArea
.spellId
);
2662 for(SpellAreaForAuraMap::const_iterator itr
= saBound
.first
; itr
!= saBound
.second
; ++itr
)
2664 if(itr
->second
->autocast
&& itr
->second
->auraSpell
> 0)
2673 sLog
.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell
,spellArea
.auraSpell
);
2677 SpellAreaMapBounds saBound2
= GetSpellAreaMapBounds(spellArea
.auraSpell
);
2678 for(SpellAreaMap::const_iterator itr2
= saBound2
.first
; itr2
!= saBound2
.second
; ++itr2
)
2680 if(itr2
->second
.autocast
&& itr2
->second
.auraSpell
> 0)
2689 sLog
.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell
,spellArea
.auraSpell
);
2695 if(spellArea
.raceMask
&& (spellArea
.raceMask
& RACEMASK_ALL_PLAYABLE
)==0)
2697 sLog
.outErrorDb("Spell %u listed in `spell_area` have wrong race mask (%u) requirement", spell
,spellArea
.raceMask
);
2701 if(spellArea
.gender
!=GENDER_NONE
&& spellArea
.gender
!=GENDER_FEMALE
&& spellArea
.gender
!=GENDER_MALE
)
2703 sLog
.outErrorDb("Spell %u listed in `spell_area` have wrong gender (%u) requirement", spell
,spellArea
.gender
);
2707 SpellArea
const* sa
= &mSpellAreaMap
.insert(SpellAreaMap::value_type(spell
,spellArea
))->second
;
2709 // for search by current zone/subzone at zone/subzone change
2710 if(spellArea
.areaId
)
2711 mSpellAreaForAreaMap
.insert(SpellAreaForAreaMap::value_type(spellArea
.areaId
,sa
));
2713 // for search at quest start/reward
2714 if(spellArea
.questStart
)
2716 if(spellArea
.questStartCanActive
)
2717 mSpellAreaForActiveQuestMap
.insert(SpellAreaForQuestMap::value_type(spellArea
.questStart
,sa
));
2719 mSpellAreaForQuestMap
.insert(SpellAreaForQuestMap::value_type(spellArea
.questStart
,sa
));
2722 // for search at quest start/reward
2723 if(spellArea
.questEnd
)
2724 mSpellAreaForQuestEndMap
.insert(SpellAreaForQuestMap::value_type(spellArea
.questEnd
,sa
));
2726 // for search at aura apply
2727 if(spellArea
.auraSpell
)
2728 mSpellAreaForAuraMap
.insert(SpellAreaForAuraMap::value_type(abs(spellArea
.auraSpell
),sa
));
2731 } while( result
->NextRow() );
2736 sLog
.outString( ">> Loaded %u spell area requirements", count
);
2739 SpellCastResult
SpellMgr::GetSpellAllowedInLocationError(SpellEntry
const *spellInfo
, uint32 map_id
, uint32 zone_id
, uint32 area_id
, Player
const* player
)
2742 if (spellInfo
->AreaGroupId
> 0)
2745 AreaGroupEntry
const* groupEntry
= sAreaGroupStore
.LookupEntry(spellInfo
->AreaGroupId
);
2748 for (uint32 i
=0; i
<6; ++i
)
2749 if (groupEntry
->AreaId
[i
] == zone_id
|| groupEntry
->AreaId
[i
] == area_id
)
2751 if (found
|| !groupEntry
->nextGroup
)
2753 // Try search in next group
2754 groupEntry
= sAreaGroupStore
.LookupEntry(groupEntry
->nextGroup
);
2758 return SPELL_FAILED_INCORRECT_AREA
;
2761 // continent limitation (virtual continent)
2762 if (spellInfo
->AttributesEx4
& SPELL_ATTR_EX4_CAST_ONLY_IN_OUTLAND
)
2764 uint32 v_map
= GetVirtualMapForMapAndZone(map_id
, zone_id
);
2765 MapEntry
const* mapEntry
= sMapStore
.LookupEntry(v_map
);
2766 if (!mapEntry
|| mapEntry
->addon
< 1 || !mapEntry
->IsContinent())
2767 return SPELL_FAILED_INCORRECT_AREA
;
2770 // raid instance limitation
2771 if (spellInfo
->AttributesEx6
& SPELL_ATTR_EX6_NOT_IN_RAID_INSTANCE
)
2773 MapEntry
const* mapEntry
= sMapStore
.LookupEntry(map_id
);
2774 if (!mapEntry
|| mapEntry
->IsRaid())
2775 return SPELL_FAILED_NOT_IN_RAID_INSTANCE
;
2778 // DB base check (if non empty then must fit at least single for allow)
2779 SpellAreaMapBounds saBounds
= spellmgr
.GetSpellAreaMapBounds(spellInfo
->Id
);
2780 if (saBounds
.first
!= saBounds
.second
)
2782 for(SpellAreaMap::const_iterator itr
= saBounds
.first
; itr
!= saBounds
.second
; ++itr
)
2784 if(itr
->second
.IsFitToRequirements(player
,zone_id
,area_id
))
2785 return SPELL_CAST_OK
;
2787 return SPELL_FAILED_INCORRECT_AREA
;
2791 switch(spellInfo
->Id
)
2793 case 23333: // Warsong Flag
2794 case 23335: // Silverwing Flag
2795 return map_id
== 489 && player
&& player
->InBattleGround() ? SPELL_CAST_OK
: SPELL_FAILED_REQUIRES_AREA
;
2796 case 34976: // Netherstorm Flag
2797 return map_id
== 566 && player
&& player
->InBattleGround() ? SPELL_CAST_OK
: SPELL_FAILED_REQUIRES_AREA
;
2798 case 2584: // Waiting to Resurrect
2799 case 22011: // Spirit Heal Channel
2800 case 22012: // Spirit Heal
2801 case 24171: // Resurrection Impact Visual
2802 case 42792: // Recently Dropped Flag
2803 case 43681: // Inactive
2804 case 44535: // Spirit Heal (mana)
2806 MapEntry
const* mapEntry
= sMapStore
.LookupEntry(map_id
);
2808 return SPELL_FAILED_INCORRECT_AREA
;
2810 return mapEntry
->IsBattleGround() && player
&& player
->InBattleGround() ? SPELL_CAST_OK
: SPELL_FAILED_REQUIRES_AREA
;
2812 case 44521: // Preparation
2815 return SPELL_FAILED_REQUIRES_AREA
;
2817 MapEntry
const* mapEntry
= sMapStore
.LookupEntry(map_id
);
2819 return SPELL_FAILED_INCORRECT_AREA
;
2821 if (!mapEntry
->IsBattleGround())
2822 return SPELL_FAILED_REQUIRES_AREA
;
2824 BattleGround
* bg
= player
->GetBattleGround();
2825 return bg
&& bg
->GetStatus()==STATUS_WAIT_JOIN
? SPELL_CAST_OK
: SPELL_FAILED_REQUIRES_AREA
;
2827 case 32724: // Gold Team (Alliance)
2828 case 32725: // Green Team (Alliance)
2829 case 35774: // Gold Team (Horde)
2830 case 35775: // Green Team (Horde)
2832 MapEntry
const* mapEntry
= sMapStore
.LookupEntry(map_id
);
2834 return SPELL_FAILED_INCORRECT_AREA
;
2836 return mapEntry
->IsBattleArena() && player
&& player
->InBattleGround() ? SPELL_CAST_OK
: SPELL_FAILED_REQUIRES_AREA
;
2838 case 32727: // Arena Preparation
2841 return SPELL_FAILED_REQUIRES_AREA
;
2843 MapEntry
const* mapEntry
= sMapStore
.LookupEntry(map_id
);
2845 return SPELL_FAILED_INCORRECT_AREA
;
2847 if (!mapEntry
->IsBattleArena())
2848 return SPELL_FAILED_REQUIRES_AREA
;
2850 BattleGround
* bg
= player
->GetBattleGround();
2851 return bg
&& bg
->GetStatus()==STATUS_WAIT_JOIN
? SPELL_CAST_OK
: SPELL_FAILED_REQUIRES_AREA
;
2855 return SPELL_CAST_OK
;
2858 void SpellMgr::LoadSkillLineAbilityMap()
2860 mSkillLineAbilityMap
.clear();
2862 barGoLink
bar( sSkillLineAbilityStore
.GetNumRows() );
2865 for (uint32 i
= 0; i
< sSkillLineAbilityStore
.GetNumRows(); ++i
)
2868 SkillLineAbilityEntry
const *SkillInfo
= sSkillLineAbilityStore
.LookupEntry(i
);
2872 mSkillLineAbilityMap
.insert(SkillLineAbilityMap::value_type(SkillInfo
->spellId
,SkillInfo
));
2877 sLog
.outString(">> Loaded %u SkillLineAbility MultiMap Data", count
);
2880 void SpellMgr::CheckUsedSpells(char const* table
)
2882 uint32 countSpells
= 0;
2883 uint32 countMasks
= 0;
2885 // 0 1 2 3 4 5 6 7 8 9 10 11
2886 QueryResult
*result
= WorldDatabase
.PQuery("SELECT spellid,SpellFamilyName,SpellFamilyMaskA,SpellFamilyMaskB,SpellIcon,SpellVisual,SpellCategory,EffectType,EffectAura,EffectIdx,Name,Code FROM %s",table
);
2895 sLog
.outErrorDb("`%s` table is empty!",table
);
2899 barGoLink
bar( result
->GetRowCount() );
2903 Field
*fields
= result
->Fetch();
2907 uint32 spell
= fields
[0].GetUInt32();
2908 int32 family
= fields
[1].GetInt32();
2909 uint64 familyMaskA
= fields
[2].GetUInt64();
2910 uint32 familyMaskB
= fields
[3].GetUInt32();
2911 int32 spellIcon
= fields
[4].GetInt32();
2912 int32 spellVisual
= fields
[5].GetInt32();
2913 int32 category
= fields
[6].GetInt32();
2914 int32 effectType
= fields
[7].GetInt32();
2915 int32 auraType
= fields
[8].GetInt32();
2916 int32 effectIdx
= fields
[9].GetInt32();
2917 std::string name
= fields
[10].GetCppString();
2918 std::string code
= fields
[11].GetCppString();
2920 // checks of correctness requirements itself
2922 if (family
< -1 || family
> SPELLFAMILY_PET
)
2924 sLog
.outError("Table '%s' for spell %u have wrong SpellFamily value(%u), skipped.",table
,spell
,family
);
2928 // TODO: spellIcon check need dbc loading
2931 sLog
.outError("Table '%s' for spell %u have wrong SpellIcon value(%u), skipped.",table
,spell
,spellIcon
);
2935 // TODO: spellVisual check need dbc loading
2936 if (spellVisual
< -1)
2938 sLog
.outError("Table '%s' for spell %u have wrong SpellVisual value(%u), skipped.",table
,spell
,spellVisual
);
2942 // TODO: for spellCategory better check need dbc loading
2943 if (category
< -1 || category
>=0 && sSpellCategoryStore
.find(category
) == sSpellCategoryStore
.end())
2945 sLog
.outError("Table '%s' for spell %u have wrong SpellCategory value(%u), skipped.",table
,spell
,category
);
2949 if (effectType
< -1 || effectType
>= TOTAL_SPELL_EFFECTS
)
2951 sLog
.outError("Table '%s' for spell %u have wrong SpellEffect type value(%u), skipped.",table
,spell
,effectType
);
2955 if (auraType
< -1 || auraType
>= TOTAL_AURAS
)
2957 sLog
.outError("Table '%s' for spell %u have wrong SpellAura type value(%u), skipped.",table
,spell
,auraType
);
2961 if (effectIdx
< -1 || effectIdx
>= 3)
2963 sLog
.outError("Table '%s' for spell %u have wrong EffectIdx value(%u), skipped.",table
,spell
,effectIdx
);
2967 // now checks of requirements
2973 SpellEntry
const* spellEntry
= sSpellStore
.LookupEntry(spell
);
2976 sLog
.outError("Spell %u '%s' not exist but used in %s.",spell
,name
.c_str(),code
.c_str());
2980 if(family
>= 0 && spellEntry
->SpellFamilyName
!= family
)
2982 sLog
.outError("Spell %u '%s' family(%u) <> %u but used in %s.",spell
,name
.c_str(),spellEntry
->SpellFamilyName
,family
,code
.c_str());
2986 if(familyMaskA
!= UI64LIT(0xFFFFFFFFFFFFFFFF) || familyMaskB
!= 0xFFFFFFFF)
2988 if(familyMaskA
== UI64LIT(0x0000000000000000) && familyMaskB
== 0x00000000)
2990 if(spellEntry
->SpellFamilyFlags
!= 0 || spellEntry
->SpellFamilyFlags2
!= 0)
2992 sLog
.outError("Spell %u '%s' not fit to (" I64FMT
"," I32FMT
") but used in %s.",spell
,name
.c_str(),familyMaskA
,familyMaskB
,code
.c_str());
2999 if((spellEntry
->SpellFamilyFlags
& familyMaskA
)==0 && (spellEntry
->SpellFamilyFlags2
& familyMaskB
)==0)
3001 sLog
.outError("Spell %u '%s' not fit to (" I64FMT
"," I32FMT
") but used in %s.",spell
,name
.c_str(),familyMaskA
,familyMaskB
,code
.c_str());
3008 if(spellIcon
>= 0 && spellEntry
->SpellIconID
!= spellIcon
)
3010 sLog
.outError("Spell %u '%s' icon(%u) <> %u but used in %s.",spell
,name
.c_str(),spellEntry
->SpellIconID
,spellIcon
,code
.c_str());
3014 if(spellVisual
>= 0 && spellEntry
->SpellVisual
[0] != spellVisual
)
3016 sLog
.outError("Spell %u '%s' visual(%u) <> %u but used in %s.",spell
,name
.c_str(),spellEntry
->SpellVisual
[0],spellVisual
,code
.c_str());
3020 if(category
>= 0 && spellEntry
->Category
!= category
)
3022 sLog
.outError("Spell %u '%s' category(%u) <> %u but used in %s.",spell
,name
.c_str(),spellEntry
->Category
,category
,code
.c_str());
3028 if(effectType
>= 0 && spellEntry
->Effect
[effectIdx
] != effectType
)
3030 sLog
.outError("Spell %u '%s' effect%d <> %u but used in %s.",spell
,name
.c_str(),effectIdx
+1,effectType
,code
.c_str());
3034 if(auraType
>= 0 && spellEntry
->EffectApplyAuraName
[effectIdx
] != auraType
)
3036 sLog
.outError("Spell %u '%s' aura%d <> %u but used in %s.",spell
,name
.c_str(),effectIdx
+1,auraType
,code
.c_str());
3043 if(effectType
>= 0 && !IsSpellHaveEffect(spellEntry
,SpellEffects(effectType
)))
3045 sLog
.outError("Spell %u '%s' not have effect %u but used in %s.",spell
,name
.c_str(),effectType
,code
.c_str());
3049 if(auraType
>= 0 && !IsSpellHaveAura(spellEntry
,AuraType(auraType
)))
3051 sLog
.outError("Spell %u '%s' not have aura %u but used in %s.",spell
,name
.c_str(),auraType
,code
.c_str());
3061 for(uint32 spellId
= 1; spellId
< sSpellStore
.GetNumRows(); ++spellId
)
3063 SpellEntry
const* spellEntry
= sSpellStore
.LookupEntry(spellId
);
3067 if(family
>=0 && spellEntry
->SpellFamilyName
!= family
)
3070 if(familyMaskA
!= UI64LIT(0xFFFFFFFFFFFFFFFF) || familyMaskB
!= 0xFFFFFFFF)
3072 if(familyMaskA
== UI64LIT(0x0000000000000000) && familyMaskB
== 0x00000000)
3074 if(spellEntry
->SpellFamilyFlags
!= 0 || spellEntry
->SpellFamilyFlags2
!= 0)
3079 if((spellEntry
->SpellFamilyFlags
& familyMaskA
)==0 && (spellEntry
->SpellFamilyFlags2
& familyMaskB
)==0)
3084 if(spellIcon
>= 0 && spellEntry
->SpellIconID
!= spellIcon
)
3087 if(spellVisual
>= 0 && spellEntry
->SpellVisual
[0] != spellVisual
)
3090 if(category
>= 0 && spellEntry
->Category
!= category
)
3095 if(effectType
>=0 && spellEntry
->Effect
[effectIdx
] != effectType
)
3098 if(auraType
>=0 && spellEntry
->EffectApplyAuraName
[effectIdx
] != auraType
)
3103 if(effectType
>=0 && !IsSpellHaveEffect(spellEntry
,SpellEffects(effectType
)))
3106 if(auraType
>=0 && !IsSpellHaveAura(spellEntry
,AuraType(auraType
)))
3117 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",
3118 name
.c_str(),family
,familyMaskA
,familyMaskB
,spellIcon
,spellVisual
,category
,effectIdx
+1,effectType
,effectIdx
+1,auraType
,code
.c_str());
3120 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",
3121 name
.c_str(),family
,familyMaskA
,familyMaskB
,spellIcon
,spellVisual
,category
,effectType
,auraType
,code
.c_str());
3126 } while( result
->NextRow() );
3131 sLog
.outString( ">> Checked %u spells and %u spell masks", countSpells
, countMasks
);
3134 DiminishingGroup
GetDiminishingReturnsGroupForSpell(SpellEntry
const* spellproto
, bool triggered
)
3136 // Explicit Diminishing Groups
3137 switch(spellproto
->SpellFamilyName
)
3139 case SPELLFAMILY_GENERIC
:
3140 // some generic arena related spells have by some strange reason MECHANIC_TURN
3141 if (spellproto
->Mechanic
== MECHANIC_TURN
)
3142 return DIMINISHING_NONE
;
3144 case SPELLFAMILY_ROGUE
:
3147 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00001000000))
3148 return DIMINISHING_FEAR_BLIND
;
3150 else if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000400))
3151 return DIMINISHING_CHEAPSHOT_POUNCE
;
3152 // Crippling poison - Limit to 10 seconds in PvP (No SpellFamilyFlags)
3153 else if (spellproto
->SpellIconID
== 163)
3154 return DIMINISHING_LIMITONLY
;
3157 case SPELLFAMILY_WARLOCK
:
3160 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00080000000))
3161 return DIMINISHING_LIMITONLY
;
3163 else if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00040000000))
3164 return DIMINISHING_CHARM
;
3167 case SPELLFAMILY_DRUID
:
3170 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x02000000000))
3171 return DIMINISHING_CYCLONE
;
3173 else if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00000020000))
3174 return DIMINISHING_CHEAPSHOT_POUNCE
;
3176 else if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000400))
3177 return DIMINISHING_LIMITONLY
;
3180 case SPELLFAMILY_WARRIOR
:
3182 // Hamstring - limit duration to 10s in PvP
3183 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000002))
3184 return DIMINISHING_LIMITONLY
;
3187 case SPELLFAMILY_PRIEST
:
3190 if ((spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000004)) && spellproto
->SpellIconID
== 150)
3191 return DIMINISHING_LIMITONLY
;
3194 case SPELLFAMILY_DEATHKNIGHT
:
3196 // Hungering Cold (no flags)
3197 if (spellproto
->SpellIconID
== 2797)
3198 return DIMINISHING_POLYMORPH_GOUGE_SAP
;
3206 uint32 mechanic
= GetAllSpellMechanicMask(spellproto
);
3207 if (mechanic
== MECHANIC_NONE
) return DIMINISHING_NONE
;
3208 if (mechanic
& ((1<<MECHANIC_STUN
) |
3209 (1<<MECHANIC_SHACKLE
))) return triggered
? DIMINISHING_TRIGGER_STUN
: DIMINISHING_CONTROL_STUN
;
3210 if (mechanic
& (1<<MECHANIC_SLEEP
)) return DIMINISHING_FREEZE_SLEEP
;
3211 if (mechanic
& (1<<MECHANIC_POLYMORPH
)) return DIMINISHING_POLYMORPH_GOUGE_SAP
;
3212 if (mechanic
& (1<<MECHANIC_ROOT
)) return triggered
? DIMINISHING_TRIGGER_ROOT
: DIMINISHING_CONTROL_ROOT
;
3213 if (mechanic
& ((1<<MECHANIC_FEAR
) |
3214 (1<<MECHANIC_TURN
))) return DIMINISHING_FEAR_BLIND
;
3215 if (mechanic
& (1<<MECHANIC_CHARM
)) return DIMINISHING_CHARM
;
3216 if (mechanic
& (1<<MECHANIC_SILENCE
)) return DIMINISHING_SILENCE
;
3217 if (mechanic
& (1<<MECHANIC_DISARM
)) return DIMINISHING_DISARM
;
3218 if (mechanic
& (1<<MECHANIC_FREEZE
)) return DIMINISHING_FREEZE_SLEEP
;
3219 if (mechanic
& ((1<<MECHANIC_KNOCKOUT
) |
3220 (1<<MECHANIC_SAPPED
))) return DIMINISHING_POLYMORPH_GOUGE_SAP
;
3221 if (mechanic
& (1<<MECHANIC_BANISH
)) return DIMINISHING_BANISH
;
3222 if (mechanic
& (1<<MECHANIC_HORROR
)) return DIMINISHING_DEATHCOIL
;
3225 return DIMINISHING_NONE
;
3228 int32
GetDiminishingReturnsLimitDuration(DiminishingGroup group
, SpellEntry
const* spellproto
)
3230 if(!IsDiminishingReturnsGroupDurationLimited(group
))
3233 // Explicit diminishing duration
3234 switch(spellproto
->SpellFamilyName
)
3236 case SPELLFAMILY_HUNTER
:
3239 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x0000100000000000))
3243 case SPELLFAMILY_PALADIN
:
3245 // Repentance - limit to 6 seconds in PvP
3246 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000004))
3250 case SPELLFAMILY_DRUID
:
3252 // Faerie Fire - limit to 40 seconds in PvP (3.1)
3253 if (spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000400))
3257 case SPELLFAMILY_PRIEST
:
3259 // Vampiric Embrace - limit to 60 seconds in PvP (3.1)
3260 if ((spellproto
->SpellFamilyFlags
& UI64LIT(0x00000000004)) && spellproto
->SpellIconID
== 150)
3271 bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group
)
3275 case DIMINISHING_CONTROL_STUN
:
3276 case DIMINISHING_TRIGGER_STUN
:
3277 case DIMINISHING_CONTROL_ROOT
:
3278 case DIMINISHING_TRIGGER_ROOT
:
3279 case DIMINISHING_FEAR_BLIND
:
3280 case DIMINISHING_CHARM
:
3281 case DIMINISHING_POLYMORPH_GOUGE_SAP
:
3282 case DIMINISHING_CHEAPSHOT_POUNCE
:
3283 case DIMINISHING_FREEZE_SLEEP
:
3284 case DIMINISHING_CYCLONE
:
3285 case DIMINISHING_BANISH
:
3286 case DIMINISHING_LIMITONLY
:
3294 DiminishingReturnsType
GetDiminishingReturnsGroupType(DiminishingGroup group
)
3298 case DIMINISHING_CYCLONE
:
3299 case DIMINISHING_TRIGGER_STUN
:
3300 case DIMINISHING_CONTROL_STUN
:
3301 case DIMINISHING_CHEAPSHOT_POUNCE
:
3303 case DIMINISHING_CONTROL_ROOT
:
3304 case DIMINISHING_TRIGGER_ROOT
:
3305 case DIMINISHING_FEAR_BLIND
:
3306 case DIMINISHING_CHARM
:
3307 case DIMINISHING_POLYMORPH_GOUGE_SAP
:
3308 case DIMINISHING_SILENCE
:
3309 case DIMINISHING_DISARM
:
3310 case DIMINISHING_DEATHCOIL
:
3311 case DIMINISHING_FREEZE_SLEEP
:
3312 case DIMINISHING_BANISH
:
3313 return DRTYPE_PLAYER
;
3321 bool SpellArea::IsFitToRequirements(Player
const* player
, uint32 newZone
, uint32 newArea
) const
3323 if(gender
!=GENDER_NONE
)
3325 // not in expected gender
3326 if(!player
|| gender
!= player
->getGender())
3332 // not in expected race
3333 if(!player
|| !(raceMask
& player
->getRaceMask()))
3339 // not in expected zone
3340 if(newZone
!=areaId
&& newArea
!=areaId
)
3346 // not in expected required quest state
3347 if(!player
|| (!questStartCanActive
|| !player
->IsActiveQuest(questStart
)) && !player
->GetQuestRewardStatus(questStart
))
3353 // not in expected forbidden quest state
3354 if(!player
|| player
->GetQuestRewardStatus(questEnd
))
3360 // not have expected aura
3364 // have expected aura
3365 return player
->HasAura(auraSpell
,0);
3367 // not have expected aura
3368 return !player
->HasAura(-auraSpell
,0);