diff options
Diffstat (limited to 'src/game/SpellMgr.cpp')
| -rw-r--r-- | src/game/SpellMgr.cpp | 917 | 
1 files changed, 619 insertions, 298 deletions
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 43ee5d7d4a5..f312329192c 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -1,7 +1,7 @@  /* - * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>   * - * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> + * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@  #include "World.h"  #include "Chat.h"  #include "Spell.h" +#include "BattleGroundMgr.h"  bool IsAreaEffectTarget[TOTAL_SPELL_TARGETS]; @@ -38,25 +39,25 @@ SpellMgr::SpellMgr()              case SPELL_EFFECT_PERSISTENT_AREA_AURA: //27              case SPELL_EFFECT_SUMMON:               //28              case SPELL_EFFECT_TRIGGER_MISSILE:      //32 -            case SPELL_EFFECT_SUMMON_WILD:          //41 -            case SPELL_EFFECT_SUMMON_GUARDIAN:      //42 +            //case SPELL_EFFECT_SUMMON_WILD:          //41 not 303 +            //case SPELL_EFFECT_SUMMON_GUARDIAN:      //42 not 303              case SPELL_EFFECT_TRANS_DOOR:           //50 summon object              case SPELL_EFFECT_SUMMON_PET:           //56              case SPELL_EFFECT_ADD_FARSIGHT:         //72 -            case SPELL_EFFECT_SUMMON_POSSESSED:     //73 -            case SPELL_EFFECT_SUMMON_TOTEM:         //74 +            //case SPELL_EFFECT_SUMMON_POSSESSED:     //73 +            //case SPELL_EFFECT_SUMMON_TOTEM:         //74              case SPELL_EFFECT_SUMMON_OBJECT_WILD:   //76 -            case SPELL_EFFECT_SUMMON_TOTEM_SLOT1:   //87 -            case SPELL_EFFECT_SUMMON_TOTEM_SLOT2:   //88 -            case SPELL_EFFECT_SUMMON_TOTEM_SLOT3:   //89 -            case SPELL_EFFECT_SUMMON_TOTEM_SLOT4:   //90 -            case SPELL_EFFECT_SUMMON_CRITTER:       //97 +            //case SPELL_EFFECT_SUMMON_TOTEM_SLOT1:   //87 +            //case SPELL_EFFECT_SUMMON_TOTEM_SLOT2:   //88 +            //case SPELL_EFFECT_SUMMON_TOTEM_SLOT3:   //89 +            //case SPELL_EFFECT_SUMMON_TOTEM_SLOT4:   //90 +            //case SPELL_EFFECT_SUMMON_CRITTER:       //97 not 303              case SPELL_EFFECT_SUMMON_OBJECT_SLOT1:  //104              case SPELL_EFFECT_SUMMON_OBJECT_SLOT2:  //105              case SPELL_EFFECT_SUMMON_OBJECT_SLOT3:  //106              case SPELL_EFFECT_SUMMON_OBJECT_SLOT4:  //107              case SPELL_EFFECT_SUMMON_DEAD_PET:      //109 -            case SPELL_EFFECT_SUMMON_DEMON:         //112 +            //case SPELL_EFFECT_SUMMON_DEMON:         //112 not 303              case SPELL_EFFECT_TRIGGER_SPELL_2:      //151 ritual of summon                  EffectTargetType[i] = SPELL_REQUIRE_DEST;                  break; @@ -105,7 +106,6 @@ SpellMgr::SpellMgr()              case TARGET_UNIT_TARGET_ALLY:              case TARGET_UNIT_TARGET_RAID:              case TARGET_UNIT_TARGET_ANY: -            case TARGET_UNIT_SINGLE_UNKNOWN:              case TARGET_UNIT_TARGET_ENEMY:              case TARGET_UNIT_TARGET_PARTY:              case TARGET_UNIT_PARTY_TARGET: @@ -244,19 +244,8 @@ uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell)      int32 castTime = spellCastTimeEntry->CastTime; -    if (spell) -    { -        if(Player* modOwner = spell->GetCaster()->GetSpellModOwner()) -            modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell); - -        if( !(spellInfo->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_UNK5)) ) -            castTime = int32(castTime * spell->GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED)); -        else -        { -            if (spell->IsRangedSpell() && !spell->IsAutoRepeat()) -                castTime = int32(castTime * spell->GetCaster()->m_modAttackSpeedPct[RANGED_ATTACK]); -        } -    } +    if (spell && spell->GetCaster()) +        spell->GetCaster()->ModSpellCastTime(spellInfo, castTime);      if (spellInfo->Attributes & SPELL_ATTR_RANGED && (!spell || !(spell->IsAutoRepeat())))          castTime += 500; @@ -328,17 +317,17 @@ SpellSpecific GetSpellSpecific(uint32 spellId)          case SPELLFAMILY_MAGE:          {              // family flags 18(Molten), 25(Frost/Ice), 28(Mage) -            if (spellInfo->SpellFamilyFlags & 0x12040000) +            if (spellInfo->SpellFamilyFlags[0] & 0x12040000)                  return SPELL_MAGE_ARMOR; -            if ((spellInfo->SpellFamilyFlags & 0x1000000) && spellInfo->EffectApplyAuraName[0]==SPELL_AURA_MOD_CONFUSE) +            if ((spellInfo->SpellFamilyFlags[0] & 0x1000000) && spellInfo->EffectApplyAuraName[0]==SPELL_AURA_MOD_CONFUSE)                  return SPELL_MAGE_POLYMORPH;              break;          }          case SPELLFAMILY_WARRIOR:          { -            if (spellInfo->SpellFamilyFlags & 0x00008000010000LL) +            if (spellInfo->SpellFamilyFlags[1] & 0x000080 || spellInfo->SpellFamilyFlags[0] & 0x10000LL)                  return SPELL_POSITIVE_SHOUT;              break; @@ -349,12 +338,12 @@ SpellSpecific GetSpellSpecific(uint32 spellId)              if (spellInfo->Dispel == DISPEL_CURSE)                  return SPELL_CURSE; -            // family flag 37 (only part spells have family name) -            if (spellInfo->SpellFamilyFlags & 0x2000000000LL) +            // Warlock (Demon Armor | Demon Skin | Fel Armor) +            if (spellInfo->SpellFamilyFlags[1] & 0x20000020 || spellInfo->SpellFamilyFlags[2] & 0x00000010)                  return SPELL_WARLOCK_ARMOR;              //seed of corruption and corruption -            if (spellInfo->SpellFamilyFlags & 0x1000000002LL) +            if (spellInfo->SpellFamilyFlags[1] & 0x10 || spellInfo->SpellFamilyFlags[0] & 0x2)                  return SPELL_WARLOCK_CORRUPTION;              break;          } @@ -364,6 +353,13 @@ SpellSpecific GetSpellSpecific(uint32 spellId)              if (spellInfo->Dispel == DISPEL_POISON)                  return SPELL_STING; +            // only hunter aspects have this +            if( spellInfo->SpellFamilyFlags[1] & 0x00440000 || spellInfo->SpellFamilyFlags[0] & 0x00380000 || spellInfo->SpellFamilyFlags[2] & 0x00003010) +                return SPELL_ASPECT; + +            if( spellInfo->SpellFamilyFlags[2] & 0x00000002 ) +                return SPELL_TRACKER; +              break;          }          case SPELLFAMILY_PALADIN: @@ -371,16 +367,16 @@ SpellSpecific GetSpellSpecific(uint32 spellId)              if (IsSealSpell(spellInfo))                  return SPELL_SEAL; -            if (spellInfo->SpellFamilyFlags & 0x10000100LL) +            if (spellInfo->SpellFamilyFlags[0] & 0x11010002)                  return SPELL_BLESSING; -            if ((spellInfo->SpellFamilyFlags & 0x00000820180400LL) && (spellInfo->AttributesEx3 & 0x200)) +            if ((spellInfo->SpellFamilyFlags[1] & 0x000008 || spellInfo->SpellFamilyFlags[0] & 20180400) && (spellInfo->AttributesEx3 & 0x200))                  return SPELL_JUDGEMENT;              for (int i = 0; i < 3; i++)              { -                // only paladin auras have this -                if (spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY) +                // only paladin auras have this (for palaldin class family) +                if (spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_RAID)                      return SPELL_AURA;              }              break; @@ -395,19 +391,11 @@ SpellSpecific GetSpellSpecific(uint32 spellId)          case SPELLFAMILY_POTION:              return spellmgr.GetSpellElixirSpecific(spellInfo->Id); -    } -    // only warlock armor/skin have this (in additional to family cases) -    if( spellInfo->SpellVisual == 130 && spellInfo->SpellIconID == 89) -    { -        return SPELL_WARLOCK_ARMOR; -    } - -    // only hunter aspects have this (but not all aspects in hunter family) -    if( spellInfo->activeIconID == 122 && (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_NATURE) && -        (spellInfo->Attributes & 0x50000) != 0 && (spellInfo->Attributes & 0x9000010) == 0) -    { -        return SPELL_ASPECT; +        case SPELLFAMILY_DEATHKNIGHT: +            if ((spellInfo->Attributes & 0x10) && (spellInfo->AttributesEx2 & 0x10) && (spellInfo->AttributesEx4 & 0x200000)) +                return SPELL_PRESENCE; +            break;      }      for(int i = 0; i < 3; ++i) @@ -416,10 +404,6 @@ SpellSpecific GetSpellSpecific(uint32 spellId)          {              switch(spellInfo->EffectApplyAuraName[i])              { -                case SPELL_AURA_TRACK_CREATURES: -                case SPELL_AURA_TRACK_RESOURCES: -                case SPELL_AURA_TRACK_STEALTHED: -                    return SPELL_TRACKER;                  case SPELL_AURA_MOD_CHARM:                  case SPELL_AURA_MOD_POSSESS_PET:                  case SPELL_AURA_MOD_POSSESS: @@ -427,7 +411,6 @@ SpellSpecific GetSpellSpecific(uint32 spellId)              }          }      } -      // elixirs can have different families, but potion most ofc.      if(SpellSpecific sp = spellmgr.GetSpellElixirSpecific(spellInfo->Id))          return sp; @@ -463,6 +446,7 @@ bool IsSingleFromSpellSpecificPerTarget(uint32 spellSpec1,uint32 spellSpec2)          case SPELL_MAGE_ARMOR:          case SPELL_ELEMENTAL_SHIELD:          case SPELL_MAGE_POLYMORPH: +        case SPELL_PRESENCE:          case SPELL_WELL_FED:          case SPELL_DRINK:          case SPELL_FOOD: @@ -496,8 +480,6 @@ bool IsPositiveTarget(uint32 targetA, uint32 targetB)          case TARGET_CURRENT_ENEMY_COORDINATES:          case TARGET_UNIT_CHANNEL:              return false; -        case TARGET_ALL_AROUND_CASTER: -            return (targetB == TARGET_ALL_PARTY || targetB == TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER);          default:              break;      } @@ -906,8 +888,8 @@ void SpellMgr::LoadSpellAffects()      uint32 count = 0; -    //                                                0      1         2 -    QueryResult *result = WorldDatabase.Query("SELECT entry, effectId, SpellFamilyMask FROM spell_affect"); +    //                                                0      1         2                3                4 +    QueryResult *result = WorldDatabase.Query("SELECT entry, effectId, SpellClassMask0, SpellClassMask1, SpellClassMask2 FROM spell_affect");      if( !result )      { @@ -954,26 +936,22 @@ void SpellMgr::LoadSpellAffects()              continue;          } -        uint64 spellAffectMask = fields[2].GetUInt64(); +        flag96 affect(fields[2].GetUInt32(), fields[3].GetUInt32(), fields[4].GetUInt32()); -        // Spell.dbc have own data for low part of SpellFamilyMask -        if( spellInfo->EffectItemType[effectId]) -        { -            if(spellInfo->EffectItemType[effectId] == spellAffectMask) -            { -                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); -                continue; -            } +        // Spell.dbc have own data +        if (effectId>3) +            continue; -            // 24429 have wrong data in EffectItemType and overwrites by DB, possible bug in client -            if(spellInfo->Id!=24429 && spellInfo->EffectItemType[effectId] != spellAffectMask) -            { -                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); -                continue; -            } +        flag96 dbc_affect; +        dbc_affect = spellInfo->EffectSpellClassMask[effectId]; +        if(dbc_affect[0] == affect[0] || dbc_affect[1] == affect[1] || dbc_affect[2] == affect[2]) +        { +            char text[]="ABC"; +            sLog.outErrorDb("Spell %u listed in `spell_affect` have redundant (same with EffectSpellClassMask%c) data for effect index (%u) and not needed, skipped.", entry, text[effectId], effectId); +            continue;          } -        mSpellAffectMap.insert(SpellAffectMap::value_type((entry<<8) + effectId,spellAffectMask)); +        mSpellAffectMap[(entry<<8) + effectId] = affect;          ++count;      } while( result->NextRow() ); @@ -981,7 +959,7 @@ void SpellMgr::LoadSpellAffects()      delete result;      sLog.outString(); -    sLog.outString( ">> Loaded %u spell affect definitions", count ); +    sLog.outString( ">> Loaded %u custom spell affect definitions", count );      for (uint32 id = 0; id < sSpellStore.GetNumRows(); ++id)      { @@ -997,7 +975,9 @@ void SpellMgr::LoadSpellAffects()                  spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_TARGET_TRIGGER) )                  continue; -            if(spellInfo->EffectItemType[effectId] != 0) +            flag96 dbc_affect; +            dbc_affect = spellInfo->EffectSpellClassMask[effectId]; +            if(dbc_affect)                  continue;              if(mSpellAffectMap.find((id<<8) + effectId) !=  mSpellAffectMap.end()) @@ -1008,33 +988,19 @@ void SpellMgr::LoadSpellAffects()      }  } -bool SpellMgr::IsAffectedBySpell(SpellEntry const *spellInfo, uint32 spellId, uint8 effectId, uint64 familyFlags) const +bool SpellMgr::IsAffectedByMod(SpellEntry const *spellInfo, SpellModifier *mod) const  {      // false for spellInfo == NULL -    if (!spellInfo) +    if (!spellInfo || !mod)          return false; -    SpellEntry const *affect_spell = sSpellStore.LookupEntry(spellId); -    // false for affect_spell == NULL -    if (!affect_spell) +    SpellEntry const *affect_spell = sSpellStore.LookupEntry(mod->spellId); +    // False if affect_spell == NULL or spellFamily not equal +    if (!affect_spell || affect_spell->SpellFamilyName != spellInfo->SpellFamilyName)          return false; -    // False if spellFamily not equal -    if (affect_spell->SpellFamilyName != spellInfo->SpellFamilyName) -        return false; - -    // If familyFlags == 0 -    if (!familyFlags) -    { -        // Get it from spellAffect table -        familyFlags = GetSpellAffectMask(spellId,effectId); -        // false if familyFlags == 0 -        if (!familyFlags) -            return false; -    } -      // true -    if (familyFlags & spellInfo->SpellFamilyFlags) +    if (mod->mask  & spellInfo->SpellFamilyFlags)          return true;      return false; @@ -1046,15 +1012,12 @@ void SpellMgr::LoadSpellProcEvents()      uint32 count = 0; -    //                                                0      1           2                3                4          5       6        7             8 -    QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event"); +    //                                                0      1           2                3                 4                 5                 6          7       8        9             10 +    QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");      if( !result )      { -          barGoLink bar( 1 ); -          bar.step(); -          sLog.outString();          sLog.outString( ">> Loaded %u spell proc event conditions", count  );          return; @@ -1068,7 +1031,7 @@ void SpellMgr::LoadSpellProcEvents()          bar.step(); -        uint16 entry = fields[0].GetUInt16(); +        uint32 entry = fields[0].GetUInt32();          const SpellEntry *spell = sSpellStore.LookupEntry(entry);          if (!spell) @@ -1081,12 +1044,13 @@ void SpellMgr::LoadSpellProcEvents()          spe.schoolMask      = fields[1].GetUInt32();          spe.spellFamilyName = fields[2].GetUInt32(); -        spe.spellFamilyMask = fields[3].GetUInt64(); -        spe.procFlags       = fields[4].GetUInt32(); -        spe.procEx          = fields[5].GetUInt32(); -        spe.ppmRate         = fields[6].GetFloat(); -        spe.customChance    = fields[7].GetFloat(); -        spe.cooldown        = fields[8].GetUInt32(); +        spe.spellFamilyMask = (uint64)fields[3].GetUInt32()|((uint64)fields[4].GetUInt32()<<32); +        spe.spellFamilyMask2= fields[5].GetUInt32(); +        spe.procFlags       = fields[6].GetUInt32(); +        spe.procEx          = fields[7].GetUInt32(); +        spe.ppmRate         = fields[8].GetFloat(); +        spe.customChance    = fields[9].GetFloat(); +        spe.cooldown        = fields[10].GetUInt32();          mSpellProcEventMap[entry] = spe; @@ -1106,80 +1070,54 @@ void SpellMgr::LoadSpellProcEvents()      sLog.outString();      if (customProc) -        sLog.outString( ">> Loaded %u custom spell proc event conditions +%u custom",  count, customProc ); +        sLog.outString( ">> Loaded %u extra spell proc event conditions +%u custom",  count, customProc );      else -        sLog.outString( ">> Loaded %u spell proc event conditions", count ); +        sLog.outString( ">> Loaded %u extra spell proc event conditions", count ); +} -    /* -    // Commented for now, as it still produces many errors (still quite many spells miss spell_proc_event) -    for (uint32 id = 0; id < sSpellStore.GetNumRows(); ++id) +void SpellMgr::LoadSpellBonusess() +{ +    mSpellBonusMap.clear();                             // need for reload case +    uint32 count = 0; +    //                                                0      1             2          3 +    QueryResult *result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus FROM spell_bonus_data"); +    if( !result )      { -        SpellEntry const* spellInfo = sSpellStore.LookupEntry(id); -        if (!spellInfo) -            continue; - -        bool found = false; -        for (int effectId = 0; effectId < 3; ++effectId) -        { -            // at this moment check only SPELL_AURA_PROC_TRIGGER_SPELL -            if( spellInfo->EffectApplyAuraName[effectId] == SPELL_AURA_PROC_TRIGGER_SPELL ) -            { -                found = true; -                break; -            } -        } +        barGoLink bar( 1 ); +        bar.step(); +        sLog.outString(); +        sLog.outString( ">> Loaded %u spell bonus data", count); +        return; +    } -        if(!found) -            continue; +    barGoLink bar( result->GetRowCount() ); +    do +    { +        Field *fields = result->Fetch(); +        bar.step(); +        uint32 entry = fields[0].GetUInt32(); -        if(GetSpellProcEvent(id)) +        const SpellEntry *spell = sSpellStore.LookupEntry(entry); +        if (!spell) +        { +            sLog.outErrorDb("Spell %u listed in `spell_bonus_data` does not exist", entry);              continue; +        } -        sLog.outErrorDb("Spell %u (%s) misses spell_proc_event",id,spellInfo->SpellName[sWorld.GetDBClang()]); -    } -    */ -} - -/* -bool SpellMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags ) -{ -    if((procFlags & spellProcEvent->procFlags) == 0) -        return false; +        SpellBonusEntry sbe; -    // Additional checks in case spell cast/hit/crit is the event -    // Check (if set) school, category, skill line, spell talent mask -    if(spellProcEvent->schoolMask && (!procSpell || (GetSpellSchoolMask(procSpell) & spellProcEvent->schoolMask) == 0)) -        return false; -    if(spellProcEvent->category && (!procSpell || procSpell->Category != spellProcEvent->category)) -        return false; -    if(spellProcEvent->skillId) -    { -        if (!procSpell) -            return false; +        sbe.direct_damage = fields[1].GetFloat(); +        sbe.dot_damage    = fields[2].GetFloat(); +        sbe.ap_bonus      = fields[3].GetFloat(); -        SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(procSpell->Id); -        SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(procSpell->Id); +        mSpellBonusMap[entry] = sbe; +    } while( result->NextRow() ); -        bool found = false; -        for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) -        { -            if(_spell_idx->second->skillId == spellProcEvent->skillId) -            { -                found = true; -                break; -            } -        } -        if (!found) -            return false; -    } -    if(spellProcEvent->spellFamilyName && (!procSpell || spellProcEvent->spellFamilyName != procSpell->SpellFamilyName)) -        return false; -    if(spellProcEvent->spellFamilyMask && (!procSpell || (spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0)) -        return false; +    delete result; -    return true; +    sLog.outString(); +    sLog.outString( ">> Loaded %u extra spell bonus data",  count);  } -*/  bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active)  { @@ -1191,7 +1129,7 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellP          return false;      // Always trigger for this -    if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL_AND_GET_XP)) +    if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_ON_TRAP_ACTIVATION))          return true;      if (spellProcEvent)     // Exist event data @@ -1217,9 +1155,9 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellP                  return false;              // spellFamilyName is Ok need check for spellFamilyMask if present -            if(spellProcEvent->spellFamilyMask) +            if(spellProcEvent->spellFamilyMask || spellProcEvent->spellFamilyMask2)              { -                if ((spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0) +                if ((spellProcEvent->spellFamilyMask  & procSpell->SpellFamilyFlags ) == 0)                      return false;                  active = true; // Spell added manualy -> so its active spell              } @@ -1318,28 +1256,38 @@ bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellI  bool SpellMgr::canStackSpellRanks(SpellEntry const *spellInfo)  { +    if(IsPassiveSpell(spellInfo->Id))                       // ranked passive spell +        return false;      if(spellInfo->powerType != POWER_MANA && spellInfo->powerType != POWER_HEALTH)          return false; -    if(IsProfessionSpell(spellInfo->Id)) +    if(IsProfessionOrRidingSpell(spellInfo->Id)) +        return false; + +    if(spellmgr.IsSkillBonusSpell(spellInfo->Id))          return false;      // All stance spells. if any better way, change it.      for (int i = 0; i < 3; i++)      { -        // Paladin aura Spell -        if(spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN -            && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AREA_AURA_PARTY) -            return false; -        // Druid form Spell -        if(spellInfo->SpellFamilyName == SPELLFAMILY_DRUID -            && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA -            && spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT) -            return false; -        // Rogue Stealth -        if(spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE -            && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA -            && spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT) -            return false; +        switch(spellInfo->SpellFamilyName) +        { +            case SPELLFAMILY_PALADIN: +                // Paladin aura Spell +                if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AREA_AURA_RAID) +                    return false; +                break; +            case SPELLFAMILY_DRUID: +                // Druid form Spell +                if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA && +                    spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT) +                    return false; +                break; +            case SPELLFAMILY_ROGUE: +                // Rogue Stealth +                if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA && +                    spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT) +                    return false; +        }      }      return true;  } @@ -1368,6 +1316,11 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool      if(spellInfo_1->SpellFamilyName != spellInfo_2->SpellFamilyName)          return false; +    // TODO: Is this needed? +    // Allow stack passive and not passive spells +    if ((spellInfo_1->Attributes & SPELL_ATTR_PASSIVE)!=(spellInfo_2->Attributes & SPELL_ATTR_PASSIVE)) +        return false; +      // generic spells      if(!spellInfo_1->SpellFamilyName)      { @@ -1422,6 +1375,21 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool      return true;  } + +bool SpellMgr::IsProfessionOrRidingSpell(uint32 spellId) +{ +    SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); +    if(!spellInfo) +        return false; + +    if(spellInfo->Effect[1] != SPELL_EFFECT_SKILL) +        return false; + +    uint32 skill = spellInfo->EffectMiscValue[1]; + +    return IsProfessionOrRidingSkill(skill); +} +  bool SpellMgr::IsProfessionSpell(uint32 spellId)  {      SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); @@ -1455,6 +1423,24 @@ bool SpellMgr::IsPrimaryProfessionFirstRankSpell(uint32 spellId) const      return IsPrimaryProfessionSpell(spellId) && GetSpellRank(spellId)==1;  } +bool SpellMgr::IsSkillBonusSpell(uint32 spellId) const +{ +    SkillLineAbilityMap::const_iterator lower = GetBeginSkillLineAbilityMap(spellId); +    SkillLineAbilityMap::const_iterator upper = GetEndSkillLineAbilityMap(spellId); + +    for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) +    { +        SkillLineAbilityEntry const *pAbility = _spell_idx->second; +        if (!pAbility || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL) +            continue; + +        if(pAbility->req_skill_value > 0) +            return true; +    } + +    return false; +} +  SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spellInfo, uint32 playerLevel) const  {      // ignore passive spells @@ -1466,7 +1452,8 @@ SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spell      {          if( IsPositiveEffect(spellInfo->Id, i) && (              spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA || -            spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY +            spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY || +            spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_RAID              ) )          {              needRankSelection = true; @@ -1541,21 +1528,31 @@ struct SpellRankEntry      uint32 RangeIndex;      uint32 SpellVisual;      uint32 ProcFlags; -    uint64 SpellFamilyFlags; +    flag96 SpellFamilyFlags;      uint32 TargetAuraState;      uint32 ManaCost; - -    bool operator()(const SpellRankEntry & _Left,const SpellRankEntry & _Right)const -    { -        return (_Left.SkillId != _Right.SkillId ? _Left.SkillId < _Right.SkillId -            : _Left.SpellName!=_Right.SpellName ? _Left.SpellName < _Right.SpellName -            : _Left.ProcFlags!=_Right.ProcFlags ? _Left.ProcFlags < _Right.ProcFlags -            : _Left.SpellFamilyFlags!=_Right.SpellFamilyFlags ? _Left.SpellFamilyFlags < _Right.SpellFamilyFlags -            : (_Left.SpellVisual!=_Right.SpellVisual) && (!_Left.SpellVisual || !_Right.SpellVisual) ? _Left.SpellVisual < _Right.SpellVisual -            : (_Left.ManaCost!=_Right.ManaCost) && (!_Left.ManaCost || !_Right.ManaCost) ? _Left.ManaCost < _Right.ManaCost -            : (_Left.DurationIndex!=_Right.DurationIndex) && (!_Left.DurationIndex || !_Right.DurationIndex)? _Left.DurationIndex < _Right.DurationIndex -            : (_Left.RangeIndex!=_Right.RangeIndex) && (!_Left.RangeIndex || !_Right.RangeIndex || _Left.RangeIndex==1 || !_Right.RangeIndex==1) ? _Left.RangeIndex < _Right.RangeIndex -            : _Left.TargetAuraState < _Right.TargetAuraState +    uint32 CastingTimeIndex; +    flag96 Effect; +    flag96 Aura; +    uint16 TalentID; + +    bool operator < (const SpellRankEntry & _Right) const +    { +        return (SkillId != _Right.SkillId ? SkillId < _Right.SkillId +            : SpellName!=_Right.SpellName ? SpellName < _Right.SpellName +            : ProcFlags!=_Right.ProcFlags ? ProcFlags < _Right.ProcFlags + +            : Effect!=_Right.Effect ? Effect < _Right.Effect +            : Aura!=_Right.Aura ? Aura < _Right.Aura +            : TalentID!=_Right.TalentID ? TalentID < _Right.TalentID +            : (CastingTimeIndex!=_Right.CastingTimeIndex) && (!CastingTimeIndex || !_Right.CastingTimeIndex || CastingTimeIndex==1 || !_Right.CastingTimeIndex==1) ? CastingTimeIndex < _Right.CastingTimeIndex + +            : SpellFamilyFlags!=_Right.SpellFamilyFlags ? SpellFamilyFlags < _Right.SpellFamilyFlags +            : (SpellVisual!=_Right.SpellVisual) && (!SpellVisual || !_Right.SpellVisual) ? SpellVisual < _Right.SpellVisual +            : (ManaCost!=_Right.ManaCost) && (!ManaCost || !_Right.ManaCost) ? ManaCost < _Right.ManaCost +            : (DurationIndex!=_Right.DurationIndex) && (!DurationIndex || !_Right.DurationIndex)? DurationIndex < _Right.DurationIndex +            : (RangeIndex!=_Right.RangeIndex) && (!RangeIndex || !_Right.RangeIndex || RangeIndex==1 || !_Right.RangeIndex==1) ? RangeIndex < _Right.RangeIndex +            : TargetAuraState < _Right.TargetAuraState              );      }  }; @@ -1564,6 +1561,7 @@ struct SpellRankValue  {      uint32 Id;      char const *Rank; +    bool strict;  };  void SpellMgr::LoadSpellChains() @@ -1576,14 +1574,12 @@ void SpellMgr::LoadSpellChains()          SkillLineAbilityEntry const *AbilityInfo=sSkillLineAbilityStore.LookupEntry(ability_id);          if (!AbilityInfo)              continue; -        if (AbilityInfo->spellId==20154) //exception to these rules (not needed in 3.0.3) -            continue;          if (!AbilityInfo->forward_spellid)              continue;          ChainedSpells.push_back(AbilityInfo->forward_spellid);      } -    std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry> RankMap; +    std::multimap<SpellRankEntry, SpellRankValue> RankMap;      for (uint32 ability_id=0;ability_id<sSkillLineAbilityStore.GetNumRows();ability_id++)      { @@ -1593,8 +1589,6 @@ void SpellMgr::LoadSpellChains()          //get only spell with lowest ability_id to prevent doubles          uint32 spell_id=AbilityInfo->spellId; -        if (spell_id==20154) //exception to these rules (not needed in 3.0.3) -            continue;          bool found=false;          for (uint32 i=0; i<ChainedSpells.size(); i++)          { @@ -1613,7 +1607,7 @@ void SpellMgr::LoadSpellChains()          if(sRank.empty())              continue;          //exception to polymorph spells-make pig and turtle other chain than sheep -        if ((SpellInfo->SpellFamilyName==SPELLFAMILY_MAGE) && (SpellInfo->SpellFamilyFlags & 0x1000000) && (SpellInfo->SpellIconID!=82)) +        if ((SpellInfo->SpellFamilyName==SPELLFAMILY_MAGE) && (SpellInfo->SpellFamilyFlags[0] & 0x1000000) && (SpellInfo->SpellIconID!=82))              continue;          SpellRankEntry entry; @@ -1625,14 +1619,16 @@ void SpellMgr::LoadSpellChains()          entry.ProcFlags=SpellInfo->procFlags;          entry.SpellFamilyFlags=SpellInfo->SpellFamilyFlags;          entry.TargetAuraState=SpellInfo->TargetAuraState; -        entry.SpellVisual=SpellInfo->SpellVisual; +        entry.SpellVisual=SpellInfo->SpellVisual[0];          entry.ManaCost=SpellInfo->manaCost; - +        entry.CastingTimeIndex=0; +        entry.TalentID=0;          for (;;)          {              AbilityInfo=mSkillLineAbilityMap.lower_bound(spell_id)->second;              value.Id=spell_id;              value.Rank=SpellInfo->Rank[sWorld.GetDefaultDbcLocale()]; +            value.strict=false;              RankMap.insert(std::pair<SpellRankEntry, SpellRankValue>(entry,value));              spell_id=AbilityInfo->forward_spellid;              SpellInfo=sSpellStore.LookupEntry(spell_id); @@ -1645,48 +1641,109 @@ void SpellMgr::LoadSpellChains()      uint32 count=0; -    for (std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator itr = RankMap.begin();itr!=RankMap.end();) +    for (std::multimap<SpellRankEntry, SpellRankValue>::iterator itr = RankMap.begin();itr!=RankMap.end();)      {          SpellRankEntry entry=itr->first;          //trac errors in extracted data -        std::multimap<char const *, std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator> RankErrorMap; -        for (std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator itr2 = RankMap.lower_bound(entry);itr2!=RankMap.upper_bound(entry);itr2++) +        std::multimap<char const *, std::multimap<SpellRankEntry, SpellRankValue>::iterator> RankErrorMap; +        for (std::multimap<SpellRankEntry, SpellRankValue>::iterator itr2 = RankMap.lower_bound(entry);itr2!=RankMap.upper_bound(entry);itr2++)          {              bar.step(); -            RankErrorMap.insert(std::pair<char const *, std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator>(itr2->second.Rank,itr2)); -        } -        for (std::multimap<char const *, std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator>::iterator itr2 = RankErrorMap.begin();itr2!=RankErrorMap.end();) -        { -            char const * err_entry=itr2->first; -            uint32 rank_count=RankErrorMap.count(itr2->first); -            if (rank_count>1) -            for (itr2 = RankErrorMap.lower_bound(err_entry);itr2!=RankErrorMap.upper_bound(err_entry);itr2++) +            RankErrorMap.insert(std::pair<char const *, std::multimap<SpellRankEntry, SpellRankValue>::iterator>(itr2->second.Rank,itr2)); +        } +         +        bool error=false; +        //if strict == true strict check is not needed +        if (!itr->second.strict) +            //check for rank duplicates, if there are any do strict check +            for (std::multimap<char const *, std::multimap<SpellRankEntry, SpellRankValue>::iterator>::iterator itr2 = RankErrorMap.begin();itr2!=RankErrorMap.end();)              { -                sLog.outDebug("There is a duplicate rank entry (%s) for spell: %u",itr2->first,itr2->second->second.Id); -                sLog.outDebug("Spell %u removed from chain data.",itr2->second->second.Id); -                RankMap.erase(itr2->second); -                itr=RankMap.lower_bound(entry); +                char const * err_entry=itr2->first; +                uint32 rank_count=RankErrorMap.count(itr2->first); +                if (rank_count>1) +                { +                    error=true; +                    break; +                } +                else +                    itr2++;              } -            else -                itr2++; -        } -        //do not proceed for spells with less than 2 ranks -        uint32 spell_max_rank=RankMap.count(entry); -        if (spell_max_rank<2) +        bool allHaveTalents=true; +        if (error)          { -            itr=RankMap.upper_bound(entry); +            std::list<uint32> ConflictedSpells; +            for (std::multimap<SpellRankEntry, SpellRankValue>::iterator itr2 = RankMap.lower_bound(entry);itr2!=RankMap.upper_bound(entry);itr2=RankMap.lower_bound(entry)) +            { +                ConflictedSpells.push_back(itr2->second.Id); +                if (!GetTalentSpellPos(itr2->second.Id)) +                    allHaveTalents=false; +                RankMap.erase(itr2); +            } +            SpellRankEntry nextEntry, currEntry; +            for (;!ConflictedSpells.empty();ConflictedSpells.pop_front()) +            { +                SpellEntry const *SpellInfo=sSpellStore.LookupEntry(ConflictedSpells.front()); +                currEntry.SkillId=entry.SkillId; +                currEntry.SpellName=SpellInfo->SpellName[sWorld.GetDefaultDbcLocale()]; +                currEntry.DurationIndex=SpellInfo->DurationIndex; +                currEntry.RangeIndex=SpellInfo->rangeIndex; +                currEntry.ProcFlags=SpellInfo->procFlags; +                currEntry.SpellFamilyFlags=SpellInfo->SpellFamilyFlags; +                //compare talents only when all spells from chain have entry +                //to prevent wrong results with spells which have first rank talented and other not +                if (allHaveTalents) +                    currEntry.TalentID=GetTalentSpellPos(ConflictedSpells.front())->talent_id; +                else +                    currEntry.TalentID=0; +                currEntry.TargetAuraState=SpellInfo->TargetAuraState; +                currEntry.SpellVisual=SpellInfo->SpellVisual[0]; +                currEntry.ManaCost=SpellInfo->manaCost; + +                //compare effects and casting time +                currEntry.CastingTimeIndex=SpellInfo->CastingTimeIndex; +                currEntry.Effect[0]=SpellInfo->Effect[0]; +                currEntry.Effect[1]=SpellInfo->Effect[1]; +                currEntry.Effect[2]=SpellInfo->Effect[2]; + +                currEntry.Aura[0]=SpellInfo->EffectApplyAuraName[0]; +                currEntry.Aura[1]=SpellInfo->EffectApplyAuraName[1]; +                currEntry.Aura[2]=SpellInfo->EffectApplyAuraName[2]; + +                SpellRankValue currValue; +                currValue.Id=ConflictedSpells.front(); +                currValue.Rank=SpellInfo->Rank[sWorld.GetDefaultDbcLocale()]; +                currValue.strict=true; +                RankMap.insert(std::pair<SpellRankEntry, SpellRankValue>(currEntry,currValue)); +            } +            itr=RankMap.begin();              continue;          } +        else +            for (std::multimap<char const *, std::multimap<SpellRankEntry, SpellRankValue>::iterator>::iterator itr2 = RankErrorMap.begin();itr2!=RankErrorMap.end();) +            { +                char const * err_entry=itr2->first; +                uint32 rank_count=RankErrorMap.count(itr2->first); +                if (rank_count>1) +                for (itr2 = RankErrorMap.lower_bound(err_entry);itr2!=RankErrorMap.upper_bound(err_entry);itr2++) +                { +                    sLog.outDebug("There is a duplicate rank entry (%s) for spell: %u",itr2->first,itr2->second->second.Id); +                    if (!(itr2->second->second.Id==52375 || itr2->second->second.Id==45902)) +                    { +                        sLog.outDebug("Spell %u removed from chain data.",itr2->second->second.Id); +                        RankMap.erase(itr2->second); +                    } +                } +                else +                    itr2++; +            } -        itr=RankMap.upper_bound(entry); - -        //order spells by spells by spellLevel +        //order spells by spellLevel          std::list<uint32> RankedSpells;          uint32 min_spell_lvl=0; -        std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator min_itr; +        std::multimap<SpellRankEntry, SpellRankValue>::iterator min_itr;          for (;RankMap.count(entry);)          { -            for (std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator itr2 = RankMap.lower_bound(entry);itr2!=RankMap.upper_bound(entry);itr2++) +            for (std::multimap<SpellRankEntry, SpellRankValue>::iterator itr2 = RankMap.lower_bound(entry);itr2!=RankMap.upper_bound(entry);itr2++)              {                  SpellEntry const *SpellInfo=sSpellStore.LookupEntry(itr2->second.Id);                  if (SpellInfo->spellLevel<min_spell_lvl || itr2==RankMap.lower_bound(entry)) @@ -1722,9 +1779,13 @@ void SpellMgr::LoadSpellChains()              }          } +        //do not proceed for spells with less than 2 ranks +        itr=RankMap.begin(); +        if (RankedSpells.size()<2) +            continue; +          count++; -        itr=RankMap.upper_bound(entry);          uint32 spell_rank=1;          for(std::list<uint32>::iterator itr2 = RankedSpells.begin();itr2!=RankedSpells.end();spell_rank++)          { @@ -1748,8 +1809,8 @@ void SpellMgr::LoadSpellChains()      }  //uncomment these two lines to print yourself list of spell_chains on startup -//    for (UNORDERED_MAP<uint32, SpellChainNode>::iterator itr=mSpellChains.begin();itr!=mSpellChains.end();itr++) -//       sLog.outString( "Id: %u, Rank: %d , %s",itr->first,itr->second.rank, sSpellStore.LookupEntry(itr->first)->Rank[sWorld.GetDefaultDbcLocale()]); +    //for (UNORDERED_MAP<uint32, SpellChainNode>::iterator itr=mSpellChains.begin();itr!=mSpellChains.end();itr++) +       //sLog.outString( "Id: %u, Rank: %d , %s, %u, %u, %u, %u",itr->first,itr->second.rank, sSpellStore.LookupEntry(itr->first)->Rank[sWorld.GetDefaultDbcLocale()], itr->second.first, itr->second.last,itr->second.next ,itr->second.prev);      sLog.outString();      sLog.outString( ">> Loaded %u spell chains",count); @@ -1761,8 +1822,10 @@ void SpellMgr::LoadSpellLearnSkills()      // search auto-learned skills and add its to map also for use in unlearn spells/talents      uint32 dbc_count = 0; +    barGoLink bar( sSpellStore.GetNumRows() );      for(uint32 spell = 0; spell < sSpellStore.GetNumRows(); ++spell)      { +        bar.step();          SpellEntry const* entry = sSpellStore.LookupEntry(spell);          if(!entry) @@ -1797,7 +1860,8 @@ void SpellMgr::LoadSpellLearnSpells()  {      mSpellLearnSpells.clear();                              // need for reload case -    QueryResult *result = WorldDatabase.Query("SELECT entry, SpellID FROM spell_learn_spell"); +    //                                                0      1        2 +    QueryResult *result = WorldDatabase.Query("SELECT entry, SpellID, Active FROM spell_learn_spell");      if(!result)      {          barGoLink bar( 1 ); @@ -1821,6 +1885,7 @@ void SpellMgr::LoadSpellLearnSpells()          SpellLearnSpellNode node;          node.spell      = fields[1].GetUInt32(); +        node.active     = fields[2].GetBool();          node.autoLearned= false;          if(!sSpellStore.LookupEntry(spell_id)) @@ -1857,7 +1922,16 @@ void SpellMgr::LoadSpellLearnSpells()              {                  SpellLearnSpellNode dbc_node;                  dbc_node.spell       = entry->EffectTriggerSpell[i]; -                dbc_node.autoLearned = true; +                dbc_node.active      = true;                // all dbc based learned spells is active (show in spell book or hide by client itself) + +                // ignore learning not existed spells (broken/outdated/or generic learnig spell 483 +                if(!sSpellStore.LookupEntry(dbc_node.spell)) +                    continue; + +                // talent or passive spells or skill-step spells auto-casted and not need dependent learning, +                // pet teaching spells don't must be dependent learning (casted) +                // other required explicit dependent learning +                dbc_node.autoLearned = entry->EffectImplicitTargetA[i]==TARGET_PET || GetTalentSpellCost(spell) > 0 || IsPassiveSpell(spell) || IsSpellHaveEffect(entry,SPELL_EFFECT_SKILL_STEP);                  SpellLearnSpellMap::const_iterator db_node_begin = GetBeginSpellLearnSpell(spell);                  SpellLearnSpellMap::const_iterator db_node_end   = GetEndSpellLearnSpell(spell); @@ -2176,7 +2250,7 @@ void SpellMgr::LoadSpellCustomAttr()              }          } -        if(spellInfo->SpellVisual == 3879) +        if(spellInfo->SpellVisual[0] == 3879)              mSpellCustomAttr[i] |= SPELL_ATTR_CU_CONE_BACK;          switch(i) @@ -2319,6 +2393,187 @@ void SpellMgr::LoadSpellLinked()  }  /// Some checks for spells, to prevent adding depricated/broken spells for trainers, spell book, etc +void SpellMgr::LoadPetLevelupSpellMap() +{ +    CreatureFamilyEntry const *creatureFamily; +    SpellEntry const *spell; +    uint32 count = 0; + +    for (uint32 i = 0; i < sCreatureFamilyStore.GetNumRows(); ++i) +    { +        creatureFamily = sCreatureFamilyStore.LookupEntry(i); + +        if(!creatureFamily)                                 // not exist +            continue; + +        if(creatureFamily->petTalentType < 0)               // not hunter pet family +            continue; + +        for(uint32 j = 0; j < sSpellStore.GetNumRows(); ++j) +        { +            spell = sSpellStore.LookupEntry(j); + +            // not exist +            if(!spell) +                continue; + +            // not hunter spell +            if(spell->SpellFamilyName != SPELLFAMILY_HUNTER) +                continue; + +            // not pet spell +            if(!(spell->SpellFamilyFlags[1] & 0x10000000)) +                continue; + +            // not Growl or Cower (generics) +            if(spell->SpellIconID != 201 && spell->SpellIconID != 958) +            { +                switch(creatureFamily->ID) +                { +                    case CREATURE_FAMILY_BAT:               // Bite and Sonic Blast +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 1577) +                            continue; +                        break; +                    case CREATURE_FAMILY_BEAR:              // Claw and Swipe +                        if(spell->SpellIconID != 262 && spell->SpellIconID != 1562) +                            continue; +                        break; +                    case CREATURE_FAMILY_BIRD_OF_PREY:      // Claw and Snatch +                        if(spell->SpellIconID != 262 && spell->SpellIconID != 168) +                            continue; +                        break; +                    case CREATURE_FAMILY_BOAR:              // Bite and Gore +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 1578) +                            continue; +                        break; +                    case CREATURE_FAMILY_CARRION_BIRD:      // Bite and Demoralizing Screech +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 1579) +                            continue; +                        break; +                    case CREATURE_FAMILY_CAT:               // Claw and Prowl and Rake +                        if(spell->SpellIconID != 262 && spell->SpellIconID != 495 && spell->SpellIconID != 494) +                            continue; +                        break; +                    case CREATURE_FAMILY_CHIMAERA:          // Bite and Froststorm Breath +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 62) +                            continue; +                        break; +                    case CREATURE_FAMILY_CORE_HOUND:        // Bite and Lava Breath +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 1197) +                            continue; +                        break; +                    case CREATURE_FAMILY_CRAB:              // Claw and Pin +                        if(spell->SpellIconID != 262 && spell->SpellIconID != 2679) +                            continue; +                        break; +                    case CREATURE_FAMILY_CROCOLISK:         // Bite and Bad Attitude +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 1581) +                            continue; +                        break; +                    case CREATURE_FAMILY_DEVILSAUR:         // Bite and Monstrous Bite +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 599) +                            continue; +                        break; +                    case CREATURE_FAMILY_DRAGONHAWK:        // Bite and Fire Breath +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 2128) +                            continue; +                        break; +                    case CREATURE_FAMILY_GORILLA:           // Smack and Thunderstomp +                        if(spell->SpellIconID != 473 && spell->SpellIconID != 148) +                            continue; +                        break; +                    case CREATURE_FAMILY_HYENA:             // Bite and Tendon Rip +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 138) +                            continue; +                        break; +                    case CREATURE_FAMILY_MOTH:              // Serenity Dust and Smack +                        if(spell->SpellIconID != 1714 && spell->SpellIconID != 473) +                            continue; +                        break; +                    case CREATURE_FAMILY_NETHER_RAY:        // Bite and Nether Shock +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 2027) +                            continue; +                        break; +                    case CREATURE_FAMILY_RAPTOR:            // Claw and Savage Rend +                        if(spell->SpellIconID != 262 && spell->SpellIconID != 245) +                            continue; +                        break; +                    case CREATURE_FAMILY_RAVAGER:           // Bite and Ravage +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 2253) +                            continue; +                        break; +                    case CREATURE_FAMILY_RHINO:             // Smack and Stampede +                        if(spell->SpellIconID != 473 && spell->SpellIconID != 3066) +                            continue; +                        break; +                    case CREATURE_FAMILY_SCORPID:           // Claw and Scorpid Poison +                        if(spell->SpellIconID != 262 && spell->SpellIconID != 163) +                            continue; +                        break; +                    case CREATURE_FAMILY_SERPENT:           // Bite and Poison Spit +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 68) +                            continue; +                        break; +                    case CREATURE_FAMILY_SILITHID:          // Claw and Venom Web Spray +                        if(spell->SpellIconID != 262 && (spell->SpellIconID != 272 && spell->SpellVisual[0] != 12013)) +                            continue; +                        break; +                    case CREATURE_FAMILY_SPIDER:            // Bite and Web +                        if(spell->SpellIconID != 1680 && (spell->SpellIconID != 272 && spell->SpellVisual[0] != 684)) +                            continue; +                        break; +                    case CREATURE_FAMILY_SPIRIT_BEAST:      // Claw and Prowl and Spirit Strike +                        if(spell->SpellIconID != 262 && spell->SpellIconID != 495 && spell->SpellIconID != 255) +                            continue; +                        break; +                    case CREATURE_FAMILY_SPOREBAT:          // Smack and Spore Cloud +                        if(spell->SpellIconID != 473 && spell->SpellIconID != 2681) +                            continue; +                        break; +                    case CREATURE_FAMILY_TALLSTRIDER:       // Claw and Dust Cloud +                        if(spell->SpellIconID != 262 && (spell->SpellIconID != 157 && !(spell->Attributes & 0x4000000))) +                            continue; +                        break; +                    case CREATURE_FAMILY_TURTLE:            // Bite and Shell Shield +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 1588) +                            continue; +                        break; +                    case CREATURE_FAMILY_WARP_STALKER:      // Bite and Warp +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 1952) +                            continue; +                         break; +                    case CREATURE_FAMILY_WASP:              // Smack and Sting +                        if(spell->SpellIconID != 473 && spell->SpellIconID != 110) +                            continue; +                        break; +                    case CREATURE_FAMILY_WIND_SERPENT:      // Bite and Lightning Breath +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 62) +                            continue; +                        break; +                    case CREATURE_FAMILY_WOLF:              // Bite and Furious Howl +                        if(spell->SpellIconID != 1680 && spell->SpellIconID != 1573) +                            continue; +                        break; +                    case CREATURE_FAMILY_WORM:              // Acid Spit and Bite +                        if(spell->SpellIconID != 636 && spell->SpellIconID != 1680) +                            continue; +                        break; +                    default: +                        sLog.outError("LoadPetLevelupSpellMap: Unhandled creature family %u", creatureFamily->ID); +                        continue; +                    } +            } + +            mPetLevelupSpellMap[creatureFamily->ID][spell->spellLevel] = spell->Id; +            count++; +        } +    } + +    sLog.outString(); +    sLog.outString( ">> Loaded %u pet levelup spells", count ); +} + +/// Some checks for spells, to prevent adding deprecated/broken spells for trainers, spell book, etc  bool SpellMgr::IsSpellValid(SpellEntry const* spellInfo, Player* pl, bool msg)  {      // not exist @@ -2393,11 +2648,24 @@ bool SpellMgr::IsSpellValid(SpellEntry const* spellInfo, Player* pl, bool msg)      return true;  } -bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id) +uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id, uint32 bgInstanceId)  {      // normal case -    if( spellInfo->AreaId && spellInfo->AreaId != zone_id && spellInfo->AreaId != area_id ) -        return false; +    if( spellInfo->AreaGroupId > 0) +    { +        bool found = false; + +        AreaGroupEntry const* groupEntry = sAreaGroupStore.LookupEntry(spellInfo->AreaGroupId); +        if(groupEntry) +        { +            for (uint8 i=0; i<7; i++) +                if( groupEntry->AreaId[i] == zone_id || groupEntry->AreaId[i] == area_id ) +                    found = true; +        } + +        if(!found) +            return SPELL_FAILED_INCORRECT_AREA; +    }      // elixirs (all area dependent elixirs have family SPELLFAMILY_POTION, use this for speedup)      if(spellInfo->SpellFamilyName==SPELLFAMILY_POTION) @@ -2407,28 +2675,28 @@ bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 z              if(mask & ELIXIR_BATTLE_MASK)              {                  if(spellInfo->Id==45373)                    // Bloodberry Elixir -                    return zone_id==4075; +                    return zone_id==4075 ? 0 : SPELL_FAILED_REQUIRES_AREA;              }              if(mask & ELIXIR_UNSTABLE_MASK)              {                  // in the Blade's Edge Mountains Plateaus and Gruul's Lair. -                return zone_id ==3522 || map_id==565; +                return zone_id ==3522 || map_id==565 ? 0 : SPELL_FAILED_INCORRECT_AREA;              }              if(mask & ELIXIR_SHATTRATH_MASK)              {                  // in Tempest Keep, Serpentshrine Cavern, Caverns of Time: Mount Hyjal, Black Temple, Sunwell Plateau                  if(zone_id ==3607 || map_id==534 || map_id==564 || zone_id==4075) -                    return true; +                    return 0;                  MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);                  if(!mapEntry) -                    return false; +                    return SPELL_FAILED_INCORRECT_AREA; -                return mapEntry->multimap_id==206; +                return mapEntry->multimap_id==206 ? 0 : SPELL_FAILED_INCORRECT_AREA;              }              // elixirs not have another limitations -            return true; +            return 0;          }      } @@ -2440,35 +2708,104 @@ bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 z          {              MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);              if(!mapEntry) -                return false; +                return SPELL_FAILED_INCORRECT_AREA; -            return mapEntry->multimap_id==206; +            return mapEntry->multimap_id==206 ? 0 : SPELL_FAILED_REQUIRES_AREA;          }          case 41617:                                         // Cenarion Mana Salve          case 41619:                                         // Cenarion Healing Salve          {              MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);              if(!mapEntry) -                return false; +                return SPELL_FAILED_INCORRECT_AREA; -            return mapEntry->multimap_id==207; +            return mapEntry->multimap_id==207 ? 0 : SPELL_FAILED_REQUIRES_AREA;          }          case 40216:                                         // Dragonmaw Illusion          case 42016:                                         // Dragonmaw Illusion -            return area_id == 3759 || area_id == 3966 || area_id == 3939; +            return area_id == 3759 || area_id == 3966 || area_id == 3939 ? 0 : SPELL_FAILED_INCORRECT_AREA; +        case 51721:                                         // Dominion Over Acherus +        case 54055:                                         // Dominion Over Acherus +            return area_id == 4281 || area_id == 4342 ? 0 : SPELL_FAILED_INCORRECT_AREA; +        case 51852:                                         // The Eye of Acherus +            return map_id == 609 ? 0 : SPELL_FAILED_REQUIRES_AREA; +        case 54119:                                         // Mist of the Kvaldir +            return area_id == 4028 || area_id == 4029 || area_id == 4106 || area_id == 4031 ? 0 : SPELL_FAILED_INCORRECT_AREA; +        case 23333:                                         // Warsong Flag +        case 23335:                                         // Silverwing Flag +            return map_id == 489 && bgInstanceId ? 0 : SPELL_FAILED_REQUIRES_AREA; +        case 34976:                                         // Netherstorm Flag +            return map_id == 566 && bgInstanceId ? 0 : SPELL_FAILED_REQUIRES_AREA; +        case 2584:                                          // Waiting to Resurrect +        case 22011:                                         // Spirit Heal Channel +        case 22012:                                         // Spirit Heal +        case 24171:                                         // Resurrection Impact Visual +        case 42792:                                         // Recently Dropped Flag +        case 43681:                                         // Inactive +        case 44535:                                         // Spirit Heal (mana) +        { +            MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); +            if(!mapEntry) +                return SPELL_FAILED_INCORRECT_AREA; + +            return mapEntry->IsBattleGround() && bgInstanceId ? 0 : SPELL_FAILED_REQUIRES_AREA; +        } +        case 44521:                                         // Preparation +        { +            if(!bgInstanceId) +                return SPELL_FAILED_REQUIRES_AREA; + +            MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); +            if(!mapEntry) +                return SPELL_FAILED_INCORRECT_AREA; + +            if(!mapEntry->IsBattleGround()) +                return SPELL_FAILED_REQUIRES_AREA; + +            BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgInstanceId); +            return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA; +        } +        case 32724:                                         // Gold Team (Alliance) +        case 32725:                                         // Green Team (Alliance) +        case 35774:                                         // Gold Team (Horde) +        case 35775:                                         // Green Team (Horde) +        { +            MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); +            if(!mapEntry) +                return SPELL_FAILED_INCORRECT_AREA; + +            return mapEntry->IsBattleArena() && bgInstanceId ? 0 : SPELL_FAILED_REQUIRES_AREA; +        } +        case 32727:                                         // Arena Preparation +        { +            if(!bgInstanceId) +                return SPELL_FAILED_REQUIRES_AREA; + +            MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); +            if(!mapEntry) +                return SPELL_FAILED_INCORRECT_AREA; + +            if(!mapEntry->IsBattleArena()) +                return SPELL_FAILED_REQUIRES_AREA; + +            BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgInstanceId); +            return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA; +        }      } -    return true; +    return 0;  }  void SpellMgr::LoadSkillLineAbilityMap()  {      mSkillLineAbilityMap.clear(); +    barGoLink bar( sSkillLineAbilityStore.GetNumRows() );      uint32 count = 0;      for (uint32 i = 0; i < sSkillLineAbilityStore.GetNumRows(); i++)      { +        bar.step();          SkillLineAbilityEntry const *SkillInfo = sSkillLineAbilityStore.LookupEntry(i);          if(!SkillInfo)              continue; @@ -2478,7 +2815,7 @@ void SpellMgr::LoadSkillLineAbilityMap()      }      sLog.outString(); -    sLog.outString(">> Loaded %u SkillLineAbility MultiMap", count); +    sLog.outString(">> Loaded %u SkillLineAbility MultiMap Data", count);  }  DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto, bool triggered) @@ -2486,56 +2823,49 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto      // Explicit Diminishing Groups      switch(spellproto->SpellFamilyName)      { -        case SPELLFAMILY_MAGE: -        { -            // Polymorph -            if ((spellproto->SpellFamilyFlags & 0x00001000000LL) && spellproto->EffectApplyAuraName[0]==SPELL_AURA_MOD_CONFUSE) -                return DIMINISHING_POLYMORPH; -            break; -        }          case SPELLFAMILY_ROGUE:          {              // Kidney Shot -            if (spellproto->SpellFamilyFlags & 0x00000200000LL) +            if (spellproto->SpellFamilyFlags[0] & 0x200000)                  return DIMINISHING_KIDNEYSHOT;              // Sap -            else if (spellproto->SpellFamilyFlags & 0x00000000080LL) +            else if (spellproto->SpellFamilyFlags[0] & 0x80)                  return DIMINISHING_POLYMORPH;              // Gouge -            else if (spellproto->SpellFamilyFlags & 0x00000000008LL) +            else if (spellproto->SpellFamilyFlags[0] & 0x8)                  return DIMINISHING_POLYMORPH;              // Blind -            else if (spellproto->SpellFamilyFlags & 0x00001000000LL) +            else if (spellproto->SpellFamilyFlags[0] & 0x00001000000)                  return DIMINISHING_BLIND_CYCLONE;              break;          }          case SPELLFAMILY_WARLOCK:          {              // Death Coil -            if (spellproto->SpellFamilyFlags & 0x00000080000LL) +            if (spellproto->SpellFamilyFlags[0] & 0x00000080000)                  return DIMINISHING_DEATHCOIL;              // Seduction -            if (spellproto->SpellFamilyFlags & 0x00040000000LL) +            if (spellproto->SpellFamilyFlags[0] & 0x00040000000)                  return DIMINISHING_FEAR;              // Fear              //else if (spellproto->SpellFamilyFlags & 0x40840000000LL)              //    return DIMINISHING_WARLOCK_FEAR;              // Curses/etc -            else if (spellproto->SpellFamilyFlags & 0x00080000000LL) +            else if (spellproto->SpellFamilyFlags[0] & 0x80000000)                  return DIMINISHING_LIMITONLY;              break;          }          case SPELLFAMILY_DRUID:          {              // Cyclone -            if (spellproto->SpellFamilyFlags & 0x02000000000LL) +            if (spellproto->SpellFamilyFlags[1] & 0x020)                  return DIMINISHING_BLIND_CYCLONE;              break;          }          case SPELLFAMILY_WARRIOR:          {              // Hamstring - limit duration to 10s in PvP -            if (spellproto->SpellFamilyFlags & 0x00000000002LL) +            if (spellproto->SpellFamilyFlags[0] & 0x00000000002)                  return DIMINISHING_LIMITONLY;              break;          } @@ -2544,30 +2874,21 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto      }      // Get by mechanic -    for (uint8 i=0;i<3;++i) -    { -        if (spellproto->Mechanic      == MECHANIC_STUN    || spellproto->EffectMechanic[i] == MECHANIC_STUN) -            return triggered ? DIMINISHING_TRIGGER_STUN : DIMINISHING_CONTROL_STUN; -        else if (spellproto->Mechanic == MECHANIC_SLEEP   || spellproto->EffectMechanic[i] == MECHANIC_SLEEP) -            return DIMINISHING_SLEEP; -        else if (spellproto->Mechanic == MECHANIC_ROOT    || spellproto->EffectMechanic[i] == MECHANIC_ROOT) -            return triggered ? DIMINISHING_TRIGGER_ROOT : DIMINISHING_CONTROL_ROOT; -        else if (spellproto->Mechanic == MECHANIC_FEAR    || spellproto->EffectMechanic[i] == MECHANIC_FEAR) -            return DIMINISHING_FEAR; -        else if (spellproto->Mechanic == MECHANIC_CHARM   || spellproto->EffectMechanic[i] == MECHANIC_CHARM) -            return DIMINISHING_CHARM; -        else if (spellproto->Mechanic == MECHANIC_SILENCE || spellproto->EffectMechanic[i] == MECHANIC_SILENCE) -            return DIMINISHING_SILENCE; -        else if (spellproto->Mechanic == MECHANIC_DISARM  || spellproto->EffectMechanic[i] == MECHANIC_DISARM) -            return DIMINISHING_DISARM; -        else if (spellproto->Mechanic == MECHANIC_FREEZE  || spellproto->EffectMechanic[i] == MECHANIC_FREEZE) -            return DIMINISHING_FREEZE; -        else if (spellproto->Mechanic == MECHANIC_KNOCKOUT|| spellproto->EffectMechanic[i] == MECHANIC_KNOCKOUT || -                 spellproto->Mechanic == MECHANIC_SAPPED  || spellproto->EffectMechanic[i] == MECHANIC_SAPPED) -            return DIMINISHING_KNOCKOUT; -        else if (spellproto->Mechanic == MECHANIC_BANISH  || spellproto->EffectMechanic[i] == MECHANIC_BANISH) -            return DIMINISHING_BANISH; -    } +    uint32 mechanic = GetAllSpellMechanicMask(spellproto); +    if (mechanic == MECHANIC_NONE)          return DIMINISHING_NONE; +    if (mechanic & (1<<MECHANIC_STUN))      return triggered ? DIMINISHING_TRIGGER_STUN : DIMINISHING_CONTROL_STUN; +    if (mechanic & (1<<MECHANIC_SLEEP))     return DIMINISHING_SLEEP; +    if (mechanic & (1<<MECHANIC_POLYMORPH)) return DIMINISHING_POLYMORPH; +    if (mechanic & (1<<MECHANIC_ROOT))      return triggered ? DIMINISHING_TRIGGER_ROOT : DIMINISHING_CONTROL_ROOT; +    if (mechanic & (1<<MECHANIC_FEAR))      return DIMINISHING_FEAR; +    if (mechanic & (1<<MECHANIC_CHARM))     return DIMINISHING_CHARM; +    if (mechanic & (1<<MECHANIC_SILENCE))   return DIMINISHING_SILENCE; +    if (mechanic & (1<<DIMINISHING_DISARM)) return DIMINISHING_DISARM; +    if (mechanic & (1<<MECHANIC_FREEZE))    return DIMINISHING_FREEZE; +    if (mechanic & ((1<<MECHANIC_KNOCKOUT) | (1<<MECHANIC_SAPPED)))    return DIMINISHING_KNOCKOUT; +    if (mechanic & (1<<MECHANIC_BANISH))    return DIMINISHING_BANISH; +    if (mechanic & (1<<MECHANIC_HORROR))    return DIMINISHING_DEATHCOIL; +      return DIMINISHING_NONE;  }  | 
