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

Revision 219, 71.6 kB (checked in by yumileroy, 17 years ago)

[svn] Update IsNoStackSpellDueToSpell?. This should fix the bug that some talent spell auras cannot stack. Patch provided by QAston.

Original author: megamage
Date: 2008-11-12 10:22:56-06: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            //seed of corruption and corruption
167            if (spellInfo->SpellFamilyFlags & 0x1000000002LL)
168                return SPELL_WARLOCK_CORRUPTION;
169            break;
170        }
171        case SPELLFAMILY_HUNTER:
172        {
173            // only hunter stings have this
174            if (spellInfo->Dispel == DISPEL_POISON)
175                return SPELL_STING;
176
177            break;
178        }
179        case SPELLFAMILY_PALADIN:
180        {
181            if (IsSealSpell(spellInfo))
182                return SPELL_SEAL;
183
184            if (spellInfo->SpellFamilyFlags & 0x10000100LL)
185                return SPELL_BLESSING;
186
187            if ((spellInfo->SpellFamilyFlags & 0x00000820180400LL) && (spellInfo->AttributesEx3 & 0x200))
188                return SPELL_JUDGEMENT;
189
190            for (int i = 0; i < 3; i++)
191            {
192                // only paladin auras have this
193                if (spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY)
194                    return SPELL_AURA;
195            }
196            break;
197        }
198        case SPELLFAMILY_SHAMAN:
199        {
200            if (IsElementalShield(spellInfo))
201                return SPELL_ELEMENTAL_SHIELD;
202
203            break;
204        }
205
206        case SPELLFAMILY_POTION:
207            return spellmgr.GetSpellElixirSpecific(spellInfo->Id);
208    }
209
210    // only warlock armor/skin have this (in additional to family cases)
211    if( spellInfo->SpellVisual == 130 && spellInfo->SpellIconID == 89)
212    {
213        return SPELL_WARLOCK_ARMOR;
214    }
215
216    // only hunter aspects have this (but not all aspects in hunter family)
217    if( spellInfo->activeIconID == 122 && (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_NATURE) &&
218        (spellInfo->Attributes & 0x50000) != 0 && (spellInfo->Attributes & 0x9000010) == 0)
219    {
220        return SPELL_ASPECT;
221    }
222
223    for(int i = 0; i < 3; i++)
224        if( spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA && (
225        spellInfo->EffectApplyAuraName[i] == SPELL_AURA_TRACK_CREATURES ||
226        spellInfo->EffectApplyAuraName[i] == SPELL_AURA_TRACK_RESOURCES ||
227        spellInfo->EffectApplyAuraName[i] == SPELL_AURA_TRACK_STEALTHED ) )
228            return SPELL_TRACKER;
229
230    // elixirs can have different families, but potion most ofc.
231    if(SpellSpecific sp = spellmgr.GetSpellElixirSpecific(spellInfo->Id))
232        return sp;
233
234    return SPELL_NORMAL;
235}
236
237bool IsSingleFromSpellSpecificPerCaster(uint32 spellSpec1,uint32 spellSpec2)
238{
239    switch(spellSpec1)
240    {
241        case SPELL_SEAL:
242        case SPELL_BLESSING:
243        case SPELL_AURA:
244        case SPELL_STING:
245        case SPELL_CURSE:
246        case SPELL_ASPECT:
247        case SPELL_TRACKER:
248        case SPELL_WARLOCK_ARMOR:
249        case SPELL_MAGE_ARMOR:
250        case SPELL_ELEMENTAL_SHIELD:
251        case SPELL_MAGE_POLYMORPH:
252        case SPELL_POSITIVE_SHOUT:
253        case SPELL_JUDGEMENT:
254        case SPELL_WARLOCK_CORRUPTION:
255            return spellSpec1==spellSpec2;
256        case SPELL_BATTLE_ELIXIR:
257            return spellSpec2==SPELL_BATTLE_ELIXIR
258                || spellSpec2==SPELL_FLASK_ELIXIR;
259        case SPELL_GUARDIAN_ELIXIR:
260            return spellSpec2==SPELL_GUARDIAN_ELIXIR
261                || spellSpec2==SPELL_FLASK_ELIXIR;
262        case SPELL_FLASK_ELIXIR:
263            return spellSpec2==SPELL_BATTLE_ELIXIR
264                || spellSpec2==SPELL_GUARDIAN_ELIXIR
265                || spellSpec2==SPELL_FLASK_ELIXIR;
266        default:
267            return false;
268    }
269}
270
271bool IsPositiveTarget(uint32 targetA, uint32 targetB)
272{
273    // non-positive targets
274    switch(targetA)
275    {
276        case TARGET_CHAIN_DAMAGE:
277        case TARGET_ALL_ENEMY_IN_AREA:
278        case TARGET_ALL_ENEMY_IN_AREA_INSTANT:
279        case TARGET_IN_FRONT_OF_CASTER:
280        case TARGET_ALL_ENEMY_IN_AREA_CHANNELED:
281        case TARGET_CURRENT_ENEMY_COORDINATES:
282        case TARGET_SINGLE_ENEMY:
283            return false;
284        case TARGET_ALL_AROUND_CASTER:
285            return (targetB == TARGET_ALL_PARTY || targetB == TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER);
286        default:
287            break;
288    }
289    if (targetB)
290        return IsPositiveTarget(targetB, 0);
291    return true;
292}
293
294bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
295{
296    SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
297    if (!spellproto) return false;
298
299    switch(spellId)
300    {
301        case 23333:                                         // BG spell
302        case 23335:                                         // BG spell
303        case 34976:                                         // BG spell
304            return true;
305        case 28441:                                         // not positive dummy spell
306        case 37675:                                         // Chaos Blast
307            return false;
308    }
309
310    switch(spellproto->Effect[effIndex])
311    {
312        // always positive effects (check before target checks that provided non-positive result in some case for positive effects)
313        case SPELL_EFFECT_HEAL:
314        case SPELL_EFFECT_LEARN_SPELL:
315        case SPELL_EFFECT_SKILL_STEP:
316        case SPELL_EFFECT_HEAL_PCT:
317        case SPELL_EFFECT_ENERGIZE_PCT:
318            return true;
319
320            // non-positive aura use
321        case SPELL_EFFECT_APPLY_AURA:
322        case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
323        {
324            switch(spellproto->EffectApplyAuraName[effIndex])
325            {
326                case SPELL_AURA_DUMMY:
327                {
328                    // dummy aura can be positive or negative dependent from casted spell
329                    switch(spellproto->Id)
330                    {
331                        case 13139:                         // net-o-matic special effect
332                        case 23445:                         // evil twin
333                        case 38637:                         // Nether Exhaustion (red)
334                        case 38638:                         // Nether Exhaustion (green)
335                        case 38639:                         // Nether Exhaustion (blue)
336                            return false;
337                        default:
338                            break;
339                    }
340                }   break;
341                case SPELL_AURA_MOD_STAT:
342                case SPELL_AURA_MOD_DAMAGE_DONE:            // dependent from bas point sign (negative -> negative)
343                case SPELL_AURA_MOD_HEALING_DONE:
344                {
345                    if(spellproto->EffectBasePoints[effIndex]+int32(spellproto->EffectBaseDice[effIndex]) < 0)
346                        return false;
347                    break;
348                }
349                case SPELL_AURA_ADD_TARGET_TRIGGER:
350                    return true;
351                case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
352                    if(spellId != spellproto->EffectTriggerSpell[effIndex])
353                    {
354                        uint32 spellTriggeredId = spellproto->EffectTriggerSpell[effIndex];
355                        SpellEntry const *spellTriggeredProto = sSpellStore.LookupEntry(spellTriggeredId);
356
357                        if(spellTriggeredProto)
358                        {
359                            // non-positive targets of main spell return early
360                            for(int i = 0; i < 3; ++i)
361                            {
362                                // if non-positive trigger cast targeted to positive target this main cast is non-positive
363                                // this will place this spell auras as debuffs
364                                if(IsPositiveTarget(spellTriggeredProto->EffectImplicitTargetA[effIndex],spellTriggeredProto->EffectImplicitTargetB[effIndex]) && !IsPositiveEffect(spellTriggeredId,i))
365                                    return false;
366                            }
367                        }
368                    }
369                    break;
370                case SPELL_AURA_PROC_TRIGGER_SPELL:
371                    // many positive auras have negative triggered spells at damage for example and this not make it negative (it can be canceled for example)
372                    break;
373                case SPELL_AURA_MOD_STUN:                   //have positive and negative spells, we can't sort its correctly at this moment.
374                    if(effIndex==0 && spellproto->Effect[1]==0 && spellproto->Effect[2]==0)
375                        return false;                       // but all single stun aura spells is negative
376
377                    // Petrification
378                    if(spellproto->Id == 17624)
379                        return false;
380                    break;
381                case SPELL_AURA_MOD_ROOT:
382                case SPELL_AURA_MOD_SILENCE:
383                case SPELL_AURA_GHOST:
384                case SPELL_AURA_PERIODIC_LEECH:
385                case SPELL_AURA_MOD_PACIFY_SILENCE:
386                case SPELL_AURA_MOD_STALKED:
387                case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
388                    return false;
389                case SPELL_AURA_PERIODIC_DAMAGE:            // used in positive spells also.
390                    // part of negative spell if casted at self (prevent cancel)
391                    if(spellproto->EffectImplicitTargetA[effIndex] == TARGET_SELF)
392                        return false;
393                    break;
394                case SPELL_AURA_MOD_DECREASE_SPEED:         // used in positive spells also
395                    // part of positive spell if casted at self
396                    if(spellproto->EffectImplicitTargetA[effIndex] != TARGET_SELF)
397                        return false;
398                    // but not this if this first effect (don't found batter check)
399                    if(spellproto->Attributes & 0x4000000 && effIndex==0)
400                        return false;
401                    break;
402                case SPELL_AURA_TRANSFORM:
403                    // some spells negative
404                    switch(spellproto->Id)
405                    {
406                        case 36897:                         // Transporter Malfunction (race mutation to horde)
407                        case 36899:                         // Transporter Malfunction (race mutation to alliance)
408                            return false;
409                    }
410                    break;
411                case SPELL_AURA_MOD_SCALE:
412                    // some spells negative
413                    switch(spellproto->Id)
414                    {
415                        case 36900:                         // Soul Split: Evil!
416                        case 36901:                         // Soul Split: Good
417                        case 36893:                         // Transporter Malfunction (decrease size case)
418                        case 36895:                         // Transporter Malfunction (increase size case)
419                            return false;
420                    }
421                    break;
422                case SPELL_AURA_MECHANIC_IMMUNITY:
423                {
424                    // non-positive immunities
425                    switch(spellproto->EffectMiscValue[effIndex])
426                    {
427                        case MECHANIC_BANDAGE:
428                        case MECHANIC_SHIELD:
429                        case MECHANIC_MOUNT:
430                        case MECHANIC_INVULNERABILITY:
431                            return false;
432                        default:
433                            break;
434                    }
435                }   break;
436                case SPELL_AURA_ADD_FLAT_MODIFIER:          // mods
437                case SPELL_AURA_ADD_PCT_MODIFIER:
438                {
439                    // non-positive mods
440                    switch(spellproto->EffectMiscValue[effIndex])
441                    {
442                        case SPELLMOD_COST:                 // dependent from bas point sign (negative -> positive)
443                            if(spellproto->EffectBasePoints[effIndex]+int32(spellproto->EffectBaseDice[effIndex]) > 0)
444                                return false;
445                            break;
446                        default:
447                            break;
448                    }
449                }   break;
450                case SPELL_AURA_MOD_HEALING_PCT:
451                    if(spellproto->EffectBasePoints[effIndex]+int32(spellproto->EffectBaseDice[effIndex]) < 0)
452                        return false;
453                    break;
454                case SPELL_AURA_MOD_SKILL:
455                    if(spellproto->EffectBasePoints[effIndex]+int32(spellproto->EffectBaseDice[effIndex]) < 0)
456                        return false;
457                    break;
458                case SPELL_AURA_FORCE_REACTION:
459                    if(spellproto->Id==42792)               // Recently Dropped Flag (prevent cancel)
460                        return false;
461                    break;
462                default:
463                    break;
464            }
465            break;
466        }
467        default:
468            break;
469    }
470
471    // non-positive targets
472    if(!IsPositiveTarget(spellproto->EffectImplicitTargetA[effIndex],spellproto->EffectImplicitTargetB[effIndex]))
473        return false;
474
475    // AttributesEx check
476    if(spellproto->AttributesEx & (1<<7))
477        return false;
478
479    // ok, positive
480    return true;
481}
482
483bool IsPositiveSpell(uint32 spellId)
484{
485    SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
486    if (!spellproto) return false;
487
488    // spells with atleast one negative effect are considered negative
489    // some self-applied spells have negative effects but in self casting case negative check ignored.
490    for (int i = 0; i < 3; i++)
491        if (!IsPositiveEffect(spellId, i))
492            return false;
493    return true;
494}
495
496bool IsSingleTargetSpell(SpellEntry const *spellInfo)
497{
498    // all other single target spells have if it has AttributesEx5
499    if ( spellInfo->AttributesEx5 & SPELL_ATTR_EX5_SINGLE_TARGET_SPELL )
500        return true;
501
502    // TODO - need found Judgements rule
503    switch(GetSpellSpecific(spellInfo->Id))
504    {
505        case SPELL_JUDGEMENT:
506            return true;
507    }
508
509    // single target triggered spell.
510    // Not real client side single target spell, but it' not triggered until prev. aura expired.
511    // This is allow store it in single target spells list for caster for spell proc checking
512    if(spellInfo->Id==38324)                                // Regeneration (triggered by 38299 (HoTs on Heals))
513        return true;
514
515    return false;
516}
517
518bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellInfo2)
519{
520    // TODO - need better check
521    // Equal icon and spellfamily
522    if( spellInfo1->SpellFamilyName == spellInfo2->SpellFamilyName &&
523        spellInfo1->SpellIconID == spellInfo2->SpellIconID )
524        return true;
525
526    // TODO - need found Judgements rule
527    SpellSpecific spec1 = GetSpellSpecific(spellInfo1->Id);
528    // spell with single target specific types
529    switch(spec1)
530    {
531        case SPELL_JUDGEMENT:
532            if(GetSpellSpecific(spellInfo2->Id) == spec1)
533                return true;
534            break;
535    }
536
537    return false;
538}
539
540uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
541{
542    // talents that learn spells can have stance requirements that need ignore
543    // (this requirement only for client-side stance show in talent description)
544    if( GetTalentSpellCost(spellInfo->Id) > 0 &&
545        (spellInfo->Effect[0]==SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[1]==SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[2]==SPELL_EFFECT_LEARN_SPELL) )
546        return 0;
547
548    uint32 stanceMask = (form ? 1 << (form - 1) : 0);
549
550    if (stanceMask & spellInfo->StancesNot)                 // can explicitly not be casted in this stance
551        return SPELL_FAILED_NOT_SHAPESHIFT;
552
553    if (stanceMask & spellInfo->Stances)                    // can explicitly be casted in this stance
554        return 0;
555
556    bool actAsShifted = false;
557    if (form > 0)
558    {
559        SpellShapeshiftEntry const *shapeInfo = sSpellShapeshiftStore.LookupEntry(form);
560        if (!shapeInfo)
561        {
562            sLog.outError("GetErrorAtShapeshiftedCast: unknown shapeshift %u", form);
563            return 0;
564        }
565        actAsShifted = !(shapeInfo->flags1 & 1);            // shapeshift acts as normal form for spells
566    }
567
568    if(actAsShifted)
569    {
570        if (spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) // not while shapeshifted
571            return SPELL_FAILED_NOT_SHAPESHIFT;
572        else if (spellInfo->Stances != 0)                   // needs other shapeshift
573            return SPELL_FAILED_ONLY_SHAPESHIFT;
574    }
575    else
576    {
577        // needs shapeshift
578        if(!(spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT) && spellInfo->Stances != 0)
579            return SPELL_FAILED_ONLY_SHAPESHIFT;
580    }
581
582    return 0;
583}
584
585void SpellMgr::LoadSpellTargetPositions()
586{
587    mSpellTargetPositions.clear();                                // need for reload case
588
589    uint32 count = 0;
590
591    //                                                0   1           2                  3                  4                  5
592    QueryResult *result = WorldDatabase.Query("SELECT id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM spell_target_position");
593    if( !result )
594    {
595
596        barGoLink bar( 1 );
597
598        bar.step();
599
600        sLog.outString();
601        sLog.outString( ">> Loaded %u spell target coordinates", count );
602        return;
603    }
604
605    barGoLink bar( result->GetRowCount() );
606
607    do
608    {
609        Field *fields = result->Fetch();
610
611        bar.step();
612
613        ++count;
614
615        uint32 Spell_ID = fields[0].GetUInt32();
616
617        SpellTargetPosition st;
618
619        st.target_mapId       = fields[1].GetUInt32();
620        st.target_X           = fields[2].GetFloat();
621        st.target_Y           = fields[3].GetFloat();
622        st.target_Z           = fields[4].GetFloat();
623        st.target_Orientation = fields[5].GetFloat();
624
625        SpellEntry const* spellInfo = sSpellStore.LookupEntry(Spell_ID);
626        if(!spellInfo)
627        {
628            sLog.outErrorDb("Spell (ID:%u) listed in `spell_target_position` does not exist.",Spell_ID);
629            continue;
630        }
631
632        bool found = false;
633        for(int i = 0; i < 3; ++i)
634        {
635            if( spellInfo->EffectImplicitTargetA[i]==TARGET_TABLE_X_Y_Z_COORDINATES || spellInfo->EffectImplicitTargetB[i]==TARGET_TABLE_X_Y_Z_COORDINATES )
636            {
637                found = true;
638                break;
639            }
640        }
641        if(!found)
642        {
643            sLog.outErrorDb("Spell (Id: %u) listed in `spell_target_position` does not have target TARGET_TABLE_X_Y_Z_COORDINATES (17).",Spell_ID);
644            continue;
645        }
646
647        MapEntry const* mapEntry = sMapStore.LookupEntry(st.target_mapId);
648        if(!mapEntry)
649        {
650            sLog.outErrorDb("Spell (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Spell_ID,st.target_mapId);
651            continue;
652        }
653
654        if(st.target_X==0 && st.target_Y==0 && st.target_Z==0)
655        {
656            sLog.outErrorDb("Spell (ID:%u) target coordinates not provided.",Spell_ID);
657            continue;
658        }
659
660        mSpellTargetPositions[Spell_ID] = st;
661
662    } while( result->NextRow() );
663
664    delete result;
665
666    sLog.outString();
667    sLog.outString( ">> Loaded %u spell teleport coordinates", count );
668}
669
670void SpellMgr::LoadSpellAffects()
671{
672    mSpellAffectMap.clear();                                // need for reload case
673
674    uint32 count = 0;
675
676    //                                                0      1         2
677    QueryResult *result = WorldDatabase.Query("SELECT entry, effectId, SpellFamilyMask FROM spell_affect");
678    if( !result )
679    {
680
681        barGoLink bar( 1 );
682
683        bar.step();
684
685        sLog.outString();
686        sLog.outString( ">> Loaded %u spell affect definitions", count );
687        return;
688    }
689
690    barGoLink bar( result->GetRowCount() );
691
692    do
693    {
694        Field *fields = result->Fetch();
695
696        bar.step();
697
698        uint16 entry = fields[0].GetUInt16();
699        uint8 effectId = fields[1].GetUInt8();
700
701        SpellEntry const* spellInfo = sSpellStore.LookupEntry(entry);
702
703        if (!spellInfo)
704        {
705            sLog.outErrorDb("Spell %u listed in `spell_affect` does not exist", entry);
706            continue;
707        }
708
709        if (effectId >= 3)
710        {
711            sLog.outErrorDb("Spell %u listed in `spell_affect` have invalid effect index (%u)", entry,effectId);
712            continue;
713        }
714
715        if( spellInfo->Effect[effectId] != SPELL_EFFECT_APPLY_AURA ||
716            spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_FLAT_MODIFIER &&
717            spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_PCT_MODIFIER  &&
718            spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_TARGET_TRIGGER )
719        {
720            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);
721            continue;
722        }
723
724        uint64 spellAffectMask = fields[2].GetUInt64();
725
726        // Spell.dbc have own data for low part of SpellFamilyMask
727        if( spellInfo->EffectItemType[effectId])
728        {
729            if(spellInfo->EffectItemType[effectId] == spellAffectMask)
730            {
731                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);
732                continue;
733            }
734
735            // 24429 have wrong data in EffectItemType and overwrites by DB, possible bug in client
736            if(spellInfo->Id!=24429 && spellInfo->EffectItemType[effectId] != spellAffectMask)
737            {
738                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);
739                continue;
740            }
741        }
742
743        mSpellAffectMap.insert(SpellAffectMap::value_type((entry<<8) + effectId,spellAffectMask));
744
745        ++count;
746    } while( result->NextRow() );
747
748    delete result;
749
750    sLog.outString();
751    sLog.outString( ">> Loaded %u spell affect definitions", count );
752
753    for (uint32 id = 0; id < sSpellStore.GetNumRows(); ++id)
754    {
755        SpellEntry const* spellInfo = sSpellStore.LookupEntry(id);
756        if (!spellInfo)
757            continue;
758
759        for (int effectId = 0; effectId < 3; ++effectId)
760        {
761            if( spellInfo->Effect[effectId] != SPELL_EFFECT_APPLY_AURA ||
762                (spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_FLAT_MODIFIER &&
763                spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_PCT_MODIFIER  &&
764                spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_TARGET_TRIGGER) )
765                continue;
766
767            if(spellInfo->EffectItemType[effectId] != 0)
768                continue;
769
770            if(mSpellAffectMap.find((id<<8) + effectId) !=  mSpellAffectMap.end())
771                continue;
772
773            sLog.outErrorDb("Spell %u (%s) misses spell_affect for effect %u",id,spellInfo->SpellName[sWorld.GetDefaultDbcLocale()], effectId);
774        }
775    }
776}
777
778bool SpellMgr::IsAffectedBySpell(SpellEntry const *spellInfo, uint32 spellId, uint8 effectId, uint64 familyFlags) const
779{
780    // false for spellInfo == NULL
781    if (!spellInfo)
782        return false;
783
784    SpellEntry const *affect_spell = sSpellStore.LookupEntry(spellId);
785    // false for affect_spell == NULL
786    if (!affect_spell)
787        return false;
788
789    // False if spellFamily not equal
790    if (affect_spell->SpellFamilyName != spellInfo->SpellFamilyName)
791        return false;
792
793    // If familyFlags == 0
794    if (!familyFlags)
795    {
796        // Get it from spellAffect table
797        familyFlags = GetSpellAffectMask(spellId,effectId);
798        // false if familyFlags == 0
799        if (!familyFlags)
800            return false;
801    }
802
803    // true
804    if (familyFlags & spellInfo->SpellFamilyFlags)
805        return true;
806
807    return false;
808}
809
810void SpellMgr::LoadSpellProcEvents()
811{
812    mSpellProcEventMap.clear();                             // need for reload case
813
814    uint32 count = 0;
815
816    //                                                0      1           2         3        4                5                6          7        8
817    QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, Category, SkillID, SpellFamilyName, SpellFamilyMask, procFlags, ppmRate, cooldown FROM spell_proc_event");
818    if( !result )
819    {
820
821        barGoLink bar( 1 );
822
823        bar.step();
824
825        sLog.outString();
826        sLog.outString( ">> Loaded %u spell proc event conditions", count  );
827        return;
828    }
829
830    barGoLink bar( result->GetRowCount() );
831
832    do
833    {
834        Field *fields = result->Fetch();
835
836        bar.step();
837
838        uint16 entry = fields[0].GetUInt16();
839
840        if (!sSpellStore.LookupEntry(entry))
841        {
842            sLog.outErrorDb("Spell %u listed in `spell_proc_event` does not exist", entry);
843            continue;
844        }
845
846        SpellProcEventEntry spe;
847
848        spe.schoolMask      = fields[1].GetUInt32();
849        spe.category        = fields[2].GetUInt32();
850        spe.skillId         = fields[3].GetUInt32();
851        spe.spellFamilyName = fields[4].GetUInt32();
852        spe.spellFamilyMask = fields[5].GetUInt64();
853        spe.procFlags       = fields[6].GetUInt32();
854        spe.ppmRate         = fields[7].GetFloat();
855        spe.cooldown        = fields[8].GetUInt32();
856
857        mSpellProcEventMap[entry] = spe;
858
859        ++count;
860    } while( result->NextRow() );
861
862    delete result;
863
864    sLog.outString();
865    sLog.outString( ">> Loaded %u spell proc event conditions", count  );
866
867    /*
868    // Commented for now, as it still produces many errors (still quite many spells miss spell_proc_event)
869    for (uint32 id = 0; id < sSpellStore.GetNumRows(); ++id)
870    {
871        SpellEntry const* spellInfo = sSpellStore.LookupEntry(id);
872        if (!spellInfo)
873            continue;
874
875        bool found = false;
876        for (int effectId = 0; effectId < 3; ++effectId)
877        {
878            // at this moment check only SPELL_AURA_PROC_TRIGGER_SPELL
879            if( spellInfo->EffectApplyAuraName[effectId] == SPELL_AURA_PROC_TRIGGER_SPELL )
880            {
881                found = true;
882                break;
883            }
884        }
885
886        if(!found)
887            continue;
888
889        if(GetSpellProcEvent(id))
890            continue;
891
892        sLog.outErrorDb("Spell %u (%s) misses spell_proc_event",id,spellInfo->SpellName[sWorld.GetDBClang()]);
893    }
894    */
895}
896
897bool SpellMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags )
898{
899    if((procFlags & spellProcEvent->procFlags) == 0)
900        return false;
901
902    // Additional checks in case spell cast/hit/crit is the event
903    // Check (if set) school, category, skill line, spell talent mask
904    if(spellProcEvent->schoolMask && (!procSpell || (GetSpellSchoolMask(procSpell) & spellProcEvent->schoolMask) == 0))
905        return false;
906    if(spellProcEvent->category && (!procSpell || procSpell->Category != spellProcEvent->category))
907        return false;
908    if(spellProcEvent->skillId)
909    {
910        if (!procSpell)
911            return false;
912
913        SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(procSpell->Id);
914        SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(procSpell->Id);
915
916        bool found = false;
917        for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
918        {
919            if(_spell_idx->second->skillId == spellProcEvent->skillId)
920            {
921                found = true;
922                break;
923            }
924        }
925        if (!found)
926            return false;
927    }
928    if(spellProcEvent->spellFamilyName && (!procSpell || spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
929        return false;
930    if(spellProcEvent->spellFamilyMask && (!procSpell || (spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0))
931        return false;
932
933    return true;
934}
935
936void SpellMgr::LoadSpellElixirs()
937{
938    mSpellElixirs.clear();                                  // need for reload case
939
940    uint32 count = 0;
941
942    //                                                0      1
943    QueryResult *result = WorldDatabase.Query("SELECT entry, mask FROM spell_elixir");
944    if( !result )
945    {
946
947        barGoLink bar( 1 );
948
949        bar.step();
950
951        sLog.outString();
952        sLog.outString( ">> Loaded %u spell elixir definitions", count );
953        return;
954    }
955
956    barGoLink bar( result->GetRowCount() );
957
958    do
959    {
960        Field *fields = result->Fetch();
961
962        bar.step();
963
964        uint16 entry = fields[0].GetUInt16();
965        uint8 mask = fields[1].GetUInt8();
966
967        SpellEntry const* spellInfo = sSpellStore.LookupEntry(entry);
968
969        if (!spellInfo)
970        {
971            sLog.outErrorDb("Spell %u listed in `spell_elixir` does not exist", entry);
972            continue;
973        }
974
975        mSpellElixirs[entry] = mask;
976
977        ++count;
978    } while( result->NextRow() );
979
980    delete result;
981
982    sLog.outString();
983    sLog.outString( ">> Loaded %u spell elixir definitions", count );
984}
985
986void SpellMgr::LoadSpellThreats()
987{
988    sSpellThreatStore.Free();                               // for reload
989
990    sSpellThreatStore.Load();
991
992    sLog.outString( ">> Loaded %u aggro generating spells", sSpellThreatStore.RecordCount );
993    sLog.outString();
994}
995
996bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellId_2) const
997{
998    SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
999    if(!spellInfo_1 || !spellInfo_2) return false;
1000    if(spellInfo_1->Id == spellId_2) return false;
1001
1002    return GetFirstSpellInChain(spellInfo_1->Id)==GetFirstSpellInChain(spellId_2);
1003}
1004
1005bool SpellMgr::canStackSpellRanks(SpellEntry const *spellInfo)
1006{
1007    if(spellInfo->powerType != POWER_MANA && spellInfo->powerType != POWER_HEALTH)
1008        return false;
1009    if(IsProfessionSpell(spellInfo->Id))
1010        return false;
1011
1012    // All stance spells. if any better way, change it.
1013    for (int i = 0; i < 3; i++)
1014    {
1015        // Paladin aura Spell
1016        if(spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN
1017            && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AREA_AURA_PARTY)
1018            return false;
1019        // Druid form Spell
1020        if(spellInfo->SpellFamilyName == SPELLFAMILY_DRUID
1021            && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA
1022            && spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
1023            return false;
1024        // Rogue Stealth
1025        if(spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE
1026            && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA
1027            && spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
1028            return false;
1029    }
1030    return true;
1031}
1032
1033bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) const
1034{
1035    if(spellId_1 == spellId_2) // auras due to the same spell
1036        return false;
1037
1038    SpellEntry const *spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
1039    SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
1040
1041    if(!spellInfo_1 || !spellInfo_2)
1042        return false;
1043
1044    if(spellInfo_1->SpellFamilyName != spellInfo_2->SpellFamilyName)
1045        return false;
1046
1047    if(!spellInfo_1->SpellFamilyName) // generic spells
1048    {
1049        if(!spellInfo_1->SpellIconID
1050            || spellInfo_1->SpellIconID != spellInfo_2->SpellIconID)
1051            return false;
1052    }
1053    else if (spellInfo_1->SpellFamilyFlags != spellInfo_2->SpellFamilyFlags)
1054        return false;
1055
1056    for(uint32 i = 0; i < 3; ++i)
1057        if(spellInfo_1->Effect[i] != spellInfo_2->Effect[i]
1058            || spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i])
1059            return false;
1060
1061    return true;
1062}
1063
1064bool SpellMgr::IsProfessionSpell(uint32 spellId)
1065{
1066    SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
1067    if(!spellInfo)
1068        return false;
1069
1070    if(spellInfo->Effect[1] != SPELL_EFFECT_SKILL)
1071        return false;
1072
1073    uint32 skill = spellInfo->EffectMiscValue[1];
1074
1075    return IsProfessionSkill(skill);
1076}
1077
1078bool SpellMgr::IsPrimaryProfessionSpell(uint32 spellId)
1079{
1080    SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
1081    if(!spellInfo)
1082        return false;
1083
1084    if(spellInfo->Effect[1] != SPELL_EFFECT_SKILL)
1085        return false;
1086
1087    uint32 skill = spellInfo->EffectMiscValue[1];
1088
1089    return IsPrimaryProfessionSkill(skill);
1090}
1091
1092bool SpellMgr::IsPrimaryProfessionFirstRankSpell(uint32 spellId) const
1093{
1094    return IsPrimaryProfessionSpell(spellId) && GetSpellRank(spellId)==1;
1095}
1096
1097SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spellInfo, uint32 playerLevel) const
1098{
1099    // ignore passive spells
1100    if(IsPassiveSpell(spellInfo->Id))
1101        return spellInfo;
1102
1103    bool needRankSelection = false;
1104    for(int i=0;i<3;i++)
1105    {
1106        if( IsPositiveEffect(spellInfo->Id, i) && (
1107            spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA ||
1108            spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY
1109            ) )
1110        {
1111            needRankSelection = true;
1112            break;
1113        }
1114    }
1115
1116    // not required
1117    if(!needRankSelection)
1118        return spellInfo;
1119
1120    for(uint32 nextSpellId = spellInfo->Id; nextSpellId != 0; nextSpellId = GetPrevSpellInChain(nextSpellId))
1121    {
1122        SpellEntry const *nextSpellInfo = sSpellStore.LookupEntry(nextSpellId);
1123        if(!nextSpellInfo)
1124            break;
1125
1126        // if found appropriate level
1127        if(playerLevel + 10 >= nextSpellInfo->spellLevel)
1128            return nextSpellInfo;
1129
1130        // one rank less then
1131    }
1132
1133    // not found
1134    return NULL;
1135}
1136
1137void SpellMgr::LoadSpellChains()
1138{
1139    mSpellChains.clear();                                   // need for reload case
1140    mSpellChainsNext.clear();                               // need for reload case
1141
1142    QueryResult *result = WorldDatabase.Query("SELECT spell_id, prev_spell, first_spell, rank, req_spell FROM spell_chain");
1143    if(result == NULL)
1144    {
1145        barGoLink bar( 1 );
1146        bar.step();
1147
1148        sLog.outString();
1149        sLog.outString( ">> Loaded 0 spell chain records" );
1150        sLog.outErrorDb("`spell_chains` table is empty!");
1151        return;
1152    }
1153
1154    uint32 count = 0;
1155
1156    barGoLink bar( result->GetRowCount() );
1157    do
1158    {
1159        bar.step();
1160        Field *fields = result->Fetch();
1161
1162        uint32 spell_id = fields[0].GetUInt32();
1163
1164        SpellChainNode node;
1165        node.prev  = fields[1].GetUInt32();
1166        node.first = fields[2].GetUInt32();
1167        node.rank  = fields[3].GetUInt8();
1168        node.req   = fields[4].GetUInt32();
1169
1170        if(!sSpellStore.LookupEntry(spell_id))
1171        {
1172            sLog.outErrorDb("Spell %u listed in `spell_chain` does not exist",spell_id);
1173            continue;
1174        }
1175
1176        if(node.prev!=0 && !sSpellStore.LookupEntry(node.prev))
1177        {
1178            sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not existed previous rank spell.",
1179                spell_id,node.prev,node.first,node.rank,node.req);
1180            continue;
1181        }
1182
1183        if(!sSpellStore.LookupEntry(node.first))
1184        {
1185            sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not existing first rank spell.",
1186                spell_id,node.prev,node.first,node.rank,node.req);
1187            continue;
1188        }
1189
1190        // check basic spell chain data integrity (note: rank can be equal 0 or 1 for first/single spell)
1191        if( (spell_id == node.first) != (node.rank <= 1) ||
1192            (spell_id == node.first) != (node.prev == 0) ||
1193            (node.rank <= 1) != (node.prev == 0) )
1194        {
1195            sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not compatible chain data.",
1196                spell_id,node.prev,node.first,node.rank,node.req);
1197            continue;
1198        }
1199
1200        if(node.req!=0 && !sSpellStore.LookupEntry(node.req))
1201        {
1202            sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not existing required spell.",
1203                spell_id,node.prev,node.first,node.rank,node.req);
1204            continue;
1205        }
1206
1207        // talents not required data in spell chain for work, but must be checked if present for intergrity
1208        if(TalentSpellPos const* pos = GetTalentSpellPos(spell_id))
1209        {
1210            if(node.rank!=pos->rank+1)
1211            {
1212                sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong rank.",
1213                    spell_id,node.prev,node.first,node.rank,node.req);
1214                continue;
1215            }
1216
1217            if(TalentEntry const* talentEntry = sTalentStore.LookupEntry(pos->talent_id))
1218            {
1219                if(node.first!=talentEntry->RankID[0])
1220                {
1221                    sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong first rank spell.",
1222                        spell_id,node.prev,node.first,node.rank,node.req);
1223                    continue;
1224                }
1225
1226                if(node.rank > 1 && node.prev != talentEntry->RankID[node.rank-1-1])
1227                {
1228                    sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong prev rank spell.",
1229                        spell_id,node.prev,node.first,node.rank,node.req);
1230                    continue;
1231                }
1232
1233                if(node.req!=talentEntry->DependsOnSpell)
1234                {
1235                    sLog.outErrorDb("Talent %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has wrong required spell.",
1236                        spell_id,node.prev,node.first,node.rank,node.req);
1237                    continue;
1238                }
1239            }
1240        }
1241
1242        mSpellChains[spell_id] = node;
1243
1244        if(node.prev)
1245            mSpellChainsNext.insert(SpellChainMapNext::value_type(node.prev,spell_id));
1246
1247        if(node.req)
1248            mSpellChainsNext.insert(SpellChainMapNext::value_type(node.req,spell_id));
1249
1250        ++count;
1251    } while( result->NextRow() );
1252
1253    // additional integrity checks
1254    for(SpellChainMap::iterator i = mSpellChains.begin(); i != mSpellChains.end(); ++i)
1255    {
1256        if(i->second.prev)
1257        {
1258            SpellChainMap::iterator i_prev = mSpellChains.find(i->second.prev);
1259            if(i_prev == mSpellChains.end())
1260            {
1261                sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not found previous rank spell in table.",
1262                    i->first,i->second.prev,i->second.first,i->second.rank,i->second.req);
1263            }
1264            else if( i_prev->second.first != i->second.first )
1265            {
1266                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).",
1267                    i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
1268                    i_prev->second.prev,i_prev->second.first,i_prev->second.rank,i_prev->second.req);
1269            }
1270            else if( i_prev->second.rank+1 != i->second.rank )
1271            {
1272                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).",
1273                    i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
1274                    i_prev->second.prev,i_prev->second.first,i_prev->second.rank,i_prev->second.req);
1275            }
1276        }
1277
1278        if(i->second.req)
1279        {
1280            SpellChainMap::iterator i_req = mSpellChains.find(i->second.req);
1281            if(i_req == mSpellChains.end())
1282            {
1283                sLog.outErrorDb("Spell %u (prev: %u, first: %u, rank: %d, req: %u) listed in `spell_chain` has not found required rank spell in table.",
1284                    i->first,i->second.prev,i->second.first,i->second.rank,i->second.req);
1285            }
1286            else if( i_req->second.first == i->second.first )
1287            {
1288                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).",
1289                    i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
1290                    i_req->second.prev,i_req->second.first,i_req->second.rank,i_req->second.req);
1291            }
1292            else if( i_req->second.req )
1293            {
1294                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).",
1295                    i->first,i->second.prev,i->second.first,i->second.rank,i->second.req,
1296                    i_req->second.prev,i_req->second.first,i_req->second.rank,i_req->second.req);
1297            }
1298        }
1299    }
1300
1301    delete result;
1302
1303    sLog.outString();
1304    sLog.outString( ">> Loaded %u spell chain records", count );
1305}
1306
1307void SpellMgr::LoadSpellLearnSkills()
1308{
1309    mSpellLearnSkills.clear();                              // need for reload case
1310
1311    // search auto-learned skills and add its to map also for use in unlearn spells/talents
1312    uint32 dbc_count = 0;
1313    for(uint32 spell = 0; spell < sSpellStore.GetNumRows(); ++spell)
1314    {
1315        SpellEntry const* entry = sSpellStore.LookupEntry(spell);
1316
1317        if(!entry)
1318            continue;
1319
1320        for(int i = 0; i < 3; ++i)
1321        {
1322            if(entry->Effect[i]==SPELL_EFFECT_SKILL)
1323            {
1324                SpellLearnSkillNode dbc_node;
1325                dbc_node.skill    = entry->EffectMiscValue[i];
1326                if ( dbc_node.skill != SKILL_RIDING )
1327                    dbc_node.value    = 1;
1328                else
1329                    dbc_node.value    = (entry->EffectBasePoints[i]+1)*75;
1330                dbc_node.maxvalue = (entry->EffectBasePoints[i]+1)*75;
1331
1332                SpellLearnSkillNode const* db_node = GetSpellLearnSkill(spell);
1333
1334                mSpellLearnSkills[spell] = dbc_node;
1335                ++dbc_count;
1336                break;
1337            }
1338        }
1339    }
1340
1341    sLog.outString();
1342    sLog.outString( ">> Loaded %u Spell Learn Skills from DBC", dbc_count );
1343}
1344
1345void SpellMgr::LoadSpellLearnSpells()
1346{
1347    mSpellLearnSpells.clear();                              // need for reload case
1348
1349    QueryResult *result = WorldDatabase.Query("SELECT entry, SpellID FROM spell_learn_spell");
1350    if(!result)
1351    {
1352        barGoLink bar( 1 );
1353        bar.step();
1354
1355        sLog.outString();
1356        sLog.outString( ">> Loaded 0 spell learn spells" );
1357        sLog.outErrorDb("`spell_learn_spell` table is empty!");
1358        return;
1359    }
1360
1361    uint32 count = 0;
1362
1363    barGoLink bar( result->GetRowCount() );
1364    do
1365    {
1366        bar.step();
1367        Field *fields = result->Fetch();
1368
1369        uint32 spell_id    = fields[0].GetUInt32();
1370
1371        SpellLearnSpellNode node;
1372        node.spell      = fields[1].GetUInt32();
1373        node.autoLearned= false;
1374
1375        if(!sSpellStore.LookupEntry(spell_id))
1376        {
1377            sLog.outErrorDb("Spell %u listed in `spell_learn_spell` does not exist",spell_id);
1378            continue;
1379        }
1380
1381        if(!sSpellStore.LookupEntry(node.spell))
1382        {
1383            sLog.outErrorDb("Spell %u listed in `spell_learn_spell` does not exist",node.spell);
1384            continue;
1385        }
1386
1387        mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell_id,node));
1388
1389        ++count;
1390    } while( result->NextRow() );
1391
1392    delete result;
1393
1394    // search auto-learned spells and add its to map also for use in unlearn spells/talents
1395    uint32 dbc_count = 0;
1396    for(uint32 spell = 0; spell < sSpellStore.GetNumRows(); ++spell)
1397    {
1398        SpellEntry const* entry = sSpellStore.LookupEntry(spell);
1399
1400        if(!entry)
1401            continue;
1402
1403        for(int i = 0; i < 3; ++i)
1404        {
1405            if(entry->Effect[i]==SPELL_EFFECT_LEARN_SPELL)
1406            {
1407                SpellLearnSpellNode dbc_node;
1408                dbc_node.spell       = entry->EffectTriggerSpell[i];
1409                dbc_node.autoLearned = true;
1410
1411                SpellLearnSpellMap::const_iterator db_node_begin = GetBeginSpellLearnSpell(spell);
1412                SpellLearnSpellMap::const_iterator db_node_end   = GetEndSpellLearnSpell(spell);
1413
1414                bool found = false;
1415                for(SpellLearnSpellMap::const_iterator itr = db_node_begin; itr != db_node_end; ++itr)
1416                {
1417                    if(itr->second.spell == dbc_node.spell)
1418                    {
1419                        sLog.outErrorDb("Spell %u auto-learn spell %u in spell.dbc then the record in `spell_learn_spell` is redundant, please fix DB.",
1420                            spell,dbc_node.spell);
1421                        found = true;
1422                        break;
1423                    }
1424                }
1425
1426                if(!found)                                  // add new spell-spell pair if not found
1427                {
1428                    mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell,dbc_node));
1429                    ++dbc_count;
1430                }
1431            }
1432        }
1433    }
1434
1435    sLog.outString();
1436    sLog.outString( ">> Loaded %u spell learn spells + %u found in DBC", count, dbc_count );
1437}
1438
1439void SpellMgr::LoadSpellScriptTarget()
1440{
1441    mSpellScriptTarget.clear();                             // need for reload case
1442
1443    uint32 count = 0;
1444
1445    QueryResult *result = WorldDatabase.Query("SELECT entry,type,targetEntry FROM spell_script_target");
1446
1447    if(!result)
1448    {
1449        barGoLink bar(1);
1450
1451        bar.step();
1452
1453        sLog.outString();
1454        sLog.outErrorDb(">> Loaded 0 SpellScriptTarget. DB table `spell_script_target` is empty.");
1455        return;
1456    }
1457
1458    barGoLink bar(result->GetRowCount());
1459
1460    do
1461    {
1462        Field *fields = result->Fetch();
1463        bar.step();
1464
1465        uint32 spellId     = fields[0].GetUInt32();
1466        uint32 type        = fields[1].GetUInt32();
1467        uint32 targetEntry = fields[2].GetUInt32();
1468
1469        SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId);
1470
1471        if(!spellProto)
1472        {
1473            sLog.outErrorDb("Table `spell_script_target`: spellId %u listed for TargetEntry %u does not exist.",spellId,targetEntry);
1474            continue;
1475        }
1476
1477        /*bool targetfound = false;
1478        for(int i = 0; i <3; ++i)
1479        {
1480            if( spellProto->EffectImplicitTargetA[i]==TARGET_SCRIPT ||
1481                spellProto->EffectImplicitTargetB[i]==TARGET_SCRIPT ||
1482                spellProto->EffectImplicitTargetA[i]==TARGET_SCRIPT_COORDINATES ||
1483                spellProto->EffectImplicitTargetB[i]==TARGET_SCRIPT_COORDINATES )
1484            {
1485                targetfound = true;
1486                break;
1487            }
1488        }
1489        if(!targetfound)
1490        {
1491            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);
1492            continue;
1493        }*/
1494
1495        if( type >= MAX_SPELL_TARGET_TYPE )
1496        {
1497            sLog.outErrorDb("Table `spell_script_target`: target type %u for TargetEntry %u is incorrect.",type,targetEntry);
1498            continue;
1499        }
1500
1501        switch(type)
1502        {
1503            case SPELL_TARGET_TYPE_GAMEOBJECT:
1504            {
1505                if( targetEntry==0 )
1506                    break;
1507
1508                if(!sGOStorage.LookupEntry<GameObjectInfo>(targetEntry))
1509                {
1510                    sLog.outErrorDb("Table `spell_script_target`: gameobject template entry %u does not exist.",targetEntry);
1511                    continue;
1512                }
1513                break;
1514            }
1515            default:
1516            {
1517                if( targetEntry==0 )
1518                {
1519                    sLog.outErrorDb("Table `spell_script_target`: target entry == 0 for not GO target type (%u).",type);
1520                    continue;
1521                }
1522                if(!sCreatureStorage.LookupEntry<CreatureInfo>(targetEntry))
1523                {
1524                    sLog.outErrorDb("Table `spell_script_target`: creature template entry %u does not exist.",targetEntry);
1525                    continue;
1526                }
1527                const CreatureInfo* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(targetEntry);
1528
1529                if(spellId == 30427 && !cInfo->SkinLootId)
1530                {
1531                    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);
1532                    continue;
1533                }
1534                break;
1535            }
1536        }
1537
1538        mSpellScriptTarget.insert(SpellScriptTarget::value_type(spellId,SpellTargetEntry(SpellTargetType(type),targetEntry)));
1539
1540        ++count;
1541    } while (result->NextRow());
1542
1543    delete result;
1544
1545    // Check all spells
1546    /* Disabled (lot errors at this moment)
1547    for(uint32 i = 1; i < sSpellStore.nCount; ++i)
1548    {
1549        SpellEntry const * spellInfo = sSpellStore.LookupEntry(i);
1550        if(!spellInfo)
1551            continue;
1552
1553        bool found = false;
1554        for(int j=0; j<3; ++j)
1555        {
1556            if( spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT || spellInfo->EffectImplicitTargetA[j] != TARGET_SELF && spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT )
1557            {
1558                SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(spellInfo->Id);
1559                SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(spellInfo->Id);
1560                if(lower==upper)
1561                {
1562                    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);
1563                    break;                                  // effects of spell
1564                }
1565            }
1566        }
1567    }
1568    */
1569
1570    sLog.outString();
1571    sLog.outString(">> Loaded %u Spell Script Targets", count);
1572}
1573
1574void SpellMgr::LoadSpellPetAuras()
1575{
1576    mSpellPetAuraMap.clear();                                  // need for reload case
1577
1578    uint32 count = 0;
1579
1580    //                                                0      1    2
1581    QueryResult *result = WorldDatabase.Query("SELECT spell, pet, aura FROM spell_pet_auras");
1582    if( !result )
1583    {
1584
1585        barGoLink bar( 1 );
1586
1587        bar.step();
1588
1589        sLog.outString();
1590        sLog.outString( ">> Loaded %u spell pet auras", count );
1591        return;
1592    }
1593
1594    barGoLink bar( result->GetRowCount() );
1595
1596    do
1597    {
1598        Field *fields = result->Fetch();
1599
1600        bar.step();
1601
1602        uint16 spell = fields[0].GetUInt16();
1603        uint16 pet = fields[1].GetUInt16();
1604        uint16 aura = fields[2].GetUInt16();
1605
1606        SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find(spell);
1607        if(itr != mSpellPetAuraMap.end())
1608        {
1609            itr->second.AddAura(pet, aura);
1610        }
1611        else
1612        {
1613            SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell);
1614            if (!spellInfo)
1615            {
1616                sLog.outErrorDb("Spell %u listed in `spell_pet_auras` does not exist", spell);
1617                continue;
1618            }
1619            int i = 0;
1620            for(; i < 3; ++i)
1621                if((spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA &&
1622                    spellInfo->EffectApplyAuraName[i] == SPELL_AURA_DUMMY) ||
1623                    spellInfo->Effect[i] == SPELL_EFFECT_DUMMY)
1624                    break;
1625
1626            if(i == 3)
1627            {
1628                sLog.outError("Spell %u listed in `spell_pet_auras` does not have dummy aura or dummy effect", spell);
1629                continue;
1630            }
1631
1632            SpellEntry const* spellInfo2 = sSpellStore.LookupEntry(aura);
1633            if (!spellInfo2)
1634            {
1635                sLog.outErrorDb("Aura %u listed in `spell_pet_auras` does not exist", aura);
1636                continue;
1637            }
1638
1639            PetAura pa(pet, aura, spellInfo->EffectImplicitTargetA[i] == TARGET_PET, spellInfo->EffectBasePoints[i] + spellInfo->EffectBaseDice[i]);
1640            mSpellPetAuraMap[spell] = pa;
1641        }
1642
1643        ++count;
1644    } while( result->NextRow() );
1645
1646    delete result;
1647
1648    sLog.outString();
1649    sLog.outString( ">> Loaded %u spell pet auras", count );
1650}
1651
1652// set data in core for now
1653void SpellMgr::LoadSpellCustomAttr()
1654{
1655    SpellEntry *tempSpell;
1656    for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i)
1657    {
1658        tempSpell = (SpellEntry*)GetSpellStore()->LookupEntry(i);
1659        if(!tempSpell)
1660            continue;
1661
1662        mSpellCustomAttrMap[tempSpell->Id] = 0;
1663
1664        for(uint32 i = 0; i < 3; ++i)
1665        {
1666            switch(tempSpell->EffectApplyAuraName[i])
1667            {
1668                case SPELL_AURA_PERIODIC_DAMAGE:
1669                case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
1670                case SPELL_AURA_PERIODIC_LEECH:
1671                    mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_EFFECT_DAMAGE;
1672                    break;
1673                case SPELL_AURA_PERIODIC_HEAL:
1674                case SPELL_AURA_OBS_MOD_HEALTH:
1675                    mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_EFFECT_HEAL;
1676                    break;
1677                default:
1678                    break;
1679            }
1680        }
1681
1682        if(tempSpell->SpellVisual == 3879)
1683            mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_CONE_BACK;
1684
1685        switch(tempSpell->Id)
1686        {
1687        case 26029: // dark glare
1688        case 37433: // spout
1689        case 43140: case 43215: // flame breath
1690            mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_CONE_LINE;
1691            break;
1692        case 24340: case 26558: case 28884:     // Meteor
1693        case 36837: case 38903: case 41276:     // Meteor
1694        case 26789:                             // Shard of the Fallen Star
1695        case 31436:                             // Malevolent Cleave
1696        case 35181:                             // Dive Bomb
1697        case 40810: case 43267: case 43268:     // Saber Lash
1698        case 42384:                             // Brutal Swipe
1699        case 45150:                             // Meteor Slash
1700            mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_SHARE_DAMAGE;
1701            break;
1702        case 44978: case 45001: case 45002:     // Wild Magic
1703        case 45004: case 45006: case 45010:     // Wild Magic
1704        case 31347: // Doom
1705        case 41635: // Prayer of Mending
1706            mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_PLAYERS_ONLY;
1707            tempSpell->MaxAffectedTargets = 1;
1708            break;
1709        case 41376: // Spite
1710        case 39992: // Needle Spine
1711            mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_PLAYERS_ONLY;
1712            tempSpell->MaxAffectedTargets = 3;
1713            break;
1714        case 8122: case 8124: case 10888: case 10890: // Psychic Scream
1715            tempSpell->Attributes |= SPELL_ATTR_BREAKABLE_BY_DAMAGE;
1716            break;
1717        default:
1718            break;
1719        }
1720    }
1721}
1722
1723void SpellMgr::LoadSpellLinked()
1724{
1725    mSpellLinkedMap.clear();    // need for reload case
1726    uint32 count = 0;
1727
1728    //                                                0              1             2
1729    QueryResult *result = WorldDatabase.Query("SELECT spell_trigger, spell_effect, type FROM spell_linked_spell");
1730    if( !result )
1731    {
1732        barGoLink bar( 1 );
1733        bar.step();
1734        sLog.outString();
1735        sLog.outString( ">> Loaded %u linked spells", count );
1736        return;
1737    }
1738
1739    barGoLink bar( result->GetRowCount() );
1740
1741    do
1742    {
1743        Field *fields = result->Fetch();
1744
1745        bar.step();
1746
1747        int32 trigger = fields[0].GetInt32();
1748        int32 effect = fields[1].GetInt32();
1749        int32 type = fields[2].GetInt32();
1750
1751        SpellEntry const* spellInfo = sSpellStore.LookupEntry(abs(trigger));
1752        if (!spellInfo)
1753        {
1754            sLog.outErrorDb("Spell %u listed in `spell_linked_spell` does not exist", abs(trigger));
1755            continue;
1756        }
1757        spellInfo = sSpellStore.LookupEntry(abs(effect));
1758        if (!spellInfo)
1759        {
1760            sLog.outErrorDb("Spell %u listed in `spell_linked_spell` does not exist", abs(effect));
1761            continue;
1762        }
1763
1764        if(type) //we will find a better way when more types are needed
1765            trigger += 1000000;
1766        mSpellLinkedMap[trigger].push_back(effect);
1767
1768        ++count;
1769    } while( result->NextRow() );
1770
1771    delete result;
1772
1773    sLog.outString();
1774    sLog.outString( ">> Loaded %u linked spells", count );
1775}
1776
1777/// Some checks for spells, to prevent adding depricated/broken spells for trainers, spell book, etc
1778bool SpellMgr::IsSpellValid(SpellEntry const* spellInfo, Player* pl, bool msg)
1779{
1780    // not exist
1781    if(!spellInfo)
1782        return false;
1783
1784    bool need_check_reagents = false;
1785
1786    // check effects
1787    for(int i=0; i<3; ++i)
1788    {
1789        switch(spellInfo->Effect[i])
1790        {
1791            case 0:
1792                continue;
1793
1794                // craft spell for crafting non-existed item (break client recipes list show)
1795            case SPELL_EFFECT_CREATE_ITEM:
1796            {
1797                if(!ObjectMgr::GetItemPrototype( spellInfo->EffectItemType[i] ))
1798                {
1799                    if(msg)
1800                    {
1801                        if(pl)
1802                            ChatHandler(pl).PSendSysMessage("Craft spell %u create not-exist in DB item (Entry: %u) and then...",spellInfo->Id,spellInfo->EffectItemType[i]);
1803                        else
1804                            sLog.outErrorDb("Craft spell %u create not-exist in DB item (Entry: %u) and then...",spellInfo->Id,spellInfo->EffectItemType[i]);
1805                    }
1806                    return false;
1807                }
1808
1809                need_check_reagents = true;
1810                break;
1811            }
1812            case SPELL_EFFECT_LEARN_SPELL:
1813            {
1814                SpellEntry const* spellInfo2 = sSpellStore.LookupEntry(spellInfo->EffectTriggerSpell[0]);
1815                if( !IsSpellValid(spellInfo2,pl,msg) )
1816                {
1817                    if(msg)
1818                    {
1819                        if(pl)
1820                            ChatHandler(pl).PSendSysMessage("Spell %u learn to broken spell %u, and then...",spellInfo->Id,spellInfo->EffectTriggerSpell[0]);
1821                        else
1822                            sLog.outErrorDb("Spell %u learn to invalid spell %u, and then...",spellInfo->Id,spellInfo->EffectTriggerSpell[0]);
1823                    }
1824                    return false;
1825                }
1826                break;
1827            }
1828        }
1829    }
1830
1831    if(need_check_reagents)
1832    {
1833        for(int j = 0; j < 8; ++j)
1834        {
1835            if(spellInfo->Reagent[j] > 0 && !ObjectMgr::GetItemPrototype( spellInfo->Reagent[j] ))
1836            {
1837                if(msg)
1838                {
1839                    if(pl)
1840                        ChatHandler(pl).PSendSysMessage("Craft spell %u have not-exist reagent in DB item (Entry: %u) and then...",spellInfo->Id,spellInfo->Reagent[j]);
1841                    else
1842                        sLog.outErrorDb("Craft spell %u have not-exist reagent in DB item (Entry: %u) and then...",spellInfo->Id,spellInfo->Reagent[j]);
1843                }
1844                return false;
1845            }
1846        }
1847    }
1848
1849    return true;
1850}
1851
1852bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id)
1853{
1854    // normal case
1855    if( spellInfo->AreaId && spellInfo->AreaId != zone_id && spellInfo->AreaId != area_id )
1856        return false;
1857
1858    // elixirs (all area dependent elixirs have family SPELLFAMILY_POTION, use this for speedup)
1859    if(spellInfo->SpellFamilyName==SPELLFAMILY_POTION)
1860    {
1861        if(uint32 mask = spellmgr.GetSpellElixirMask(spellInfo->Id))
1862        {
1863            if(mask & ELIXIR_UNSTABLE_MASK)
1864            {
1865                // in the Blade's Edge Mountains Plateaus and Gruul's Lair.
1866                return zone_id ==3522 || map_id==565;
1867            }
1868            if(mask & ELIXIR_SHATTRATH_MASK)
1869            {
1870                // in Tempest Keep, Serpentshrine Cavern, Caverns of Time: Mount Hyjal, Black Temple
1871                // TODO: and the Sunwell Plateau
1872                if(zone_id ==3607 || map_id==534 || map_id==564)
1873                    return true;
1874
1875                MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
1876                if(!mapEntry)
1877                    return false;
1878
1879                return mapEntry->multimap_id==206;
1880            }
1881
1882            // elixirs not have another limitations
1883            return true;
1884        }
1885    }
1886
1887    // special cases zone check (maps checked by multimap common id)
1888    switch(spellInfo->Id)
1889    {
1890        case 41618:
1891        case 41620:
1892        {
1893            MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
1894            if(!mapEntry)
1895                return false;
1896
1897            return mapEntry->multimap_id==206;
1898        }
1899
1900        case 41617:
1901        case 41619:
1902        {
1903            MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
1904            if(!mapEntry)
1905                return false;
1906
1907            return mapEntry->multimap_id==207;
1908        }
1909        // Dragonmaw Illusion
1910        case 40216:
1911        case 42016:
1912        {
1913            if ( area_id != 3759 && area_id != 3966 && area_id != 3939 )
1914                return false;
1915            break;
1916        }
1917    }
1918
1919    return true;
1920}
1921
1922void SpellMgr::LoadSkillLineAbilityMap()
1923{
1924    mSkillLineAbilityMap.clear();
1925
1926    uint32 count = 0;
1927
1928    for (uint32 i = 0; i < sSkillLineAbilityStore.GetNumRows(); i++)
1929    {
1930        SkillLineAbilityEntry const *SkillInfo = sSkillLineAbilityStore.LookupEntry(i);
1931        if(!SkillInfo)
1932            continue;
1933
1934        mSkillLineAbilityMap.insert(SkillLineAbilityMap::value_type(SkillInfo->spellId,SkillInfo));
1935        ++count;
1936    }
1937
1938    sLog.outString();
1939    sLog.outString(">> Loaded %u SkillLineAbility MultiMap", count);
1940}
1941
1942DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto, bool triggered)
1943{
1944    // Explicit Diminishing Groups
1945    switch(spellproto->SpellFamilyName)
1946    {
1947        case SPELLFAMILY_MAGE:
1948        {
1949            // Polymorph
1950            if ((spellproto->SpellFamilyFlags & 0x00001000000LL) && spellproto->EffectApplyAuraName[0]==SPELL_AURA_MOD_CONFUSE)
1951                return DIMINISHING_POLYMORPH;
1952            break;
1953        }
1954        case SPELLFAMILY_ROGUE:
1955        {
1956            // Kidney Shot
1957            if (spellproto->SpellFamilyFlags & 0x00000200000LL)
1958                return DIMINISHING_KIDNEYSHOT;
1959            // Blind
1960            else if (spellproto->SpellFamilyFlags & 0x00001000000LL)
1961                return DIMINISHING_BLIND_CYCLONE;
1962            break;
1963        }
1964        case SPELLFAMILY_WARLOCK:
1965        {
1966            // Death Coil
1967            if (spellproto->SpellFamilyFlags & 0x00000080000LL)
1968                return DIMINISHING_DEATHCOIL;
1969            // Fear
1970            else if (spellproto->SpellFamilyFlags & 0x40840000000LL)
1971                return DIMINISHING_WARLOCK_FEAR;
1972            // Curses/etc
1973            else if (spellproto->SpellFamilyFlags & 0x00080000000LL)
1974                return DIMINISHING_LIMITONLY;
1975            break;
1976        }
1977        case SPELLFAMILY_DRUID:
1978        {
1979            // Cyclone
1980            if (spellproto->SpellFamilyFlags & 0x02000000000LL)
1981                return DIMINISHING_BLIND_CYCLONE;
1982            break;
1983        }
1984        case SPELLFAMILY_WARRIOR:
1985        {
1986            // Hamstring - limit duration to 10s in PvP
1987            if (spellproto->SpellFamilyFlags & 0x00000000002LL)
1988                return DIMINISHING_LIMITONLY;
1989            break;
1990        }
1991        default:
1992            break;
1993    }
1994
1995    // Get by mechanic
1996    for (uint8 i=0;i<3;++i)
1997    {
1998        if (spellproto->Mechanic      == MECHANIC_STUN    || spellproto->EffectMechanic[i] == MECHANIC_STUN)
1999            return triggered ? DIMINISHING_TRIGGER_STUN : DIMINISHING_CONTROL_STUN;
2000        else if (spellproto->Mechanic == MECHANIC_SLEEP   || spellproto->EffectMechanic[i] == MECHANIC_SLEEP)
2001            return DIMINISHING_SLEEP;
2002        else if (spellproto->Mechanic == MECHANIC_ROOT    || spellproto->EffectMechanic[i] == MECHANIC_ROOT)
2003            return triggered ? DIMINISHING_TRIGGER_ROOT : DIMINISHING_CONTROL_ROOT;
2004        else if (spellproto->Mechanic == MECHANIC_FEAR    || spellproto->EffectMechanic[i] == MECHANIC_FEAR)
2005            return DIMINISHING_FEAR;
2006        else if (spellproto->Mechanic == MECHANIC_CHARM   || spellproto->EffectMechanic[i] == MECHANIC_CHARM)
2007            return DIMINISHING_CHARM;
2008        else if (spellproto->Mechanic == MECHANIC_SILENCE || spellproto->EffectMechanic[i] == MECHANIC_SILENCE)
2009            return DIMINISHING_SILENCE;
2010        else if (spellproto->Mechanic == MECHANIC_DISARM  || spellproto->EffectMechanic[i] == MECHANIC_DISARM)
2011            return DIMINISHING_DISARM;
2012        else if (spellproto->Mechanic == MECHANIC_FREEZE  || spellproto->EffectMechanic[i] == MECHANIC_FREEZE)
2013            return DIMINISHING_FREEZE;
2014        else if (spellproto->Mechanic == MECHANIC_KNOCKOUT|| spellproto->EffectMechanic[i] == MECHANIC_KNOCKOUT ||
2015                 spellproto->Mechanic == MECHANIC_SAPPED  || spellproto->EffectMechanic[i] == MECHANIC_SAPPED)
2016            return DIMINISHING_KNOCKOUT;
2017        else if (spellproto->Mechanic == MECHANIC_BANISH  || spellproto->EffectMechanic[i] == MECHANIC_BANISH)
2018            return DIMINISHING_BANISH;
2019    }
2020
2021    return DIMINISHING_NONE;
2022}
2023
2024bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group)
2025{
2026    switch(group)
2027    {
2028        case DIMINISHING_CONTROL_STUN:
2029        case DIMINISHING_TRIGGER_STUN:
2030        case DIMINISHING_KIDNEYSHOT:
2031        case DIMINISHING_SLEEP:
2032        case DIMINISHING_CONTROL_ROOT:
2033        case DIMINISHING_TRIGGER_ROOT:
2034        case DIMINISHING_FEAR:
2035        case DIMINISHING_WARLOCK_FEAR:
2036        case DIMINISHING_CHARM:
2037        case DIMINISHING_POLYMORPH:
2038        case DIMINISHING_FREEZE:
2039        case DIMINISHING_KNOCKOUT:
2040        case DIMINISHING_BLIND_CYCLONE:
2041        case DIMINISHING_BANISH:
2042        case DIMINISHING_LIMITONLY:
2043            return true;
2044    }
2045    return false;
2046}
2047
2048DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group)
2049{
2050    switch(group)
2051    {
2052        case DIMINISHING_BLIND_CYCLONE:
2053        case DIMINISHING_CONTROL_STUN:
2054        case DIMINISHING_TRIGGER_STUN:
2055        case DIMINISHING_KIDNEYSHOT:
2056            return DRTYPE_ALL;
2057        case DIMINISHING_SLEEP:
2058        case DIMINISHING_CONTROL_ROOT:
2059        case DIMINISHING_TRIGGER_ROOT:
2060        case DIMINISHING_FEAR:
2061        case DIMINISHING_CHARM:
2062        case DIMINISHING_POLYMORPH:
2063        case DIMINISHING_SILENCE:
2064        case DIMINISHING_DISARM:
2065        case DIMINISHING_DEATHCOIL:
2066        case DIMINISHING_FREEZE:
2067        case DIMINISHING_BANISH:
2068        case DIMINISHING_WARLOCK_FEAR:
2069        case DIMINISHING_KNOCKOUT:
2070            return DRTYPE_PLAYER;
2071    }
2072
2073    return DRTYPE_NONE;
2074}
Note: See TracBrowser for help on using the browser.