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

Revision 250, 75.7 kB (checked in by yumileroy, 17 years ago)

*Update aura stacking check. By QAston.
*Update pet autocast check. By qubix.

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