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

Revision 279, 73.6 kB (checked in by yumileroy, 17 years ago)

Merged commit 269 (5f0e38da128a).

Original author: gvcoman
Date: 2008-11-21 14:34:05-05:00

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