root/trunk/src/game/SpellMgr.cpp @ 122

Revision 122, 88.8 kB (checked in by yumileroy, 17 years ago)

[svn] Fix a compile error about M_PI_2.
Update Felmyst script to test new setActive function.
Fix the bug that priest's fear is unbreakable (dirty hack before find the correct way).
(some unfinished unused content included, just ignore them, will finish them later)

Original author: megamage
Date: 2008-10-27 10:57:53-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "SpellMgr.h"
22#include "ObjectMgr.h"
23#include "SpellAuraDefines.h"
24#include "ProgressBar.h"
25#include "Database/DBCStores.h"
26#include "World.h"
27#include "Chat.h"
28#include "Spell.h"
29
30SpellMgr::SpellMgr()
31{
32}
33
34SpellMgr::~SpellMgr()
35{
36}
37
38SpellMgr& SpellMgr::Instance()
39{
40    static SpellMgr spellMgr;
41    return spellMgr;
42}
43
44int32 GetSpellDuration(SpellEntry const *spellInfo)
45{
46    if(!spellInfo)
47        return 0;
48    SpellDurationEntry const *du = sSpellDurationStore.LookupEntry(spellInfo->DurationIndex);
49    if(!du)
50        return 0;
51    return (du->Duration[0] == -1) ? -1 : abs(du->Duration[0]);
52}
53
54int32 GetSpellMaxDuration(SpellEntry const *spellInfo)
55{
56    if(!spellInfo)
57        return 0;
58    SpellDurationEntry const *du = sSpellDurationStore.LookupEntry(spellInfo->DurationIndex);
59    if(!du)
60        return 0;
61    return (du->Duration[2] == -1) ? -1 : abs(du->Duration[2]);
62}
63
64uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell)
65{
66    SpellCastTimesEntry const *spellCastTimeEntry = sSpellCastTimesStore.LookupEntry(spellInfo->CastingTimeIndex);
67
68    // not all spells have cast time index and this is all is pasiive abilities
69    if(!spellCastTimeEntry)
70        return 0;
71
72    int32 castTime = spellCastTimeEntry->CastTime;
73
74    if (spell)
75    {
76        if(Player* modOwner = spell->GetCaster()->GetSpellModOwner())
77            modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell);
78
79        if( !(spellInfo->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_UNK5)) )
80            castTime = int32(castTime * spell->GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED));
81        else
82        {
83            if (spell->IsRangedSpell() && !spell->IsAutoRepeat())
84                castTime = int32(castTime * spell->GetCaster()->m_modAttackSpeedPct[RANGED_ATTACK]);
85        }
86    }
87
88    if (spellInfo->Attributes & SPELL_ATTR_RANGED && (!spell || !(spell->IsAutoRepeat())))
89        castTime += 500;
90
91    return (castTime > 0) ? uint32(castTime) : 0;
92}
93
94bool IsPassiveSpell(uint32 spellId)
95{
96    SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
97    if (!spellInfo)
98        return false;
99    return (spellInfo->Attributes & SPELL_ATTR_PASSIVE) != 0;
100}
101
102bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2)
103{
104    SpellEntry const *spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
105    SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
106    if(!spellInfo_1 || !spellInfo_2) return false;
107    if(spellInfo_1->Id == spellId_2) return false;
108
109    if (spellInfo_1->Effect[effIndex_1] != spellInfo_2->Effect[effIndex_2] ||
110        spellInfo_1->EffectItemType[effIndex_1] != spellInfo_2->EffectItemType[effIndex_2] ||
111        spellInfo_1->EffectMiscValue[effIndex_1] != spellInfo_2->EffectMiscValue[effIndex_2] ||
112        spellInfo_1->EffectApplyAuraName[effIndex_1] != spellInfo_2->EffectApplyAuraName[effIndex_2])
113        return false;
114
115    return true;
116}
117
118int32 CompareAuraRanks(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2)
119{
120    SpellEntry const*spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
121    SpellEntry const*spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
122    if(!spellInfo_1 || !spellInfo_2) return 0;
123    if (spellId_1 == spellId_2) return 0;
124
125    int32 diff = spellInfo_1->EffectBasePoints[effIndex_1] - spellInfo_2->EffectBasePoints[effIndex_2];
126    if (spellInfo_1->EffectBasePoints[effIndex_1]+1 < 0 && spellInfo_2->EffectBasePoints[effIndex_2]+1 < 0) return -diff;
127    else return diff;
128}
129
130SpellSpecific GetSpellSpecific(uint32 spellId)
131{
132    SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
133    if(!spellInfo)
134        return SPELL_NORMAL;
135
136    switch(spellInfo->SpellFamilyName)
137    {
138        case SPELLFAMILY_MAGE:
139        {
140            // family flags 18(Molten), 25(Frost/Ice), 28(Mage)
141            if (spellInfo->SpellFamilyFlags & 0x12040000)
142                return SPELL_MAGE_ARMOR;
143
144            if ((spellInfo->SpellFamilyFlags & 0x1000000) && spellInfo->EffectApplyAuraName[0]==SPELL_AURA_MOD_CONFUSE)
145                return SPELL_MAGE_POLYMORPH;
146
147            break;
148        }
149        case SPELLFAMILY_WARRIOR:
150        {
151            if (spellInfo->SpellFamilyFlags & 0x00008000010000LL)
152                return SPELL_POSITIVE_SHOUT;
153
154            break;
155        }
156        case SPELLFAMILY_WARLOCK:
157        {
158            // only warlock curses have this
159            if (spellInfo->Dispel == DISPEL_CURSE)
160                return SPELL_CURSE;
161
162            // family flag 37 (only part spells have family name)
163            if (spellInfo->SpellFamilyFlags & 0x2000000000LL)
164                return SPELL_WARLOCK_ARMOR;
165
166            break;
167        }
168        case SPELLFAMILY_HUNTER:
169        {
170            // only hunter stings have this
171            if (spellInfo->Dispel == DISPEL_POISON)
172                return SPELL_STING;
173
174            break;
175        }
176        case SPELLFAMILY_PALADIN:
177        {
178            if (IsSealSpell(spellInfo))
179                return SPELL_SEAL;
180
181            if (spellInfo->SpellFamilyFlags & 0x10000100LL)
182                return SPELL_BLESSING;
183
184            if ((spellInfo->SpellFamilyFlags & 0x00000820180400LL) && (spellInfo->AttributesEx3 & 0x200))
185                return SPELL_JUDGEMENT;
186
187            for (int i = 0; i < 3; i++)
188            {
189                // only paladin auras have this
190                if (spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY)
191                    return SPELL_AURA;
192            }
193            break;
194        }
195        case SPELLFAMILY_SHAMAN:
196        {
197            if (IsElementalShield(spellInfo))
198                return SPELL_ELEMENTAL_SHIELD;
199
200            break;
201        }
202
203        case SPELLFAMILY_POTION:
204            return spellmgr.GetSpellElixirSpecific(spellInfo->Id);
205    }
206
207    // only warlock armor/skin have this (in additional to family cases)
208    if( spellInfo->SpellVisual == 130 && spellInfo->SpellIconID == 89)
209    {
210        return SPELL_WARLOCK_ARMOR;
211    }
212
213    // only hunter aspects have this (but not all aspects in hunter family)
214    if( spellInfo->activeIconID == 122 && (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_NATURE) &&
215        (spellInfo->Attributes & 0x50000) != 0 && (spellInfo->Attributes & 0x9000010) == 0)
216    {
217        return SPELL_ASPECT;
218    }
219
220    for(int i = 0; i < 3; i++)
221        if( spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA && (
222        spellInfo->EffectApplyAuraName[i] == SPELL_AURA_TRACK_CREATURES ||
223        spellInfo->EffectApplyAuraName[i] == SPELL_AURA_TRACK_RESOURCES ||
224        spellInfo->EffectApplyAuraName[i] == SPELL_AURA_TRACK_STEALTHED ) )
225            return SPELL_TRACKER;
226
227    // elixirs can have different families, but potion most ofc.
228    if(SpellSpecific sp = spellmgr.GetSpellElixirSpecific(spellInfo->Id))
229        return sp;
230
231    return SPELL_NORMAL;
232}
233
234bool IsSingleFromSpellSpecificPerCaster(uint32 spellSpec1,uint32 spellSpec2)
235{
236    switch(spellSpec1)
237    {
238        case SPELL_SEAL:
239        case SPELL_BLESSING:
240        case SPELL_AURA:
241        case SPELL_STING:
242        case SPELL_CURSE:
243        case SPELL_ASPECT:
244        case SPELL_TRACKER:
245        case SPELL_WARLOCK_ARMOR:
246        case SPELL_MAGE_ARMOR:
247        case SPELL_MAGE_POLYMORPH:
248        case SPELL_POSITIVE_SHOUT:
249        case SPELL_JUDGEMENT:
250            return spellSpec1==spellSpec2;
251        case SPELL_BATTLE_ELIXIR:
252            return spellSpec2==SPELL_BATTLE_ELIXIR
253                || spellSpec2==SPELL_FLASK_ELIXIR;
254        case SPELL_GUARDIAN_ELIXIR:
255            return spellSpec2==SPELL_GUARDIAN_ELIXIR
256                || spellSpec2==SPELL_FLASK_ELIXIR;
257        case SPELL_FLASK_ELIXIR:
258            return spellSpec2==SPELL_BATTLE_ELIXIR
259                || spellSpec2==SPELL_GUARDIAN_ELIXIR
260                || spellSpec2==SPELL_FLASK_ELIXIR;
261        default:
262            return false;
263    }
264}
265
266bool IsPositiveTarget(uint32 targetA, uint32 targetB)
267{
268    // non-positive targets
269    switch(targetA)
270    {
271        case TARGET_CHAIN_DAMAGE:
272        case TARGET_ALL_ENEMY_IN_AREA:
273        case TARGET_ALL_ENEMY_IN_AREA_INSTANT:
274        case TARGET_IN_FRONT_OF_CASTER:
275        case TARGET_ALL_ENEMY_IN_AREA_CHANNELED:
276        case TARGET_CURRENT_ENEMY_COORDINATES:
277        case TARGET_SINGLE_ENEMY:
278            return false;
279        case TARGET_ALL_AROUND_CASTER:
280            return (targetB == TARGET_ALL_PARTY || targetB == TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER);
281        default:
282            break;
283    }
284    if (targetB)
285        return IsPositiveTarget(targetB, 0);
286    return true;
287}
288
289bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
290{
291    SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
292    if (!spellproto) return false;
293
294    switch(spellId)
295    {
296        case 23333:                                         // BG spell
297        case 23335:                                         // BG spell
298        case 34976:                                         // BG spell
299            return true;
300        case 28441:                                         // not positive dummy spell
301        case 37675:                                         // Chaos Blast
302            return false;
303    }
304
305    switch(spellproto->Effect[effIndex])
306    {
307        // always positive effects (check before target checks that provided non-positive result in some case for positive effects)
308        case SPELL_EFFECT_HEAL:
309        case SPELL_EFFECT_LEARN_SPELL:
310        case SPELL_EFFECT_SKILL_STEP:
311        case SPELL_EFFECT_HEAL_PCT:
312        case SPELL_EFFECT_ENERGIZE_PCT:
313            return true;
314
315            // non-positive aura use
316        case SPELL_EFFECT_APPLY_AURA:
317        case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
318        {
319            switch(spellproto->EffectApplyAuraName[effIndex])
320            {
321                case SPELL_AURA_DUMMY:
322                {
323                    // dummy aura can be positive or negative dependent from casted spell
324                    switch(spellproto->Id)
325                    {
326                        case 13139:                         // net-o-matic special effect
327                        case 23445:                         // evil twin
328                        case 38637:                         // Nether Exhaustion (red)
329                        case 38638:                         // Nether Exhaustion (green)
330                        case 38639:                         // Nether Exhaustion (blue)
331                            return false;
332                        default:
333                            break;
334                    }
335                }   break;
336                case SPELL_AURA_MOD_STAT:
337                case SPELL_AURA_MOD_DAMAGE_DONE:            // dependent from bas point sign (negative -> negative)
338                case SPELL_AURA_MOD_HEALING_DONE:
339                {
340                    if(spellproto->EffectBasePoints[effIndex]+int32(spellproto->EffectBaseDice[effIndex]) < 0)
341                        return false;
342                    break;
343                }
344                case SPELL_AURA_ADD_TARGET_TRIGGER:
345                    return true;
346                case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
347                    if(spellId != spellproto->EffectTriggerSpell[effIndex])
348                    {
349                        uint32 spellTriggeredId = spellproto->EffectTriggerSpell[effIndex];
350                        SpellEntry const *spellTriggeredProto = sSpellStore.LookupEntry(spellTriggeredId);
351
352                        if(spellTriggeredProto)
353                        {
354                            // non-positive targets of main spell return early
355                            for(int i = 0; i < 3; ++i)
356                            {
357                                // if non-positive trigger cast targeted to positive target this main cast is non-positive
358                                // this will place this spell auras as debuffs
359                                if(IsPositiveTarget(spellTriggeredProto->EffectImplicitTargetA[effIndex],spellTriggeredProto->EffectImplicitTargetB[effIndex]) && !IsPositiveEffect(spellTriggeredId,i))
360                                    return false;
361                            }
362                        }
363                    }
364                    break;
365                case SPELL_AURA_PROC_TRIGGER_SPELL:
366                    // many positive auras have negative triggered spells at damage for example and this not make it negative (it can be canceled for example)
367                    break;
368                case SPELL_AURA_MOD_STUN:                   //have positive and negative spells, we can't sort its correctly at this moment.
369                    if(effIndex==0 && spellproto->Effect[1]==0 && spellproto->Effect[2]==0)
370                        return false;                       // but all single stun aura spells is negative
371
372                    // Petrification
373                    if(spellproto->Id == 17624)
374                        return false;
375                    break;
376                case SPELL_AURA_MOD_ROOT:
377                case SPELL_AURA_MOD_SILENCE:
378                case SPELL_AURA_GHOST:
379                case SPELL_AURA_PERIODIC_LEECH:
380                case SPELL_AURA_MOD_PACIFY_SILENCE:
381                case SPELL_AURA_MOD_STALKED:
382                case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
383                    return false;
384                case SPELL_AURA_PERIODIC_DAMAGE:            // used in positive spells also.
385                    // part of negative spell if casted at self (prevent cancel)
386                    if(spellproto->EffectImplicitTargetA[effIndex] == TARGET_SELF)
387                        return false;
388                    break;
389                case SPELL_AURA_MOD_DECREASE_SPEED:         // used in positive spells also
390                    // part of positive spell if casted at self
391                    if(spellproto->EffectImplicitTargetA[effIndex] != TARGET_SELF)
392                        return false;
393                    // but not this if this first effect (don't found batter check)
394                    if(spellproto->Attributes & 0x4000000 && effIndex==0)
395                        return false;
396                    break;
397                case SPELL_AURA_TRANSFORM:
398                    // some spells negative
399                    switch(spellproto->Id)
400                    {
401                        case 36897:                         // Transporter Malfunction (race mutation to horde)
402                        case 36899:                         // Transporter Malfunction (race mutation to alliance)
403                            return false;
404                    }
405                    break;
406                case SPELL_AURA_MOD_SCALE:
407                    // some spells negative
408                    switch(spellproto->Id)
409                    {
410                        case 36900:                         // Soul Split: Evil!
411                        case 36901:                         // Soul Split: Good
412                        case 36893:                         // Transporter Malfunction (decrease size case)
413                        case 36895:                         // Transporter Malfunction (increase size case)
414                            return false;
415                    }
416                    break;
417                case SPELL_AURA_MECHANIC_IMMUNITY:
418                {
419                    // non-positive immunities
420                    switch(spellproto->EffectMiscValue[effIndex])
421                    {
422                        case MECHANIC_BANDAGE:
423                        case MECHANIC_SHIELD:
424                        case MECHANIC_MOUNT:
425                        case MECHANIC_INVULNERABILITY:
426                            return false;
427                        default:
428                            break;
429                    }
430                }   break;
431                case SPELL_AURA_ADD_FLAT_MODIFIER:          // mods
432                case SPELL_AURA_ADD_PCT_MODIFIER:
433                {
434                    // non-positive mods
435                    switch(spellproto->EffectMiscValue[effIndex])
436                    {
437                        case SPELLMOD_COST:                 // dependent from bas point sign (negative -> positive)
438                            if(spellproto->EffectBasePoints[effIndex]+int32(spellproto->EffectBaseDice[effIndex]) > 0)
439                                return false;
440                            break;
441                        default:
442                            break;
443                    }
444                }   break;
445                case SPELL_AURA_MOD_HEALING_PCT:
446                    if(spellproto->EffectBasePoints[effIndex]+int32(spellproto->EffectBaseDice[effIndex]) < 0)
447                        return false;
448                    break;
449                case SPELL_AURA_MOD_SKILL:
450                    if(spellproto->EffectBasePoints[effIndex]+int32(spellproto->EffectBaseDice[effIndex]) < 0)
451                        return false;
452                    break;
453                case SPELL_AURA_FORCE_REACTION:
454                    if(spellproto->Id==42792)               // Recently Dropped Flag (prevent cancel)
455                        return false;
456                    break;
457                default:
458                    break;
459            }
460            break;
461        }
462        default:
463            break;
464    }
465
466    // non-positive targets
467    if(!IsPositiveTarget(spellproto->EffectImplicitTargetA[effIndex],spellproto->EffectImplicitTargetB[effIndex]))
468        return false;
469
470    // AttributesEx check
471    if(spellproto->AttributesEx & (1<<7))
472        return false;
473
474    // ok, positive
475    return true;
476}
477
478bool IsPositiveSpell(uint32 spellId)
479{
480    SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
481    if (!spellproto) return false;
482
483    // spells with atleast one negative effect are considered negative
484    // some self-applied spells have negative effects but in self casting case negative check ignored.
485    for (int i = 0; i < 3; i++)
486        if (!IsPositiveEffect(spellId, i))
487            return false;
488    return true;
489}
490
491bool IsSingleTargetSpell(SpellEntry const *spellInfo)
492{
493    // all other single target spells have if it has AttributesEx5
494    if ( spellInfo->AttributesEx5 & SPELL_ATTR_EX5_SINGLE_TARGET_SPELL )
495        return true;
496
497    // TODO - need found Judgements rule
498    switch(GetSpellSpecific(spellInfo->Id))
499    {
500        case SPELL_JUDGEMENT:
501            return true;
502    }
503
504    // single target triggered spell.
505    // Not real client side single target spell, but it' not triggered until prev. aura expired.
506    // This is allow store it in single target spells list for caster for spell proc checking
507    if(spellInfo->Id==38324)                                // Regeneration (triggered by 38299 (HoTs on Heals))
508        return true;
509
510    return false;
511}
512
513bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellInfo2)
514{
515    // TODO - need better check
516    // Equal icon and spellfamily
517    if( spellInfo1->SpellFamilyName == spellInfo2->SpellFamilyName &&
518        spellInfo1->SpellIconID == spellInfo2->SpellIconID )
519        return true;
520
521    // TODO - need found Judgements rule
522    SpellSpecific spec1 = GetSpellSpecific(spellInfo1->Id);
523    // spell with single target specific types
524    switch(spec1)
525    {
526        case SPELL_JUDGEMENT:
527            if(GetSpellSpecific(spellInfo2->Id) == spec1)
528                return true;
529            break;
530    }
531
532    return false;
533}
534
535uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
536{
537    // talents that learn spells can have stance requirements that need ignore
538    // (this requirement only for client-side stance show in talent description)
539    if( GetTalentSpellCost(spellInfo->Id) > 0 &&
540        (spellInfo->Effect[0]==SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[1]==SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[2]==SPELL_EFFECT_LEARN_SPELL) )
541        return 0;
542
543    uint32 stanceMask = (form ? 1 << (form - 1) : 0);
544
545    if (stanceMask & spellInfo->StancesNot)                 // can explicitly not be casted in this stance
546        return SPELL_FAILED_NOT_SHAPESHIFT;
547
548    if (stanceMask & spellInfo->Stances)                    // can explicitly be casted in this stance
549        return 0;
550
551    bool actAsShifted = false;
552    if (form > 0)
553    {
554        SpellShapeshiftEntry const *shapeInfo = sSpellShapeshiftStore.LookupEntry(form);
555        if (!shapeInfo)
556        {
557            sLog.outError("GetErrorAtShapeshiftedCast: unknown shapeshift %u", form);
558            return 0;
559        }
560        actAsShifted = !(shapeInfo->flags1 & 1);            // shapeshift acts as normal form for spells
561    }
562
563    if(actAsShifted)
564    {
565        if (spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) // not while shapeshifted
566            return SPELL_FAILED_NOT_SHAPESHIFT;
567        else if (spellInfo->Stances != 0)                   // needs other shapeshift
568            return SPELL_FAILED_ONLY_SHAPESHIFT;
569    }
570    else
571    {
572        // needs shapeshift
573        if(!(spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT) && spellInfo->Stances != 0)
574            return SPELL_FAILED_ONLY_SHAPESHIFT;
575    }
576
577    return 0;
578}
579
580void SpellMgr::LoadSpellTargetPositions()
581{
582    mSpellTargetPositions.clear();                                // need for reload case
583
584    uint32 count = 0;
585
586    //                                                0   1           2                  3                  4                  5
587    QueryResult *result = WorldDatabase.Query("SELECT id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM spell_target_position");
588    if( !result )
589    {
590
591        barGoLink bar( 1 );
592
593        bar.step();
594
595        sLog.outString();
596        sLog.outString( ">> Loaded %u spell target coordinates", count );
597        return;
598    }
599
600    barGoLink bar( result->GetRowCount() );
601
602    do
603    {
604        Field *fields = result->Fetch();
605
606        bar.step();
607
608        ++count;
609
610        uint32 Spell_ID = fields[0].GetUInt32();
611
612        SpellTargetPosition st;
613
614        st.target_mapId       = fields[1].GetUInt32();
615        st.target_X           = fields[2].GetFloat();
616        st.target_Y           = fields[3].GetFloat();
617        st.target_Z           = fields[4].GetFloat();
618        st.target_Orientation = fields[5].GetFloat();
619
620        SpellEntry const* spellInfo = sSpellStore.LookupEntry(Spell_ID);
621        if(!spellInfo)
622        {
623            sLog.outErrorDb("Spell (ID:%u) listed in `spell_target_position` does not exist.",Spell_ID);
624            continue;
625        }
626
627        bool found = false;
628        for(int i = 0; i < 3; ++i)
629        {
630            if( spellInfo->EffectImplicitTargetA[i]==TARGET_TABLE_X_Y_Z_COORDINATES || spellInfo->EffectImplicitTargetB[i]==TARGET_TABLE_X_Y_Z_COORDINATES )
631            {
632                found = true;
633                break;
634            }
635        }
636        if(!found)
637        {
638            sLog.outErrorDb("Spell (Id: %u) listed in `spell_target_position` does not have target TARGET_TABLE_X_Y_Z_COORDINATES (17).",Spell_ID);
639            continue;
640        }
641
642        MapEntry const* mapEntry = sMapStore.LookupEntry(st.target_mapId);
643        if(!mapEntry)
644        {
645            sLog.outErrorDb("Spell (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Spell_ID,st.target_mapId);
646            continue;
647        }
648
649        if(st.target_X==0 && st.target_Y==0 && st.target_Z==0)
650        {
651            sLog.outErrorDb("Spell (ID:%u) target coordinates not provided.",Spell_ID);
652            continue;
653        }
654
655        mSpellTargetPositions[Spell_ID] = st;
656
657    } while( result->NextRow() );
658
659    delete result;
660
661    sLog.outString();
662    sLog.outString( ">> Loaded %u spell teleport coordinates", count );
663}
664
665void SpellMgr::LoadSpellAffects()
666{
667    mSpellAffectMap.clear();                                // need for reload case
668
669    uint32 count = 0;
670
671    //                                                0      1         2
672    QueryResult *result = WorldDatabase.Query("SELECT entry, effectId, SpellFamilyMask FROM spell_affect");
673    if( !result )
674    {
675
676        barGoLink bar( 1 );
677
678        bar.step();
679
680        sLog.outString();
681        sLog.outString( ">> Loaded %u spell affect definitions", count );
682        return;
683    }
684
685    barGoLink bar( result->GetRowCount() );
686
687    do
688    {
689        Field *fields = result->Fetch();
690
691        bar.step();
692
693        uint16 entry = fields[0].GetUInt16();
694        uint8 effectId = fields[1].GetUInt8();
695
696        SpellEntry const* spellInfo = sSpellStore.LookupEntry(entry);
697
698        if (!spellInfo)
699        {
700            sLog.outErrorDb("Spell %u listed in `spell_affect` does not exist", entry);
701            continue;
702        }
703
704        if (effectId >= 3)
705        {
706            sLog.outErrorDb("Spell %u listed in `spell_affect` have invalid effect index (%u)", entry,effectId);
707            continue;
708        }
709
710        if( spellInfo->Effect[effectId] != SPELL_EFFECT_APPLY_AURA ||
711            spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_FLAT_MODIFIER &&
712            spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_PCT_MODIFIER  &&
713            spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_TARGET_TRIGGER )
714        {
715            sLog.outErrorDb("Spell %u listed in `spell_affect` have not SPELL_AURA_ADD_FLAT_MODIFIER (%u) or SPELL_AURA_ADD_PCT_MODIFIER (%u) or SPELL_AURA_ADD_TARGET_TRIGGER (%u) for effect index (%u)", entry,SPELL_AURA_ADD_FLAT_MODIFIER,SPELL_AURA_ADD_PCT_MODIFIER,SPELL_AURA_ADD_TARGET_TRIGGER,effectId);
716            continue;
717        }
718
719        uint64 spellAffectMask = fields[2].GetUInt64();
720
721        // Spell.dbc have own data for low part of SpellFamilyMask
722        if( spellInfo->EffectItemType[effectId])
723        {
724            if(spellInfo->EffectItemType[effectId] == spellAffectMask)
725            {
726                sLog.outErrorDb("Spell %u listed in `spell_affect` have redundant (same with EffectItemType%d) data for effect index (%u) and not needed, skipped.", entry,effectId+1,effectId);
727                continue;
728            }
729
730            // 24429 have wrong data in EffectItemType and overwrites by DB, possible bug in client
731            if(spellInfo->Id!=24429 && spellInfo->EffectItemType[effectId] != spellAffectMask)
732            {
733                sLog.outErrorDb("Spell %u listed in `spell_affect` have different low part from EffectItemType%d for effect index (%u) and not needed, skipped.", entry,effectId+1,effectId);
734                continue;
735            }
736        }
737
738        mSpellAffectMap.insert(SpellAffectMap::value_type((entry<<8) + effectId,spellAffectMask));
739
740        ++count;
741    } while( result->NextRow() );
742
743    delete result;
744
745    sLog.outString();
746    sLog.outString( ">> Loaded %u spell affect definitions", count );
747
748    for (uint32 id = 0; id < sSpellStore.GetNumRows(); ++id)
749    {
750        SpellEntry const* spellInfo = sSpellStore.LookupEntry(id);
751        if (!spellInfo)
752            continue;
753
754        for (int effectId = 0; effectId < 3; ++effectId)
755        {
756            if( spellInfo->Effect[effectId] != SPELL_EFFECT_APPLY_AURA ||
757                (spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_FLAT_MODIFIER &&
758                spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_PCT_MODIFIER  &&
759                spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_TARGET_TRIGGER) )
760                continue;
761
762            if(spellInfo->EffectItemType[effectId] != 0)
763                continue;
764
765            if(mSpellAffectMap.find((id<<8) + effectId) !=  mSpellAffectMap.end())
766                continue;
767
768            sLog.outErrorDb("Spell %u (%s) misses spell_affect for effect %u",id,spellInfo->SpellName[sWorld.GetDefaultDbcLocale()], effectId);
769        }
770    }
771}
772
773bool SpellMgr::IsAffectedBySpell(SpellEntry const *spellInfo, uint32 spellId, uint8 effectId, uint64 familyFlags) const
774{
775    // false for spellInfo == NULL
776    if (!spellInfo)
777        return false;
778
779    SpellEntry const *affect_spell = sSpellStore.LookupEntry(spellId);
780    // false for affect_spell == NULL
781    if (!affect_spell)
782        return false;
783
784    // False if spellFamily not equal
785    if (affect_spell->SpellFamilyName != spellInfo->SpellFamilyName)
786        return false;
787
788    // If familyFlags == 0
789    if (!familyFlags)
790    {
791        // Get it from spellAffect table
792        familyFlags = GetSpellAffectMask(spellId,effectId);
793        // false if familyFlags == 0
794        if (!familyFlags)
795            return false;
796    }
797
798    // true
799    if (familyFlags & spellInfo->SpellFamilyFlags)
800        return true;
801
802    return false;
803}
804
805void SpellMgr::LoadSpellProcEvents()
806{
807    mSpellProcEventMap.clear();                             // need for reload case
808
809    uint32 count = 0;
810
811    //                                                0      1           2         3        4                5                6          7        8
812    QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, Category, SkillID, SpellFamilyName, SpellFamilyMask, procFlags, ppmRate, cooldown FROM spell_proc_event");
813    if( !result )
814    {
815
816        barGoLink bar( 1 );
817
818        bar.step();
819
820        sLog.outString();
821        sLog.outString( ">> Loaded %u spell proc event conditions", count  );
822        return;
823    }
824
825    barGoLink bar( result->GetRowCount() );
826
827    do
828    {
829        Field *fields = result->Fetch();
830
831        bar.step();
832
833        uint16 entry = fields[0].GetUInt16();
834
835        if (!sSpellStore.LookupEntry(entry))
836        {
837            sLog.outErrorDb("Spell %u listed in `spell_proc_event` does not exist", entry);
838            continue;
839        }
840
841        SpellProcEventEntry spe;
842
843        spe.schoolMask      = fields[1].GetUInt32();
844        spe.category        = fields[2].GetUInt32();
845        spe.skillId         = fields[3].GetUInt32();
846        spe.spellFamilyName = fields[4].GetUInt32();
847        spe.spellFamilyMask = fields[5].GetUInt64();
848        spe.procFlags       = fields[6].GetUInt32();
849        spe.ppmRate         = fields[7].GetFloat();
850        spe.cooldown        = fields[8].GetUInt32();
851
852        mSpellProcEventMap[entry] = spe;
853
854        ++count;
855    } while( result->NextRow() );
856
857    delete result;
858
859    sLog.outString();
860    sLog.outString( ">> Loaded %u spell proc event conditions", count  );
861
862    /*
863    // Commented for now, as it still produces many errors (still quite many spells miss spell_proc_event)
864    for (uint32 id = 0; id < sSpellStore.GetNumRows(); ++id)
865    {
866        SpellEntry const* spellInfo = sSpellStore.LookupEntry(id);
867        if (!spellInfo)
868            continue;
869
870        bool found = false;
871        for (int effectId = 0; effectId < 3; ++effectId)
872        {
873            // at this moment check only SPELL_AURA_PROC_TRIGGER_SPELL
874            if( spellInfo->EffectApplyAuraName[effectId] == SPELL_AURA_PROC_TRIGGER_SPELL )
875            {
876                found = true;
877                break;
878            }
879        }
880
881        if(!found)
882            continue;
883
884        if(GetSpellProcEvent(id))
885            continue;
886
887        sLog.outErrorDb("Spell %u (%s) misses spell_proc_event",id,spellInfo->SpellName[sWorld.GetDBClang()]);
888    }
889    */
890}
891
892bool SpellMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags )
893{
894    if((procFlags & spellProcEvent->procFlags) == 0)
895        return false;
896
897    // Additional checks in case spell cast/hit/crit is the event
898    // Check (if set) school, category, skill line, spell talent mask
899    if(spellProcEvent->schoolMask && (!procSpell || (GetSpellSchoolMask(procSpell) & spellProcEvent->schoolMask) == 0))
900        return false;
901    if(spellProcEvent->category && (!procSpell || procSpell->Category != spellProcEvent->category))
902        return false;
903    if(spellProcEvent->skillId)
904    {
905        if (!procSpell)
906            return false;
907
908        SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(procSpell->Id);
909        SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(procSpell->Id);
910
911        bool found = false;
912        for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
913        {
914            if(_spell_idx->second->skillId == spellProcEvent->skillId)
915            {
916                found = true;
917                break;
918            }
919        }
920        if (!found)
921            return false;
922    }
923    if(spellProcEvent->spellFamilyName && (!procSpell || spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
924        return false;
925    if(spellProcEvent->spellFamilyMask && (!procSpell || (spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0))
926        return false;
927
928    return true;
929}
930
931void SpellMgr::LoadSpellElixirs()
932{
933    mSpellElixirs.clear();                                  // need for reload case
934
935    uint32 count = 0;
936
937    //                                                0      1
938    QueryResult *result = WorldDatabase.Query("SELECT entry, mask FROM spell_elixir");
939    if( !result )
940    {
941
942        barGoLink bar( 1 );
943
944        bar.step();
945
946        sLog.outString();
947        sLog.outString( ">> Loaded %u spell elixir definitions", count );
948        return;
949    }
950
951    barGoLink bar( result->GetRowCount() );
952
953    do
954    {
955        Field *fields = result->Fetch();
956
957        bar.step();
958
959        uint16 entry = fields[0].GetUInt16();
960        uint8 mask = fields[1].GetUInt8();
961
962        SpellEntry const* spellInfo = sSpellStore.LookupEntry(entry);
963
964        if (!spellInfo)
965        {
966            sLog.outErrorDb("Spell %u listed in `spell_elixir` does not exist", entry);
967            continue;
968        }
969
970        mSpellElixirs[entry] = mask;
971
972        ++count;
973    } while( result->NextRow() );
974
975    delete result;
976
977    sLog.outString();
978    sLog.outString( ">> Loaded %u spell elixir definitions", count );
979}
980
981void SpellMgr::LoadSpellThreats()
982{
983    sSpellThreatStore.Free();                               // for reload
984
985    sSpellThreatStore.Load();
986
987    sLog.outString( ">> Loaded %u aggro generating spells", sSpellThreatStore.RecordCount );
988    sLog.outString();
989}
990
991bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellId_2) const
992{
993    SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
994    if(!spellInfo_1 || !spellInfo_2) return false;
995    if(spellInfo_1->Id == spellId_2) return false;
996
997    return GetFirstSpellInChain(spellInfo_1->Id)==GetFirstSpellInChain(spellId_2);
998}
999
1000bool SpellMgr::canStackSpellRanks(SpellEntry const *spellInfo)
1001{
1002    if(spellInfo->powerType != POWER_MANA && spellInfo->powerType != POWER_HEALTH)
1003        return false;
1004    if(IsProfessionSpell(spellInfo->Id))
1005        return false;
1006
1007    // All stance spells. if any better way, change it.
1008    for (int i = 0; i < 3; i++)
1009    {
1010        // Paladin aura Spell
1011        if(spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN
1012            && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AREA_AURA_PARTY)
1013            return false;
1014        // Druid form Spell
1015        if(spellInfo->SpellFamilyName == SPELLFAMILY_DRUID
1016            && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA
1017            && spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
1018            return false;
1019        // Rogue Stealth
1020        if(spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE
1021            && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA
1022            && spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
1023            return false;
1024    }
1025    return true;
1026}
1027
1028bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) const
1029{
1030    SpellEntry const *spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
1031    SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
1032
1033    if(!spellInfo_1 || !spellInfo_2)
1034        return false;
1035
1036    if(spellInfo_1->Id == spellId_2) //checked before
1037        return false;
1038
1039    if(spellInfo_1->SpellFamilyName && spellInfo_1->SpellFamilyName == spellInfo_2->SpellFamilyName) //resurrection sickness
1040    {
1041        if(spellInfo_1->SpellFamilyFlags && spellInfo_1->SpellFamilyFlags == spellInfo_2->SpellFamilyFlags)
1042            return true;
1043        if(spellInfo_1->SpellFamilyName == SPELLFAMILY_SHAMAN)
1044            if(IsElementalShield(spellInfo_1) && IsElementalShield(spellInfo_2))
1045                return true;
1046        //Corruption & Seed of corruption
1047        if(spellInfo_1->SpellFamilyName == SPELLFAMILY_WARLOCK)
1048            if( spellInfo_1->SpellIconID == 313 && spellInfo_2->SpellIconID == 1932 ||
1049                spellInfo_2->SpellIconID == 313 && spellInfo_1->SpellIconID == 1932 )
1050                if(spellInfo_1->SpellVisual != 0 && spellInfo_2->SpellVisual != 0)
1051                    return true;                        // can't be stacked
1052    }
1053
1054    //I think we don't check this correctly because i need a exception for spell:
1055    //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.
1056    //if(spellInfo_2->SpellFamilyFlags == 2048)
1057    //    return false;
1058
1059    // Resurrection sickness
1060    //if((spellInfo_1->Id == SPELL_ID_PASSIVE_RESURRECTION_SICKNESS) != (spellInfo_2->Id==SPELL_ID_PASSIVE_RESURRECTION_SICKNESS))
1061    //    return false;
1062
1063    // Specific spell family spells
1064    /*switch(spellInfo_1->SpellFamilyName)
1065    {
1066        case SPELLFAMILY_GENERIC:
1067            switch(spellInfo_2->SpellFamilyName)
1068            {
1069                case SPELLFAMILY_GENERIC:                   // same family case
1070                {
1071                    // Thunderfury
1072                    if( spellInfo_1->Id == 21992 && spellInfo_2->Id == 27648 || spellInfo_2->Id == 21992 && spellInfo_1->Id == 27648 )
1073                        return false;
1074
1075                    // Lightning Speed (Mongoose) and Fury of the Crashing Waves (Tsunami Talisman)
1076                    if( spellInfo_1->Id == 28093 && spellInfo_2->Id == 42084 ||
1077                        spellInfo_2->Id == 28093 && spellInfo_1->Id == 42084 )
1078                        return false;
1079
1080                    // Soulstone Resurrection and Twisting Nether (resurrector)
1081                    if( spellInfo_1->SpellIconID == 92 && spellInfo_2->SpellIconID == 92 && (
1082                        spellInfo_1->SpellVisual == 99 && spellInfo_2->SpellVisual == 0 ||
1083                        spellInfo_2->SpellVisual == 99 && spellInfo_1->SpellVisual == 0 ) )
1084                        return false;
1085
1086                    // Heart of the Wild and (Primal Instinct (Idol of Terror) triggering spell or Agility)
1087                    if( spellInfo_1->SpellIconID == 240 && spellInfo_2->SpellIconID == 240 && (
1088                        spellInfo_1->SpellVisual == 0 && spellInfo_2->SpellVisual == 78 ||
1089                        spellInfo_2->SpellVisual == 0 && spellInfo_1->SpellVisual == 78 ) )
1090                        return false;
1091
1092                    // Personalized Weather (thunder effect should overwrite rainy aura)
1093                    if(spellInfo_1->SpellIconID == 2606 && spellInfo_2->SpellIconID == 2606)
1094                        return false;
1095
1096                    // Brood Affliction: Bronze
1097                    if( (spellInfo_1->Id == 23170 && spellInfo_2->Id == 23171) ||
1098                        (spellInfo_2->Id == 23170 && spellInfo_1->Id == 23171) )
1099                        return false;
1100
1101                    break;
1102                }
1103                case SPELLFAMILY_WARRIOR:
1104                {
1105                    // Scroll of Protection and Defensive Stance (multi-family check)
1106                    if( spellInfo_1->SpellIconID == 276 && spellInfo_1->SpellVisual == 196 && spellInfo_2->Id == 71)
1107                        return false;
1108
1109                    // Improved Hamstring -> Hamstring (multi-family check)
1110                    if( (spellInfo_2->SpellFamilyFlags & 2) && spellInfo_1->Id == 23694 )
1111                        return false;
1112
1113                    break;
1114                }
1115                case SPELLFAMILY_DRUID:
1116                {
1117                    // Scroll of Stamina and Leader of the Pack (multi-family check)
1118                    if( spellInfo_1->SpellIconID == 312 && spellInfo_1->SpellVisual == 216 && spellInfo_2->Id == 24932 )
1119                        return false;
1120
1121                    // Dragonmaw Illusion (multi-family check)
1122                    if (spellId_1 == 40216 && spellId_2 == 42016 )
1123                        return false;
1124
1125                    break;
1126                }
1127                case SPELLFAMILY_ROGUE:
1128                {
1129                    // Garrote-Silence -> Garrote (multi-family check)
1130                    if( spellInfo_1->SpellIconID == 498 && spellInfo_1->SpellVisual == 0 && spellInfo_2->SpellIconID == 498  )
1131                        return false;
1132
1133                    break;
1134                }
1135                case SPELLFAMILY_HUNTER:
1136                {
1137                    // Concussive Shot and Imp. Concussive Shot (multi-family check)
1138                    if( spellInfo_1->Id == 19410 && spellInfo_2->Id == 5116 )
1139                        return false;
1140
1141                    // Improved Wing Clip -> Wing Clip (multi-family check)
1142                    if( (spellInfo_2->SpellFamilyFlags & 0x40) && spellInfo_1->Id == 19229 )
1143                        return false;
1144                    break;
1145                }
1146                case SPELLFAMILY_PALADIN:
1147                {
1148                    // Unstable Currents and other -> *Sanctity Aura (multi-family check)
1149                    if( spellInfo_2->SpellIconID==502 && spellInfo_1->SpellIconID==502 && spellInfo_1->SpellVisual==969 )
1150                        return false;
1151
1152                    // *Band of Eternal Champion and Seal of Command(multi-family check)
1153                    if( spellId_1 == 35081 && spellInfo_2->SpellIconID==561 && spellInfo_2->SpellVisual==7992)
1154                        return false;
1155
1156                    break;
1157                }
1158            }
1159            break;
1160        case SPELLFAMILY_MAGE:
1161            if( spellInfo_2->SpellFamilyName == SPELLFAMILY_MAGE )
1162            {
1163                // Blizzard & Chilled (and some other stacked with blizzard spells
1164                if( (spellInfo_1->SpellFamilyFlags & 0x80) && (spellInfo_2->SpellFamilyFlags & 0x100000) ||
1165                    (spellInfo_2->SpellFamilyFlags & 0x80) && (spellInfo_1->SpellFamilyFlags & 0x100000) )
1166                    return false;
1167
1168                // Blink & Improved Blink
1169                if( (spellInfo_1->SpellFamilyFlags & 0x0000000000010000LL) && (spellInfo_2->SpellVisual == 72 && spellInfo_2->SpellIconID == 1499) ||
1170                    (spellInfo_2->SpellFamilyFlags & 0x0000000000010000LL) && (spellInfo_1->SpellVisual == 72 && spellInfo_1->SpellIconID == 1499) )
1171                    return false;
1172            }
1173            // Detect Invisibility and Mana Shield (multi-family check)
1174            if( spellInfo_2->Id == 132 && spellInfo_1->SpellIconID == 209 && spellInfo_1->SpellVisual == 968 )
1175                return false;
1176
1177            // Combustion and Fire Protection Aura (multi-family check)
1178            if( spellInfo_1->Id == 11129 && spellInfo_2->SpellIconID == 33 && spellInfo_2->SpellVisual == 321 )
1179                return false;
1180
1181            break;
1182        case SPELLFAMILY_WARLOCK:
1183            if( spellInfo_2->SpellFamilyName == SPELLFAMILY_WARLOCK )
1184            {
1185                // Siphon Life and Drain Life
1186                if( spellInfo_1->SpellIconID == 152 && spellInfo_2->SpellIconID == 546 ||
1187                    spellInfo_2->SpellIconID == 152 && spellInfo_1->SpellIconID == 546 )
1188                    return false;
1189
1190                //Corruption & Seed of corruption
1191                if( spellInfo_1->SpellIconID == 313 && spellInfo_2->SpellIconID == 1932 ||
1192                    spellInfo_2->SpellIconID == 313 && spellInfo_1->SpellIconID == 1932 )
1193                    if(spellInfo_1->SpellVisual != 0 && spellInfo_2->SpellVisual != 0)
1194                        return true;                        // can't be stacked
1195
1196                // Corruption and Unstable Affliction
1197                if( spellInfo_1->SpellIconID == 313 && spellInfo_2->SpellIconID == 2039 ||
1198                    spellInfo_2->SpellIconID == 313 && spellInfo_1->SpellIconID == 2039 )
1199                    return false;
1200
1201                // (Corruption or Unstable Affliction) and (Curse of Agony or Curse of Doom)
1202                if( (spellInfo_1->SpellIconID == 313 || spellInfo_1->SpellIconID == 2039) && (spellInfo_2->SpellIconID == 544  || spellInfo_2->SpellIconID == 91) ||
1203                    (spellInfo_2->SpellIconID == 313 || spellInfo_2->SpellIconID == 2039) && (spellInfo_1->SpellIconID == 544  || spellInfo_1->SpellIconID == 91) )
1204                    return false;
1205            }
1206            // Detect Invisibility and Mana Shield (multi-family check)
1207            if( spellInfo_1->Id == 132 && spellInfo_2->SpellIconID == 209 && spellInfo_2->SpellVisual == 968 )
1208                return false;
1209            break;
1210        case SPELLFAMILY_WARRIOR:
1211            if( spellInfo_2->SpellFamilyName == SPELLFAMILY_WARRIOR )
1212            {
1213                // Rend and Deep Wound
1214                if( (spellInfo_1->SpellFamilyFlags & 0x20) && (spellInfo_2->SpellFamilyFlags & 0x1000000000LL) ||
1215                    (spellInfo_2->SpellFamilyFlags & 0x20) && (spellInfo_1->SpellFamilyFlags & 0x1000000000LL) )
1216                    return false;
1217
1218                // Battle Shout and Rampage
1219                if( (spellInfo_1->SpellIconID == 456 && spellInfo_2->SpellIconID == 2006) ||
1220                    (spellInfo_2->SpellIconID == 456 && spellInfo_1->SpellIconID == 2006) )
1221                    return false;
1222            }
1223
1224            // Hamstring -> Improved Hamstring (multi-family check)
1225            if( (spellInfo_1->SpellFamilyFlags & 2) && spellInfo_2->Id == 23694 )
1226                return false;
1227
1228            // Defensive Stance and Scroll of Protection (multi-family check)
1229            if( spellInfo_1->Id == 71 && spellInfo_2->SpellIconID == 276 && spellInfo_2->SpellVisual == 196 )
1230                return false;
1231
1232            // Bloodlust and Bloodthirst (multi-family check)
1233            if( spellInfo_2->Id == 2825 && spellInfo_1->SpellIconID == 38 && spellInfo_1->SpellVisual == 0 )
1234                return false;
1235
1236            break;
1237        case SPELLFAMILY_PRIEST:
1238            if( spellInfo_2->SpellFamilyName == SPELLFAMILY_PRIEST )
1239            {
1240                //Devouring Plague and Shadow Vulnerability
1241                if( (spellInfo_1->SpellFamilyFlags & 0x2000000) && (spellInfo_2->SpellFamilyFlags & 0x800000000LL) ||
1242                    (spellInfo_2->SpellFamilyFlags & 0x2000000) && (spellInfo_1->SpellFamilyFlags & 0x800000000LL) )
1243                    return false;
1244
1245                //StarShards and Shadow Word: Pain
1246                if( (spellInfo_1->SpellFamilyFlags & 0x200000) && (spellInfo_2->SpellFamilyFlags & 0x8000) ||
1247                    (spellInfo_2->SpellFamilyFlags & 0x200000) && (spellInfo_1->SpellFamilyFlags & 0x8000) )
1248                    return false;
1249            }
1250            break;
1251        case SPELLFAMILY_DRUID:
1252            if( spellInfo_2->SpellFamilyName == SPELLFAMILY_DRUID )
1253            {
1254                //Omen of Clarity and Blood Frenzy
1255                if( (spellInfo_1->SpellFamilyFlags == 0x0 && spellInfo_1->SpellIconID == 108) && (spellInfo_2->SpellFamilyFlags & 0x20000000000000LL) ||
1256                    (spellInfo_2->SpellFamilyFlags == 0x0 && spellInfo_2->SpellIconID == 108) && (spellInfo_1->SpellFamilyFlags & 0x20000000000000LL) )
1257                    return false;
1258
1259                //  Tree of Life (Shapeshift) and 34123 Tree of Life (Passive)
1260                if ((spellId_1 == 33891 && spellId_2 == 34123) ||
1261                    (spellId_2 == 33891 && spellId_1 == 34123))
1262                    return false;
1263
1264                // Wrath of Elune and Nature's Grace
1265                if( spellInfo_1->Id == 16886 && spellInfo_2->Id == 46833 || spellInfo_2->Id == 16886 && spellInfo_1->Id == 46833 )
1266                    return false;
1267
1268                // Bear Rage (Feral T4 (2)) and Omen of Clarity
1269                if( spellInfo_1->Id == 16864 && spellInfo_2->Id == 37306 || spellInfo_2->Id == 16864 && spellInfo_1->Id == 37306 )
1270                    return false;
1271
1272                // Cat Energy (Feral T4 (2)) and Omen of Clarity
1273                if( spellInfo_1->Id == 16864 && spellInfo_2->Id == 37311 || spellInfo_2->Id == 16864 && spellInfo_1->Id == 37311 )
1274                    return false;
1275            }
1276
1277            // Leader of the Pack and Scroll of Stamina (multi-family check)
1278            if( spellInfo_1->Id == 24932 && spellInfo_2->SpellIconID == 312 && spellInfo_2->SpellVisual == 216 )
1279                return false;
1280
1281            // Dragonmaw Illusion (multi-family check)
1282            if (spellId_1 == 42016 && spellId_2 == 40216 )
1283                return false;
1284
1285            break;
1286        case SPELLFAMILY_ROGUE:
1287            if( spellInfo_2->SpellFamilyName == SPELLFAMILY_ROGUE )
1288            {
1289                // Master of Subtlety
1290                if (spellId_1 == 31665 && spellId_2 == 31666 || spellId_1 == 31666 && spellId_2 == 31665 )
1291                    return false;
1292            }
1293
1294            // Garrote -> Garrote-Silence (multi-family check)
1295            if( spellInfo_1->SpellIconID == 498 && spellInfo_2->SpellIconID == 498 && spellInfo_2->SpellVisual == 0 )
1296                return false;
1297            break;
1298        case SPELLFAMILY_HUNTER:
1299            if( spellInfo_2->SpellFamilyName == SPELLFAMILY_HUNTER )
1300            {
1301                // Rapid Fire & Quick Shots
1302                if( (spellInfo_1->SpellFamilyFlags & 0x20) && (spellInfo_2->SpellFamilyFlags & 0x20000000000LL) ||
1303                    (spellInfo_2->SpellFamilyFlags & 0x20) && (spellInfo_1->SpellFamilyFlags & 0x20000000000LL) )
1304                    return false;
1305
1306                // Serpent Sting & (Immolation/Explosive Trap Effect)
1307                if( (spellInfo_1->SpellFamilyFlags & 0x4) && (spellInfo_2->SpellFamilyFlags & 0x00000004000LL) ||
1308                    (spellInfo_2->SpellFamilyFlags & 0x4) && (spellInfo_1->SpellFamilyFlags & 0x00000004000LL) )
1309                    return false;
1310
1311                // Bestial Wrath
1312                if( spellInfo_1->SpellIconID == 1680 && spellInfo_2->SpellIconID == 1680 )
1313                    return false;
1314            }
1315
1316            // Wing Clip -> Improved Wing Clip (multi-family check)
1317            if( (spellInfo_1->SpellFamilyFlags & 0x40) && spellInfo_2->Id == 19229 )
1318                return false;
1319
1320            // Concussive Shot and Imp. Concussive Shot (multi-family check)
1321            if( spellInfo_2->Id == 19410 && spellInfo_1->Id == 5116 )
1322                return false;
1323            break;
1324        case SPELLFAMILY_PALADIN:
1325            if( spellInfo_2->SpellFamilyName == SPELLFAMILY_PALADIN )
1326            {
1327                // Paladin Seals
1328                if( IsSealSpell(spellInfo_1) && IsSealSpell(spellInfo_2) )
1329                    return true;
1330            }
1331            // Combustion and Fire Protection Aura (multi-family check)
1332            if( spellInfo_2->Id == 11129 && spellInfo_1->SpellIconID == 33 && spellInfo_1->SpellVisual == 321 )
1333                return false;
1334
1335            // *Sanctity Aura -> Unstable Currents and other (multi-family check)
1336            if( spellInfo_1->SpellIconID==502 && spellInfo_2->SpellFamilyName == SPELLFAMILY_GENERIC && spellInfo_2->SpellIconID==502 && spellInfo_2->SpellVisual==969 )
1337                return false;
1338
1339            // *Seal of Command and Band of Eternal Champion (multi-family check)
1340            if( spellInfo_1->SpellIconID==561 && spellInfo_1->SpellVisual==7992 && spellId_2 == 35081)
1341                return false;
1342            break;
1343        case SPELLFAMILY_SHAMAN:
1344            if( spellInfo_2->SpellFamilyName == SPELLFAMILY_SHAMAN )
1345            {
1346                // shaman shields
1347                if( IsElementalShield(spellInfo_1) && IsElementalShield(spellInfo_2) )
1348                    return true;
1349
1350                // Windfury weapon
1351                if( spellInfo_1->SpellIconID==220 && spellInfo_2->SpellIconID==220 &&
1352                    spellInfo_1->SpellFamilyFlags != spellInfo_2->SpellFamilyFlags )
1353                    return false;
1354            }
1355            // Bloodlust and Bloodthirst (multi-family check)
1356            if( spellInfo_1->Id == 2825 && spellInfo_2->SpellIconID == 38 && spellInfo_2->SpellVisual == 0 )
1357                return false;
1358            break;
1359        default:
1360            break;
1361    }
1362
1363    if (IsRankSpellDueToSpell(spellInfo_1, spellId_2))
1364        return true;*/
1365
1366    if (spellInfo_1->SpellIconID != spellInfo_2->SpellIconID
1367        || !spellInfo_1->SpellIconID)
1368        return false;
1369
1370    if (spellInfo_1->SpellFamilyName != spellInfo_2->SpellFamilyName)
1371        return false;
1372
1373    for (int i = 0; i < 3; ++i)
1374        if (spellInfo_1->Effect[i] != spellInfo_2->Effect[i] ||
1375        spellInfo_1->EffectItemType[i] != spellInfo_2->EffectItemType[i] ||
1376        spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i] ||
1377        spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i])
1378            return false;
1379
1380    return true;
1381}
1382
1383bool SpellMgr::IsProfessionSpell(uint32 spellId)
1384{
1385    SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
1386    if(!spellInfo)
1387        return false;
1388
1389    if(spellInfo->Effect[1] != SPELL_EFFECT_SKILL)
1390        return false;
1391
1392    uint32 skill = spellInfo->EffectMiscValue[1];
1393
1394    return IsProfessionSkill(skill);
1395}
1396
1397bool SpellMgr::IsPrimaryProfessionSpell(uint32 spellId)
1398{
1399    SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
1400    if(!spellInfo)
1401        return false;
1402
1403    if(spellInfo->Effect[1] != SPELL_EFFECT_SKILL)
1404        return false;
1405
1406    uint32 skill = spellInfo->EffectMiscValue[1];
1407
1408    return IsPrimaryProfessionSkill(skill);
1409}
1410
1411bool SpellMgr::IsPrimaryProfessionFirstRankSpell(uint32 spellId) const
1412{
1413    return IsPrimaryProfessionSpell(spellId) && GetSpellRank(spellId)==1;
1414}
1415
1416SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spellInfo, uint32 playerLevel) const
1417{
1418    // ignore passive spells
1419    if(IsPassiveSpell(spellInfo->Id))
1420        return spellInfo;
1421
1422    bool needRankSelection = false;
1423    for(int i=0;i<3;i++)
1424    {
1425        if( IsPositiveEffect(spellInfo->Id, i) && (
1426            spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA ||
1427            spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY
1428            ) )
1429        {
1430            needRankSelection = true;
1431            break;
1432        }
1433    }
1434
1435    // not required
1436    if(!needRankSelection)
1437        return spellInfo;
1438
1439    for(uint32 nextSpellId = spellInfo->Id; nextSpellId != 0; nextSpellId = GetPrevSpellInChain(nextSpellId))
1440    {
1441        SpellEntry const *nextSpellInfo = sSpellStore.LookupEntry(nextSpellId);
1442        if(!nextSpellInfo)
1443            break;
1444
1445        // if found appropriate level
1446        if(playerLevel + 10 >= nextSpellInfo->spellLevel)
1447            return nextSpellInfo;
1448
1449        // one rank less then
1450    }
1451
1452    // not found
1453    return NULL;
1454}
1455
1456void SpellMgr::LoadSpellChains()
1457{
1458    mSpellChains.clear();                                   // need for reload case
1459    mSpellChainsNext.clear();                               // need for reload case
1460
1461    QueryResult *result = WorldDatabase.PQuery("SELECT spell_id, prev_spell, first_spell, rank, req_spell FROM spell_chain");
1462    if(result == NULL)
1463    {
1464        barGoLink bar( 1 );
1465        bar.step();
1466
1467        sLog.outString();
1468        sLog.outString( ">> Loaded 0 spell chain records" );
1469        sLog.outErrorDb("`spell_chains` table is empty!");
1470        return;
1471    }
1472
1473    uint32 count = 0;
1474
1475    barGoLink bar( result->GetRowCount() );
1476    do
1477    {
1478        bar.step();
1479        Field *fields = result->Fetch();
1480
1481        uint32 spell_id = fields[0].GetUInt32();
1482
1483        SpellChainNode node;
1484        node.prev  = fields[1].GetUInt32();
1485        node.first = fields[2].GetUInt32();
1486        node.rank  = fields[3].GetUInt8();
1487        node.req   = fields[4].GetUInt32();
1488
1489        if(!sSpellStore.LookupEntry(spell_id))
1490        {
1491            sLog.outErrorDb("Spell %u listed in `spell_chain` does not exist",spell_id);
1492            continue;
1493        }
1494
1495        if(node.prev!=0 && !sSpellStore.LookupEntry(node.prev))
1496        {
1497            sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not existed previous rank spell.",
1498                spell_id,node.prev,node.first,node.rank,node.req);
1499            continue;
1500        }
1501
1502        if(!sSpellStore.LookupEntry(node.first))
1503        {
1504            sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not existing first rank spell.",
1505                spell_id,node.prev,node.first,node.rank,node.req);
1506            continue;
1507        }
1508
1509        // check basic spell chain data integrity (note: rank can be equal 0 or 1 for first/single spell)
1510        if( (spell_id == node.first) != (node.rank <= 1) ||
1511            (spell_id == node.first) != (node.prev == 0) ||
1512            (node.rank <= 1) != (node.prev == 0) )
1513        {
1514            sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not compatible chain data.",
1515                spell_id,node.prev,node.first,node.rank,node.req);
1516            continue;
1517        }
1518
1519        if(node.req!=0 && !sSpellStore.LookupEntry(node.req))
1520        {
1521            sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not existing required spell.",
1522                spell_id,node.prev,node.first,node.rank,node.req);
1523            continue;
1524        }
1525
1526        // talents not required data in spell chain for work, but must be checked if present for intergrity
1527        if(TalentSpellPos const* pos = GetTalentSpellPos(spell_id))
1528        {
1529            if(node.rank!=pos->rank+1)
1530            {
1531                sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong rank.",
1532                    spell_id,node.prev,node.first,node.rank,node.req);
1533                continue;
1534            }
1535
1536            if(TalentEntry const* talentEntry = sTalentStore.LookupEntry(pos->talent_id))
1537            {
1538                if(node.first!=talentEntry->RankID[0])
1539                {
1540                    sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong first rank spell.",
1541                        spell_id,node.prev,node.first,node.rank,node.req);
1542                    continue;
1543                }
1544
1545                if(node.rank > 1 && node.prev != talentEntry->RankID[node.rank-1-1])
1546                {
1547                    sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong prev rank spell.",
1548                        spell_id,node.prev,node.first,node.rank,node.req);
1549                    continue;
1550                }
1551
1552                if(node.req!=talentEntry->DependsOnSpell)
1553                {
1554                    sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong required spell.",
1555                        spell_id,node.prev,node.first,node.rank,node.req);
1556                    continue;
1557                }
1558            }
1559        }
1560
1561        mSpellChains[spell_id] = node;
1562
1563        if(node.prev)
1564            mSpellChainsNext.insert(SpellChainMapNext::value_type(node.prev,spell_id));
1565
1566        if(node.req)
1567            mSpellChainsNext.insert(SpellChainMapNext::value_type(node.req,spell_id));
1568
1569        ++count;
1570    } while( result->NextRow() );
1571
1572    // additional integrity checks
1573    for(SpellChainMap::iterator i = mSpellChains.begin(); i != mSpellChains.end(); ++i)
1574    {
1575        if(i->second.prev)
1576        {
1577            SpellChainMap::iterator i_prev = mSpellChains.find(i->second.prev);
1578            if(i_prev == mSpellChains.end())
1579            {
1580                sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not found previous rank spell in table.",
1581                    i->first,i->second.prev,i->second.first,i->second.rank,i->second.req);
1582            }
1583            else if( i_prev->second.first != i->second.first )
1584            {
1585                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).",
1586                    i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
1587                    i_prev->second.prev,i_prev->second.first,i_prev->second.rank,i_prev->second.req);
1588            }
1589            else if( i_prev->second.rank+1 != i->second.rank )
1590            {
1591                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).",
1592                    i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
1593                    i_prev->second.prev,i_prev->second.first,i_prev->second.rank,i_prev->second.req);
1594            }
1595        }
1596
1597        if(i->second.req)
1598        {
1599            SpellChainMap::iterator i_req = mSpellChains.find(i->second.req);
1600            if(i_req == mSpellChains.end())
1601            {
1602                sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not found required rank spell in table.",
1603                    i->first,i->second.prev,i->second.first,i->second.rank,i->second.req);
1604            }
1605            else if( i_req->second.first == i->second.first )
1606            {
1607                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).",
1608                    i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
1609                    i_req->second.prev,i_req->second.first,i_req->second.rank,i_req->second.req);
1610            }
1611            else if( i_req->second.req )
1612            {
1613                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).",
1614                    i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
1615                    i_req->second.prev,i_req->second.first,i_req->second.rank,i_req->second.req);
1616            }
1617        }
1618    }
1619
1620    delete result;
1621
1622    sLog.outString();
1623    sLog.outString( ">> Loaded %u spell chain records", count );
1624}
1625
1626void SpellMgr::LoadSpellLearnSkills()
1627{
1628    mSpellLearnSkills.clear();                              // need for reload case
1629
1630    // search auto-learned skills and add its to map also for use in unlearn spells/talents
1631    uint32 dbc_count = 0;
1632    for(uint32 spell = 0; spell < sSpellStore.GetNumRows(); ++spell)
1633    {
1634        SpellEntry const* entry = sSpellStore.LookupEntry(spell);
1635
1636        if(!entry)
1637            continue;
1638
1639        for(int i = 0; i < 3; ++i)
1640        {
1641            if(entry->Effect[i]==SPELL_EFFECT_SKILL)
1642            {
1643                SpellLearnSkillNode dbc_node;
1644                dbc_node.skill    = entry->EffectMiscValue[i];
1645                if ( dbc_node.skill != SKILL_RIDING )
1646                    dbc_node.value    = 1;
1647                else
1648                    dbc_node.value    = (entry->EffectBasePoints[i]+1)*75;
1649                dbc_node.maxvalue = (entry->EffectBasePoints[i]+1)*75;
1650
1651                SpellLearnSkillNode const* db_node = GetSpellLearnSkill(spell);
1652
1653                mSpellLearnSkills[spell] = dbc_node;
1654                ++dbc_count;
1655                break;
1656            }
1657        }
1658    }
1659
1660    sLog.outString();
1661    sLog.outString( ">> Loaded %u Spell Learn Skills from DBC", dbc_count );
1662}
1663
1664void SpellMgr::LoadSpellLearnSpells()
1665{
1666    mSpellLearnSpells.clear();                              // need for reload case
1667
1668    QueryResult *result = WorldDatabase.PQuery("SELECT entry, SpellID FROM spell_learn_spell");
1669    if(!result)
1670    {
1671        barGoLink bar( 1 );
1672        bar.step();
1673
1674        sLog.outString();
1675        sLog.outString( ">> Loaded 0 spell learn spells" );
1676        sLog.outErrorDb("`spell_learn_spell` table is empty!");
1677        return;
1678    }
1679
1680    uint32 count = 0;
1681
1682    barGoLink bar( result->GetRowCount() );
1683    do
1684    {
1685        bar.step();
1686        Field *fields = result->Fetch();
1687
1688        uint32 spell_id    = fields[0].GetUInt32();
1689
1690        SpellLearnSpellNode node;
1691        node.spell      = fields[1].GetUInt32();
1692        node.autoLearned= false;
1693
1694        if(!sSpellStore.LookupEntry(spell_id))
1695        {
1696            sLog.outErrorDb("Spell %u listed in `spell_learn_spell` does not exist",spell_id);
1697            continue;
1698        }
1699
1700        if(!sSpellStore.LookupEntry(node.spell))
1701        {
1702            sLog.outErrorDb("Spell %u listed in `spell_learn_spell` does not exist",node.spell);
1703            continue;
1704        }
1705
1706        mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell_id,node));
1707
1708        ++count;
1709    } while( result->NextRow() );
1710
1711    delete result;
1712
1713    // search auto-learned spells and add its to map also for use in unlearn spells/talents
1714    uint32 dbc_count = 0;
1715    for(uint32 spell = 0; spell < sSpellStore.GetNumRows(); ++spell)
1716    {
1717        SpellEntry const* entry = sSpellStore.LookupEntry(spell);
1718
1719        if(!entry)
1720            continue;
1721
1722        for(int i = 0; i < 3; ++i)
1723        {
1724            if(entry->Effect[i]==SPELL_EFFECT_LEARN_SPELL)
1725            {
1726                SpellLearnSpellNode dbc_node;
1727                dbc_node.spell       = entry->EffectTriggerSpell[i];
1728                dbc_node.autoLearned = true;
1729
1730                SpellLearnSpellMap::const_iterator db_node_begin = GetBeginSpellLearnSpell(spell);
1731                SpellLearnSpellMap::const_iterator db_node_end   = GetEndSpellLearnSpell(spell);
1732
1733                bool found = false;
1734                for(SpellLearnSpellMap::const_iterator itr = db_node_begin; itr != db_node_end; ++itr)
1735                {
1736                    if(itr->second.spell == dbc_node.spell)
1737                    {
1738                        sLog.outErrorDb("Spell %u auto-learn spell %u in spell.dbc then the record in `spell_learn_spell` is redundant, please fix DB.",
1739                            spell,dbc_node.spell);
1740                        found = true;
1741                        break;
1742                    }
1743                }
1744
1745                if(!found)                                  // add new spell-spell pair if not found
1746                {
1747                    mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell,dbc_node));
1748                    ++dbc_count;
1749                }
1750            }
1751        }
1752    }
1753
1754    sLog.outString();
1755    sLog.outString( ">> Loaded %u spell learn spells + %u found in DBC", count, dbc_count );
1756}
1757
1758void SpellMgr::LoadSpellScriptTarget()
1759{
1760    mSpellScriptTarget.clear();                             // need for reload case
1761
1762    uint32 count = 0;
1763
1764    QueryResult *result = WorldDatabase.Query("SELECT entry,type,targetEntry FROM spell_script_target");
1765
1766    if(!result)
1767    {
1768        barGoLink bar(1);
1769
1770        bar.step();
1771
1772        sLog.outString();
1773        sLog.outErrorDb(">> Loaded 0 SpellScriptTarget. DB table `spell_script_target` is empty.");
1774        return;
1775    }
1776
1777    barGoLink bar(result->GetRowCount());
1778
1779    do
1780    {
1781        Field *fields = result->Fetch();
1782        bar.step();
1783
1784        uint32 spellId     = fields[0].GetUInt32();
1785        uint32 type        = fields[1].GetUInt32();
1786        uint32 targetEntry = fields[2].GetUInt32();
1787
1788        SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId);
1789
1790        if(!spellProto)
1791        {
1792            sLog.outErrorDb("Table `spell_script_target`: spellId %u listed for TargetEntry %u does not exist.",spellId,targetEntry);
1793            continue;
1794        }
1795
1796        /*bool targetfound = false;
1797        for(int i = 0; i <3; ++i)
1798        {
1799            if( spellProto->EffectImplicitTargetA[i]==TARGET_SCRIPT ||
1800                spellProto->EffectImplicitTargetB[i]==TARGET_SCRIPT ||
1801                spellProto->EffectImplicitTargetA[i]==TARGET_SCRIPT_COORDINATES ||
1802                spellProto->EffectImplicitTargetB[i]==TARGET_SCRIPT_COORDINATES )
1803            {
1804                targetfound = true;
1805                break;
1806            }
1807        }
1808        if(!targetfound)
1809        {
1810            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);
1811            continue;
1812        }*/
1813
1814        if( type >= MAX_SPELL_TARGET_TYPE )
1815        {
1816            sLog.outErrorDb("Table `spell_script_target`: target type %u for TargetEntry %u is incorrect.",type,targetEntry);
1817            continue;
1818        }
1819
1820        switch(type)
1821        {
1822            case SPELL_TARGET_TYPE_GAMEOBJECT:
1823            {
1824                if( targetEntry==0 )
1825                    break;
1826
1827                if(!sGOStorage.LookupEntry<GameObjectInfo>(targetEntry))
1828                {
1829                    sLog.outErrorDb("Table `spell_script_target`: gameobject template entry %u does not exist.",targetEntry);
1830                    continue;
1831                }
1832                break;
1833            }
1834            default:
1835            {
1836                if( targetEntry==0 )
1837                {
1838                    sLog.outErrorDb("Table `spell_script_target`: target entry == 0 for not GO target type (%u).",type);
1839                    continue;
1840                }
1841                if(!sCreatureStorage.LookupEntry<CreatureInfo>(targetEntry))
1842                {
1843                    sLog.outErrorDb("Table `spell_script_target`: creature template entry %u does not exist.",targetEntry);
1844                    continue;
1845                }
1846                const CreatureInfo* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(targetEntry);
1847
1848                if(spellId == 30427 && !cInfo->SkinLootId)
1849                {
1850                    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);
1851                    continue;
1852                }
1853                break;
1854            }
1855        }
1856
1857        mSpellScriptTarget.insert(SpellScriptTarget::value_type(spellId,SpellTargetEntry(SpellTargetType(type),targetEntry)));
1858
1859        ++count;
1860    } while (result->NextRow());
1861
1862    delete result;
1863
1864    // Check all spells
1865    /* Disabled (lot errors at this moment)
1866    for(uint32 i = 1; i < sSpellStore.nCount; ++i)
1867    {
1868        SpellEntry const * spellInfo = sSpellStore.LookupEntry(i);
1869        if(!spellInfo)
1870            continue;
1871
1872        bool found = false;
1873        for(int j=0; j<3; ++j)
1874        {
1875            if( spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT || spellInfo->EffectImplicitTargetA[j] != TARGET_SELF && spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT )
1876            {
1877                SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(spellInfo->Id);
1878                SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(spellInfo->Id);
1879                if(lower==upper)
1880                {
1881                    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);
1882                    break;                                  // effects of spell
1883                }
1884            }
1885        }
1886    }
1887    */
1888
1889    sLog.outString();
1890    sLog.outString(">> Loaded %u Spell Script Targets", count);
1891}
1892
1893void SpellMgr::LoadSpellPetAuras()
1894{
1895    mSpellPetAuraMap.clear();                                  // need for reload case
1896
1897    uint32 count = 0;
1898
1899    //                                                0      1    2
1900    QueryResult *result = WorldDatabase.Query("SELECT spell, pet, aura FROM spell_pet_auras");
1901    if( !result )
1902    {
1903
1904        barGoLink bar( 1 );
1905
1906        bar.step();
1907
1908        sLog.outString();
1909        sLog.outString( ">> Loaded %u spell pet auras", count );
1910        return;
1911    }
1912
1913    barGoLink bar( result->GetRowCount() );
1914
1915    do
1916    {
1917        Field *fields = result->Fetch();
1918
1919        bar.step();
1920
1921        uint16 spell = fields[0].GetUInt16();
1922        uint16 pet = fields[1].GetUInt16();
1923        uint16 aura = fields[2].GetUInt16();
1924
1925        SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find(spell);
1926        if(itr != mSpellPetAuraMap.end())
1927        {
1928            itr->second.AddAura(pet, aura);
1929        }
1930        else
1931        {
1932            SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell);
1933            if (!spellInfo)
1934            {
1935                sLog.outErrorDb("Spell %u listed in `spell_pet_auras` does not exist", spell);
1936                continue;
1937            }
1938            int i = 0;
1939            for(; i < 3; ++i)
1940                if((spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA &&
1941                    spellInfo->EffectApplyAuraName[i] == SPELL_AURA_DUMMY) ||
1942                    spellInfo->Effect[i] == SPELL_EFFECT_DUMMY)
1943                    break;
1944
1945            if(i == 3)
1946            {
1947                sLog.outError("Spell %u listed in `spell_pet_auras` does not have dummy aura or dummy effect", spell);
1948                continue;
1949            }
1950
1951            SpellEntry const* spellInfo2 = sSpellStore.LookupEntry(aura);
1952            if (!spellInfo2)
1953            {
1954                sLog.outErrorDb("Aura %u listed in `spell_pet_auras` does not exist", aura);
1955                continue;
1956            }
1957
1958            PetAura pa(pet, aura, spellInfo->EffectImplicitTargetA[i] == TARGET_PET, spellInfo->EffectBasePoints[i] + spellInfo->EffectBaseDice[i]);
1959            mSpellPetAuraMap[spell] = pa;
1960        }
1961
1962        ++count;
1963    } while( result->NextRow() );
1964
1965    delete result;
1966
1967    sLog.outString();
1968    sLog.outString( ">> Loaded %u spell pet auras", count );
1969}
1970
1971// set data in core for now
1972void SpellMgr::LoadSpellExtraAttr()
1973{
1974    SpellExtraAttribute tempAttr;
1975    tempAttr.attr[SPELL_EXTRA_ATTR_CONE_TYPE] = 0;
1976    tempAttr.attr[SPELL_EXTRA_ATTR_MAX_TARGETS] = 0;
1977    tempAttr.attr[SPELL_EXTRA_ATTR_SHARE_DAMAGE] = 0;
1978
1979    tempAttr.attr[SPELL_EXTRA_ATTR_CONE_TYPE] = 1;
1980    {
1981        SpellEntry const* tempSpell;
1982        for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i)
1983        {
1984            tempSpell = GetSpellStore()->LookupEntry(i);
1985            if(tempSpell && tempSpell->SpellVisual == 3879)
1986                mSpellExtraAttrMap[tempSpell->Id] = tempAttr;
1987        }
1988    }
1989    tempAttr.attr[SPELL_EXTRA_ATTR_CONE_TYPE] = 2;
1990    mSpellExtraAttrMap[26029] = tempAttr; // dark glare
1991    mSpellExtraAttrMap[37433] = tempAttr; // spout
1992    mSpellExtraAttrMap[43140] = tempAttr; // flame breath
1993    mSpellExtraAttrMap[43215] = tempAttr; // flame breath
1994    tempAttr.attr[SPELL_EXTRA_ATTR_CONE_TYPE] = 0;
1995
1996    tempAttr.attr[SPELL_EXTRA_ATTR_SHARE_DAMAGE] = 1;
1997    for(uint32 i = 0; i < 46000; ++i)
1998    {
1999        switch(i)
2000        {
2001            case 24340: case 26558: case 28884:     // Meteor
2002            case 36837: case 38903: case 41276:     // Meteor
2003            case 26789:                             // Shard of the Fallen Star
2004            case 31436:                             // Malevolent Cleave
2005            case 35181:                             // Dive Bomb
2006            case 40810: case 43267: case 43268:     // Saber Lash
2007            case 42384:                             // Brutal Swipe
2008            case 45150:                             // Meteor Slash
2009                mSpellExtraAttrMap[i] = tempAttr;
2010                break;
2011            default:
2012                break;
2013        }
2014    }
2015    tempAttr.attr[SPELL_EXTRA_ATTR_SHARE_DAMAGE] = 0;
2016
2017    tempAttr.attr[SPELL_EXTRA_ATTR_MAX_TARGETS] = 1;
2018    for(uint32 i = 0; i < 46000; ++i)
2019    {
2020        switch(i)
2021        {
2022            case 44978: case 45001: case 45002:     // Wild Magic
2023            case 45004: case 45006: case 45010:     // Wild Magic
2024            case 31347: // Doom
2025            case 41635: // Prayer of Mending
2026                mSpellExtraAttrMap[i] = tempAttr;
2027                break;
2028            default:
2029                break;
2030        }
2031    }
2032    tempAttr.attr[SPELL_EXTRA_ATTR_MAX_TARGETS] = 3;
2033    mSpellExtraAttrMap[41376] = tempAttr;   //Spite
2034    tempAttr.attr[SPELL_EXTRA_ATTR_MAX_TARGETS] = 0;
2035
2036    //hack here, only for those strange exceptions!
2037    // Psychic Scream
2038    SpellEntry *tempSpell;
2039    if(tempSpell = (SpellEntry*)GetSpellStore()->LookupEntry(8122))
2040        tempSpell->AttributesEx |= SPELL_ATTR_BREAKABLE_BY_DAMAGE;
2041    if(tempSpell = (SpellEntry*)GetSpellStore()->LookupEntry(8124))
2042        tempSpell->AttributesEx |= SPELL_ATTR_BREAKABLE_BY_DAMAGE;
2043    if(tempSpell = (SpellEntry*)GetSpellStore()->LookupEntry(10888))
2044        tempSpell->AttributesEx |= SPELL_ATTR_BREAKABLE_BY_DAMAGE;
2045    if(tempSpell = (SpellEntry*)GetSpellStore()->LookupEntry(10890))
2046        tempSpell->AttributesEx |= SPELL_ATTR_BREAKABLE_BY_DAMAGE;
2047}
2048
2049void SpellMgr::LoadSpellLinked()
2050{
2051    mSpellLinkedMap.clear();    // need for reload case
2052    uint32 count = 0;
2053
2054    //                                                0       1
2055    QueryResult *result = WorldDatabase.Query("SELECT spell0, spell1 FROM spell_linked_spell");
2056    if( !result )
2057    {
2058        barGoLink bar( 1 );
2059        bar.step();
2060        sLog.outString();
2061        sLog.outString( ">> Loaded %u spell pet auras", count );
2062        return;
2063    }
2064
2065    barGoLink bar( result->GetRowCount() );
2066
2067    do
2068    {
2069        Field *fields = result->Fetch();
2070
2071        bar.step();
2072
2073        uint16 spell = fields[0].GetUInt16();
2074        uint16 pet = fields[1].GetUInt16();
2075        uint16 aura = fields[2].GetUInt16();
2076
2077        SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find(spell);
2078        if(itr != mSpellPetAuraMap.end())
2079        {
2080            itr->second.AddAura(pet, aura);
2081        }
2082        else
2083        {
2084            SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell);
2085            if (!spellInfo)
2086            {
2087                sLog.outErrorDb("Spell %u listed in `spell_pet_auras` does not exist", spell);
2088                continue;
2089            }
2090            int i = 0;
2091            for(; i < 3; ++i)
2092                if((spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA &&
2093                    spellInfo->EffectApplyAuraName[i] == SPELL_AURA_DUMMY) ||
2094                    spellInfo->Effect[i] == SPELL_EFFECT_DUMMY)
2095                    break;
2096
2097            if(i == 3)
2098            {
2099                sLog.outError("Spell %u listed in `spell_pet_auras` does not have dummy aura or dummy effect", spell);
2100                continue;
2101            }
2102
2103            SpellEntry const* spellInfo2 = sSpellStore.LookupEntry(aura);
2104            if (!spellInfo2)
2105            {
2106                sLog.outErrorDb("Aura %u listed in `spell_pet_auras` does not exist", aura);
2107                continue;
2108            }
2109
2110            PetAura pa(pet, aura, spellInfo->EffectImplicitTargetA[i] == TARGET_PET, spellInfo->EffectBasePoints[i] + spellInfo->EffectBaseDice[i]);
2111            mSpellPetAuraMap[spell] = pa;
2112        }
2113
2114        ++count;
2115    } while( result->NextRow() );
2116
2117    delete result;
2118
2119    sLog.outString();
2120    sLog.outString( ">> Loaded %u spell pet auras", count );
2121}
2122
2123/// Some checks for spells, to prevent adding depricated/broken spells for trainers, spell book, etc
2124bool SpellMgr::IsSpellValid(SpellEntry const* spellInfo, Player* pl, bool msg)
2125{
2126    // not exist
2127    if(!spellInfo)
2128        return false;
2129
2130    bool need_check_reagents = false;
2131
2132    // check effects
2133    for(int i=0; i<3; ++i)
2134    {
2135        switch(spellInfo->Effect[i])
2136        {
2137            case 0:
2138                continue;
2139
2140                // craft spell for crafting non-existed item (break client recipes list show)
2141            case SPELL_EFFECT_CREATE_ITEM:
2142            {
2143                if(!ObjectMgr::GetItemPrototype( spellInfo->EffectItemType[i] ))
2144                {
2145                    if(msg)
2146                    {
2147                        if(pl)
2148                            ChatHandler(pl).PSendSysMessage("Craft spell %u create not-exist in DB item (Entry: %u) and then...",spellInfo->Id,spellInfo->EffectItemType[i]);
2149                        else
2150                            sLog.outErrorDb("Craft spell %u create not-exist in DB item (Entry: %u) and then...",spellInfo->Id,spellInfo->EffectItemType[i]);
2151                    }
2152                    return false;
2153                }
2154
2155                need_check_reagents = true;
2156                break;
2157            }
2158            case SPELL_EFFECT_LEARN_SPELL:
2159            {
2160                SpellEntry const* spellInfo2 = sSpellStore.LookupEntry(spellInfo->EffectTriggerSpell[0]);
2161                if( !IsSpellValid(spellInfo2,pl,msg) )
2162                {
2163                    if(msg)
2164                    {
2165                        if(pl)
2166                            ChatHandler(pl).PSendSysMessage("Spell %u learn to broken spell %u, and then...",spellInfo->Id,spellInfo->EffectTriggerSpell[0]);
2167                        else
2168                            sLog.outErrorDb("Spell %u learn to invalid spell %u, and then...",spellInfo->Id,spellInfo->EffectTriggerSpell[0]);
2169                    }
2170                    return false;
2171                }
2172                break;
2173            }
2174        }
2175    }
2176
2177    if(need_check_reagents)
2178    {
2179        for(int j = 0; j < 8; ++j)
2180        {
2181            if(spellInfo->Reagent[j] > 0 && !ObjectMgr::GetItemPrototype( spellInfo->Reagent[j] ))
2182            {
2183                if(msg)
2184                {
2185                    if(pl)
2186                        ChatHandler(pl).PSendSysMessage("Craft spell %u have not-exist reagent in DB item (Entry: %u) and then...",spellInfo->Id,spellInfo->Reagent[j]);
2187                    else
2188                        sLog.outErrorDb("Craft spell %u have not-exist reagent in DB item (Entry: %u) and then...",spellInfo->Id,spellInfo->Reagent[j]);
2189                }
2190                return false;
2191            }
2192        }
2193    }
2194
2195    return true;
2196}
2197
2198bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id)
2199{
2200    // normal case
2201    if( spellInfo->AreaId && spellInfo->AreaId != zone_id && spellInfo->AreaId != area_id )
2202        return false;
2203
2204    // elixirs (all area dependent elixirs have family SPELLFAMILY_POTION, use this for speedup)
2205    if(spellInfo->SpellFamilyName==SPELLFAMILY_POTION)
2206    {
2207        if(uint32 mask = spellmgr.GetSpellElixirMask(spellInfo->Id))
2208        {
2209            if(mask & ELIXIR_UNSTABLE_MASK)
2210            {
2211                // in the Blade's Edge Mountains Plateaus and Gruul's Lair.
2212                return zone_id ==3522 || map_id==565;
2213            }
2214            if(mask & ELIXIR_UNSTABLE_MASK)
2215            {
2216                // in Tempest Keep, Serpentshrine Cavern, Caverns of Time: Mount Hyjal, Black Temple
2217                // TODO: and the Sunwell Plateau
2218                if(zone_id ==3607 || map_id==534 || map_id==564)
2219                    return true;
2220
2221                MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
2222                if(!mapEntry)
2223                    return false;
2224
2225                return mapEntry->multimap_id==206;
2226            }
2227
2228            // elixirs not have another limitations
2229            return true;
2230        }
2231    }
2232
2233    // special cases zone check (maps checked by multimap common id)
2234    switch(spellInfo->Id)
2235    {
2236        case 41618:
2237        case 41620:
2238        {
2239            MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
2240            if(!mapEntry)
2241                return false;
2242
2243            return mapEntry->multimap_id==206;
2244        }
2245
2246        case 41617:
2247        case 41619:
2248        {
2249            MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
2250            if(!mapEntry)
2251                return false;
2252
2253            return mapEntry->multimap_id==207;
2254        }
2255        // Dragonmaw Illusion
2256        case 40216:
2257        case 42016:
2258        {
2259            if ( area_id != 3759 && area_id != 3966 && area_id != 3939 )
2260                return false;
2261            break;
2262        }
2263    }
2264
2265    return true;
2266}
2267
2268void SpellMgr::LoadSkillLineAbilityMap()
2269{
2270    mSkillLineAbilityMap.clear();
2271
2272    uint32 count = 0;
2273
2274    for (uint32 i = 0; i < sSkillLineAbilityStore.GetNumRows(); i++)
2275    {
2276        SkillLineAbilityEntry const *SkillInfo = sSkillLineAbilityStore.LookupEntry(i);
2277        if(!SkillInfo)
2278            continue;
2279
2280        mSkillLineAbilityMap.insert(SkillLineAbilityMap::value_type(SkillInfo->spellId,SkillInfo));
2281        ++count;
2282    }
2283
2284    sLog.outString();
2285    sLog.outString(">> Loaded %u SkillLineAbility MultiMap", count);
2286}
2287
2288DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto, bool triggered)
2289{
2290    // Explicit Diminishing Groups
2291    switch(spellproto->SpellFamilyName)
2292    {
2293        case SPELLFAMILY_MAGE:
2294        {
2295            // Polymorph
2296            if ((spellproto->SpellFamilyFlags & 0x00001000000LL) && spellproto->EffectApplyAuraName[0]==SPELL_AURA_MOD_CONFUSE)
2297                return DIMINISHING_POLYMORPH;
2298            break;
2299        }
2300        case SPELLFAMILY_ROGUE:
2301        {
2302            // Kidney Shot
2303            if (spellproto->SpellFamilyFlags & 0x00000200000LL)
2304                return DIMINISHING_KIDNEYSHOT;
2305            // Blind
2306            else if (spellproto->SpellFamilyFlags & 0x00001000000LL)
2307                return DIMINISHING_BLIND_CYCLONE;
2308            break;
2309        }
2310        case SPELLFAMILY_WARLOCK:
2311        {
2312            // Death Coil
2313            if (spellproto->SpellFamilyFlags & 0x00000080000LL)
2314                return DIMINISHING_DEATHCOIL;
2315            // Fear
2316            else if (spellproto->SpellFamilyFlags & 0x40840000000LL)
2317                return DIMINISHING_WARLOCK_FEAR;
2318            // Curses/etc
2319            else if (spellproto->SpellFamilyFlags & 0x00080000000LL)
2320                return DIMINISHING_LIMITONLY;
2321            break;
2322        }
2323        case SPELLFAMILY_DRUID:
2324        {
2325            // Cyclone
2326            if (spellproto->SpellFamilyFlags & 0x02000000000LL)
2327                return DIMINISHING_BLIND_CYCLONE;
2328            break;
2329        }
2330        case SPELLFAMILY_WARRIOR:
2331        {
2332            // Hamstring - limit duration to 10s in PvP
2333            if (spellproto->SpellFamilyFlags & 0x00000000002LL)
2334                return DIMINISHING_LIMITONLY;
2335            break;
2336        }
2337        default:
2338            break;
2339    }
2340
2341    // Get by mechanic
2342    for (uint8 i=0;i<3;++i)
2343    {
2344        if (spellproto->Mechanic      == MECHANIC_STUN    || spellproto->EffectMechanic[i] == MECHANIC_STUN)
2345            return triggered ? DIMINISHING_TRIGGER_STUN : DIMINISHING_CONTROL_STUN;
2346        else if (spellproto->Mechanic == MECHANIC_SLEEP   || spellproto->EffectMechanic[i] == MECHANIC_SLEEP)
2347            return DIMINISHING_SLEEP;
2348        else if (spellproto->Mechanic == MECHANIC_ROOT    || spellproto->EffectMechanic[i] == MECHANIC_ROOT)
2349            return triggered ? DIMINISHING_TRIGGER_ROOT : DIMINISHING_CONTROL_ROOT;
2350        else if (spellproto->Mechanic == MECHANIC_FEAR    || spellproto->EffectMechanic[i] == MECHANIC_FEAR)
2351            return DIMINISHING_FEAR;
2352        else if (spellproto->Mechanic == MECHANIC_CHARM   || spellproto->EffectMechanic[i] == MECHANIC_CHARM)
2353            return DIMINISHING_CHARM;
2354        else if (spellproto->Mechanic == MECHANIC_SILENCE || spellproto->EffectMechanic[i] == MECHANIC_SILENCE)
2355            return DIMINISHING_SILENCE;
2356        else if (spellproto->Mechanic == MECHANIC_DISARM  || spellproto->EffectMechanic[i] == MECHANIC_DISARM)
2357            return DIMINISHING_DISARM;
2358        else if (spellproto->Mechanic == MECHANIC_FREEZE  || spellproto->EffectMechanic[i] == MECHANIC_FREEZE)
2359            return DIMINISHING_FREEZE;
2360        else if (spellproto->Mechanic == MECHANIC_KNOCKOUT|| spellproto->EffectMechanic[i] == MECHANIC_KNOCKOUT ||
2361                 spellproto->Mechanic == MECHANIC_SAPPED  || spellproto->EffectMechanic[i] == MECHANIC_SAPPED)
2362            return DIMINISHING_KNOCKOUT;
2363        else if (spellproto->Mechanic == MECHANIC_BANISH  || spellproto->EffectMechanic[i] == MECHANIC_BANISH)
2364            return DIMINISHING_BANISH;
2365    }
2366
2367    return DIMINISHING_NONE;
2368}
2369
2370bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group)
2371{
2372    switch(group)
2373    {
2374        case DIMINISHING_CONTROL_STUN:
2375        case DIMINISHING_TRIGGER_STUN:
2376        case DIMINISHING_KIDNEYSHOT:
2377        case DIMINISHING_SLEEP:
2378        case DIMINISHING_CONTROL_ROOT:
2379        case DIMINISHING_TRIGGER_ROOT:
2380        case DIMINISHING_FEAR:
2381        case DIMINISHING_WARLOCK_FEAR:
2382        case DIMINISHING_CHARM:
2383        case DIMINISHING_POLYMORPH:
2384        case DIMINISHING_FREEZE:
2385        case DIMINISHING_KNOCKOUT:
2386        case DIMINISHING_BLIND_CYCLONE:
2387        case DIMINISHING_BANISH:
2388        case DIMINISHING_LIMITONLY:
2389            return true;
2390    }
2391    return false;
2392}
2393
2394DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group)
2395{
2396    switch(group)
2397    {
2398        case DIMINISHING_BLIND_CYCLONE:
2399        case DIMINISHING_CONTROL_STUN:
2400        case DIMINISHING_TRIGGER_STUN:
2401        case DIMINISHING_KIDNEYSHOT:
2402            return DRTYPE_ALL;
2403        case DIMINISHING_SLEEP:
2404        case DIMINISHING_CONTROL_ROOT:
2405        case DIMINISHING_TRIGGER_ROOT:
2406        case DIMINISHING_FEAR:
2407        case DIMINISHING_CHARM:
2408        case DIMINISHING_POLYMORPH:
2409        case DIMINISHING_SILENCE:
2410        case DIMINISHING_DISARM:
2411        case DIMINISHING_DEATHCOIL:
2412        case DIMINISHING_FREEZE:
2413        case DIMINISHING_BANISH:
2414        case DIMINISHING_WARLOCK_FEAR:
2415        case DIMINISHING_KNOCKOUT:
2416            return DRTYPE_PLAYER;
2417    }
2418
2419    return DRTYPE_NONE;
2420}
Note: See TracBrowser for help on using the browser.