2010-10-07 15:35:36 +02:00
/*
2012-01-01 00:32:13 +01:00
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* 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 the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
2008-11-17 22:07:21 -06:00
*/
2009-10-17 15:51:44 -07:00
2008-11-17 22:07:21 -06:00
#include "SpellMgr.h"
2011-07-26 23:09:28 +02:00
#include "SpellInfo.h"
2008-11-17 22:07:21 -06:00
#include "ObjectMgr.h"
2010-12-21 11:40:20 +01:00
#include "SpellAuras.h"
2008-11-17 22:07:21 -06:00
#include "SpellAuraDefines.h"
2011-07-26 23:09:28 +02:00
#include "SharedDefines.h"
2009-03-27 09:58:20 -06:00
#include "DBCStores.h"
2008-11-17 22:07:21 -06:00
#include "World.h"
#include "Chat.h"
#include "Spell.h"
2010-08-08 04:37:24 +02:00
#include "BattlegroundMgr.h"
2009-05-10 22:48:22 -05:00
#include "CreatureAI.h"
2010-04-18 23:20:07 +02:00
#include "MapManager.h"
2011-01-09 00:00:08 -03:00
#include "BattlegroundIC.h"
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
bool IsPrimaryProfessionSkill ( uint32 skill )
2008-11-17 22:07:21 -06:00
{
2011-09-15 14:08:17 +02:00
SkillLineEntry const * pSkill = sSkillLineStore . LookupEntry ( skill );
2011-07-26 23:09:28 +02:00
if ( ! pSkill )
2008-11-17 22:07:21 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( pSkill -> categoryId != SKILL_CATEGORY_PROFESSION )
2009-03-21 18:05:43 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
return true ;
2009-07-23 18:32:32 +02:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
bool IsPartOfSkillLine ( uint32 skillId , uint32 spellId )
2010-02-20 23:57:54 +01:00
{
2011-07-26 23:09:28 +02:00
SkillLineAbilityMapBounds skillBounds = sSpellMgr -> GetSkillLineAbilityMapBounds ( spellId );
for ( SkillLineAbilityMap :: const_iterator itr = skillBounds . first ; itr != skillBounds . second ; ++ itr )
if ( itr -> second -> skillId == skillId )
2011-05-29 15:46:14 +02:00
return true ;
2011-07-26 23:09:28 +02:00
return false ;
2010-02-20 23:57:54 +01:00
}
2011-07-26 23:09:28 +02:00
DiminishingGroup GetDiminishingReturnsGroupForSpell ( SpellInfo const * spellproto , bool triggered )
2009-07-30 17:16:56 +02:00
{
2011-07-26 23:09:28 +02:00
if ( spellproto -> IsPositive ())
return DIMINISHING_NONE ;
2011-05-05 12:52:40 +02:00
2011-07-26 23:09:28 +02:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2011-05-05 12:52:40 +02:00
{
2011-07-26 23:09:28 +02:00
if ( spellproto -> Effects [ i ]. ApplyAuraName == SPELL_AURA_MOD_TAUNT )
return DIMINISHING_TAUNT ;
2009-07-30 17:16:56 +02:00
}
2011-05-05 12:52:40 +02:00
2011-07-26 23:09:28 +02:00
// Explicit Diminishing Groups
switch ( spellproto -> SpellFamilyName )
2008-11-17 22:07:21 -06:00
{
2008-11-28 20:19:37 +01:00
case SPELLFAMILY_GENERIC :
{
2011-07-26 23:09:28 +02:00
// Pet charge effects (Infernal Awakening, Demon Charge)
if ( spellproto -> SpellVisual [ 0 ] == 2816 && spellproto -> SpellIconID == 15 )
return DIMINISHING_CONTROLLED_STUN ;
// Gnaw
else if ( spellproto -> Id == 47481 )
return DIMINISHING_CONTROLLED_STUN ;
2008-11-28 20:19:37 +01:00
break ;
}
2011-07-26 23:09:28 +02:00
// Event spells
case SPELLFAMILY_UNK1 :
return DIMINISHING_NONE ;
2008-11-17 22:07:21 -06:00
case SPELLFAMILY_MAGE :
{
2011-07-26 23:09:28 +02:00
// Frostbite
if ( spellproto -> SpellFamilyFlags [ 1 ] & 0x80000000 )
return DIMINISHING_ROOT ;
// Shattered Barrier
else if ( spellproto -> SpellVisual [ 0 ] == 12297 )
return DIMINISHING_ROOT ;
// Deep Freeze
else if ( spellproto -> SpellIconID == 2939 && spellproto -> SpellVisual [ 0 ] == 9963 )
return DIMINISHING_CONTROLLED_STUN ;
// Frost Nova / Freeze (Water Elemental)
else if ( spellproto -> SpellIconID == 193 )
return DIMINISHING_CONTROLLED_ROOT ;
// Dragon's Breath
else if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x800000 )
2011-11-13 00:51:33 +01:00
return DIMINISHING_DRAGONS_BREATH ;
2008-11-17 22:07:21 -06:00
break ;
}
case SPELLFAMILY_WARRIOR :
{
2011-08-19 13:33:53 -03:00
// Hamstring - limit duration to 10s in PvP
if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x2 )
return DIMINISHING_LIMITONLY ;
2011-07-26 23:09:28 +02:00
// Charge Stun (own diminishing)
else if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x01000000 )
return DIMINISHING_CHARGE ;
2008-11-17 22:07:21 -06:00
break ;
}
case SPELLFAMILY_WARLOCK :
{
2011-07-26 23:09:28 +02:00
// Death Coil
if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x80000 )
return DIMINISHING_HORROR ;
2011-08-19 13:33:53 -03:00
// Curses/etc
else if (( spellproto -> SpellFamilyFlags [ 0 ] & 0x80000000 ) || ( spellproto -> SpellFamilyFlags [ 1 ] & 0x200 ))
return DIMINISHING_LIMITONLY ;
2011-07-26 23:09:28 +02:00
// Seduction
else if ( spellproto -> SpellFamilyFlags [ 1 ] & 0x10000000 )
return DIMINISHING_FEAR ;
2008-11-17 22:07:21 -06:00
break ;
}
2009-08-24 19:12:22 -05:00
case SPELLFAMILY_PRIEST :
{
2011-07-26 23:09:28 +02:00
// Psychic Horror
if ( spellproto -> SpellFamilyFlags [ 2 ] & 0x2000 )
return DIMINISHING_HORROR ;
2009-08-24 19:12:22 -05:00
break ;
}
2011-07-26 23:09:28 +02:00
case SPELLFAMILY_DRUID :
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
// Pounce
if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x20000 )
return DIMINISHING_OPENING_STUN ;
// Cyclone
else if ( spellproto -> SpellFamilyFlags [ 1 ] & 0x20 )
return DIMINISHING_CYCLONE ;
// Entangling Roots
// Nature's Grasp
else if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x00000200 )
return DIMINISHING_CONTROLLED_ROOT ;
2011-08-19 13:33:53 -03:00
// Faerie Fire
else if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x400 )
return DIMINISHING_LIMITONLY ;
2008-11-17 22:07:21 -06:00
break ;
}
2011-07-26 23:09:28 +02:00
case SPELLFAMILY_ROGUE :
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
// Gouge
if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x8 )
return DIMINISHING_DISORIENT ;
// Blind
else if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x1000000 )
return DIMINISHING_FEAR ;
// Cheap Shot
else if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x400 )
return DIMINISHING_OPENING_STUN ;
2011-08-19 13:33:53 -03:00
// Crippling poison - Limit to 10 seconds in PvP (No SpellFamilyFlags)
else if ( spellproto -> SpellIconID == 163 )
return DIMINISHING_LIMITONLY ;
2008-11-17 22:07:21 -06:00
break ;
}
2011-07-26 23:09:28 +02:00
case SPELLFAMILY_HUNTER :
2008-11-17 22:07:21 -06:00
{
2011-11-13 00:51:33 +01:00
// Hunter's Mark
2011-08-19 13:33:53 -03:00
if (( spellproto -> SpellFamilyFlags [ 0 ] & 0x400 ) && spellproto -> SpellIconID == 538 )
return DIMINISHING_LIMITONLY ;
2011-07-26 23:09:28 +02:00
// Scatter Shot (own diminishing)
2011-08-19 13:33:53 -03:00
else if (( spellproto -> SpellFamilyFlags [ 0 ] & 0x40000 ) && spellproto -> SpellIconID == 132 )
2011-07-26 23:09:28 +02:00
return DIMINISHING_SCATTER_SHOT ;
// Entrapment (own diminishing)
else if ( spellproto -> SpellVisual [ 0 ] == 7484 && spellproto -> SpellIconID == 20 )
return DIMINISHING_ENTRAPMENT ;
// Wyvern Sting mechanic is MECHANIC_SLEEP but the diminishing is DIMINISHING_DISORIENT
else if (( spellproto -> SpellFamilyFlags [ 1 ] & 0x1000 ) && spellproto -> SpellIconID == 1721 )
return DIMINISHING_DISORIENT ;
// Freezing Arrow
else if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x8 )
return DIMINISHING_DISORIENT ;
2008-11-17 22:07:21 -06:00
break ;
}
2011-07-26 23:09:28 +02:00
case SPELLFAMILY_PALADIN :
{
2011-08-19 13:33:53 -03:00
// Judgement of Justice - limit duration to 10s in PvP
if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x100000 )
return DIMINISHING_LIMITONLY ;
2011-07-26 23:09:28 +02:00
// Turn Evil
2011-08-19 13:33:53 -03:00
else if (( spellproto -> SpellFamilyFlags [ 1 ] & 0x804000 ) && spellproto -> SpellIconID == 309 )
2011-07-26 23:09:28 +02:00
return DIMINISHING_FEAR ;
2008-12-29 12:22:49 -06:00
break ;
2011-07-26 23:09:28 +02:00
}
case SPELLFAMILY_DEATHKNIGHT :
2009-02-18 16:26:02 -06:00
{
2011-07-26 23:09:28 +02:00
// Hungering Cold (no flags)
if ( spellproto -> SpellIconID == 2797 )
return DIMINISHING_DISORIENT ;
2011-08-19 13:33:53 -03:00
// Mark of Blood
else if (( spellproto -> SpellFamilyFlags [ 0 ] & 0x10000000 ) && spellproto -> SpellIconID == 2285 )
return DIMINISHING_LIMITONLY ;
2011-07-26 23:09:28 +02:00
break ;
2009-02-18 16:26:02 -06:00
}
2008-11-20 18:13:10 -06:00
default :
2011-07-26 23:09:28 +02:00
break ;
2008-11-20 18:13:10 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// Lastly - Set diminishing depending on mechanic
uint32 mechanic = spellproto -> GetAllEffectsMechanicMask ();
if ( mechanic & ( 1 << MECHANIC_CHARM ))
return DIMINISHING_MIND_CONTROL ;
if ( mechanic & ( 1 << MECHANIC_SILENCE ))
return DIMINISHING_SILENCE ;
if ( mechanic & ( 1 << MECHANIC_SLEEP ))
return DIMINISHING_SLEEP ;
if ( mechanic & (( 1 << MECHANIC_SAPPED ) | ( 1 << MECHANIC_POLYMORPH ) | ( 1 << MECHANIC_SHACKLE )))
return DIMINISHING_DISORIENT ;
// Mechanic Knockout, except Blast Wave
if ( mechanic & ( 1 << MECHANIC_KNOCKOUT ) && spellproto -> SpellIconID != 292 )
return DIMINISHING_DISORIENT ;
if ( mechanic & ( 1 << MECHANIC_DISARM ))
return DIMINISHING_DISARM ;
if ( mechanic & ( 1 << MECHANIC_FEAR ))
return DIMINISHING_FEAR ;
if ( mechanic & ( 1 << MECHANIC_STUN ))
return triggered ? DIMINISHING_STUN : DIMINISHING_CONTROLLED_STUN ;
if ( mechanic & ( 1 << MECHANIC_BANISH ))
return DIMINISHING_BANISH ;
if ( mechanic & ( 1 << MECHANIC_ROOT ))
return triggered ? DIMINISHING_ROOT : DIMINISHING_CONTROLLED_ROOT ;
return DIMINISHING_NONE ;
}
DiminishingReturnsType GetDiminishingReturnsGroupType ( DiminishingGroup group )
2008-11-20 18:13:10 -06:00
{
2011-07-26 23:09:28 +02:00
switch ( group )
2008-11-20 18:13:10 -06:00
{
2011-07-26 23:09:28 +02:00
case DIMINISHING_TAUNT :
case DIMINISHING_CONTROLLED_STUN :
case DIMINISHING_STUN :
case DIMINISHING_OPENING_STUN :
case DIMINISHING_CYCLONE :
case DIMINISHING_CHARGE :
return DRTYPE_ALL ;
2011-08-19 13:33:53 -03:00
case DIMINISHING_LIMITONLY :
case DIMINISHING_NONE :
return DRTYPE_NONE ;
2008-11-17 22:07:21 -06:00
default :
2011-07-26 23:09:28 +02:00
return DRTYPE_PLAYER ;
2008-11-17 22:07:21 -06:00
}
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
DiminishingLevels GetDiminishingReturnsMaxLevel ( DiminishingGroup group )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
switch ( group )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
case DIMINISHING_TAUNT :
return DIMINISHING_LEVEL_TAUNT_IMMUNE ;
2008-11-17 22:07:21 -06:00
default :
2011-07-26 23:09:28 +02:00
return DIMINISHING_LEVEL_IMMUNE ;
2008-11-17 22:07:21 -06:00
}
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
int32 GetDiminishingReturnsLimitDuration ( DiminishingGroup group , SpellInfo const * spellproto )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
if ( ! IsDiminishingReturnsGroupDurationLimited ( group ))
return 0 ;
2010-01-10 13:48:57 +01:00
2011-07-26 23:09:28 +02:00
// Explicit diminishing duration
2010-06-23 03:45:44 +02:00
switch ( spellproto -> SpellFamilyName )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
case SPELLFAMILY_DRUID :
{
// Faerie Fire - limit to 40 seconds in PvP (3.1)
if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x400 )
return 40 * IN_MILLISECONDS ;
2010-06-23 03:45:44 +02:00
break ;
2011-07-26 23:09:28 +02:00
}
2010-06-28 20:34:11 +02:00
case SPELLFAMILY_HUNTER :
2011-07-26 23:09:28 +02:00
{
// Wyvern Sting
if ( spellproto -> SpellFamilyFlags [ 1 ] & 0x1000 )
return 6 * IN_MILLISECONDS ;
// Hunter's Mark
if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x400 )
return 120 * IN_MILLISECONDS ;
2010-06-28 20:34:11 +02:00
break ;
2011-07-26 23:09:28 +02:00
}
case SPELLFAMILY_PALADIN :
{
// Repentance - limit to 6 seconds in PvP
if ( spellproto -> SpellFamilyFlags [ 0 ] & 0x4 )
return 6 * IN_MILLISECONDS ;
break ;
}
case SPELLFAMILY_WARLOCK :
{
// Banish - limit to 6 seconds in PvP
if ( spellproto -> SpellFamilyFlags [ 1 ] & 0x8000000 )
return 6 * IN_MILLISECONDS ;
// Curse of Tongues - limit to 12 seconds in PvP
else if ( spellproto -> SpellFamilyFlags [ 2 ] & 0x800 )
return 12 * IN_MILLISECONDS ;
// Curse of Elements - limit to 120 seconds in PvP
else if ( spellproto -> SpellFamilyFlags [ 1 ] & 0x200 )
return 120 * IN_MILLISECONDS ;
2010-09-05 14:34:48 -07:00
break ;
2011-07-26 23:09:28 +02:00
}
2010-06-23 03:45:44 +02:00
default :
break ;
2009-03-18 21:04:46 +01:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
return 10 * IN_MILLISECONDS ;
}
bool IsDiminishingReturnsGroupDurationLimited ( DiminishingGroup group )
{
switch ( group )
2009-03-18 21:04:46 +01:00
{
2011-11-13 00:51:33 +01:00
case DIMINISHING_BANISH :
2011-07-26 23:09:28 +02:00
case DIMINISHING_CONTROLLED_STUN :
case DIMINISHING_CONTROLLED_ROOT :
2011-11-13 00:51:33 +01:00
case DIMINISHING_CYCLONE :
case DIMINISHING_DISORIENT :
case DIMINISHING_ENTRAPMENT :
2011-07-26 23:09:28 +02:00
case DIMINISHING_FEAR :
2011-11-13 00:51:33 +01:00
case DIMINISHING_HORROR :
2011-07-26 23:09:28 +02:00
case DIMINISHING_MIND_CONTROL :
case DIMINISHING_OPENING_STUN :
2011-11-13 00:51:33 +01:00
case DIMINISHING_ROOT :
case DIMINISHING_STUN :
2011-07-26 23:09:28 +02:00
case DIMINISHING_SLEEP :
2011-11-13 00:51:33 +01:00
case DIMINISHING_LIMITONLY :
2009-03-18 21:04:46 +01:00
return true ;
default :
2011-07-26 23:09:28 +02:00
return false ;
2009-03-18 21:04:46 +01:00
}
2011-07-26 23:09:28 +02:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellMgr :: SpellMgr ()
{
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellMgr ::~ SpellMgr ()
{
UnloadSpellInfoStore ();
}
/// Some checks for spells, to prevent adding deprecated/broken spells for trainers, spell book, etc
2011-11-07 11:18:00 -06:00
bool SpellMgr :: IsSpellValid ( SpellInfo const * spellInfo , Player * player , bool msg )
2011-07-26 23:09:28 +02:00
{
// not exist
if ( ! spellInfo )
return false ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
bool need_check_reagents = false ;
// check effects
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
{
switch ( spellInfo -> Effects [ i ]. Effect )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
case 0 :
continue ;
// craft spell for crafting non-existed item (break client recipes list show)
case SPELL_EFFECT_CREATE_ITEM :
case SPELL_EFFECT_CREATE_ITEM_2 :
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
if ( spellInfo -> Effects [ i ]. ItemType == 0 )
{
// skip auto-loot crafting spells, its not need explicit item info (but have special fake items sometime)
if ( ! spellInfo -> IsLootCrafting ())
2009-04-09 17:32:22 +02:00
{
2011-07-26 23:09:28 +02:00
if ( msg )
2009-04-09 17:32:22 +02:00
{
2011-11-07 11:18:00 -06:00
if ( player )
ChatHandler ( player ). PSendSysMessage ( "Craft spell %u not have create item entry." , spellInfo -> Id );
2011-07-26 23:09:28 +02:00
else
sLog -> outErrorDb ( "Craft spell %u not have create item entry." , spellInfo -> Id );
2009-04-09 17:32:22 +02:00
}
2008-11-17 22:07:21 -06:00
return false ;
2011-07-26 23:09:28 +02:00
}
}
// also possible IsLootCrafting case but fake item must exist anyway
else if ( ! sObjectMgr -> GetItemTemplate ( spellInfo -> Effects [ i ]. ItemType ))
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
if ( msg )
2008-11-17 22:07:21 -06:00
{
2011-11-07 11:18:00 -06:00
if ( player )
ChatHandler ( player ). PSendSysMessage ( "Craft spell %u create not-exist in DB item (Entry: %u) and then..." , spellInfo -> Id , spellInfo -> Effects [ i ]. ItemType );
2011-07-26 23:09:28 +02:00
else
sLog -> outErrorDb ( "Craft spell %u create not-exist in DB item (Entry: %u) and then..." , spellInfo -> Id , spellInfo -> Effects [ i ]. ItemType );
2008-11-17 22:07:21 -06:00
}
2011-07-26 23:09:28 +02:00
return false ;
2011-06-17 12:00:11 +02:00
}
2011-07-26 23:09:28 +02:00
need_check_reagents = true ;
break ;
}
case SPELL_EFFECT_LEARN_SPELL :
{
SpellInfo const * spellInfo2 = sSpellMgr -> GetSpellInfo ( spellInfo -> Effects [ i ]. TriggerSpell );
2011-11-07 11:18:00 -06:00
if ( ! IsSpellValid ( spellInfo2 , player , msg ))
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
if ( msg )
2008-11-17 22:07:21 -06:00
{
2011-11-07 11:18:00 -06:00
if ( player )
ChatHandler ( player ). PSendSysMessage ( "Spell %u learn to broken spell %u, and then..." , spellInfo -> Id , spellInfo -> Effects [ i ]. TriggerSpell );
2011-07-26 23:09:28 +02:00
else
sLog -> outErrorDb ( "Spell %u learn to invalid spell %u, and then..." , spellInfo -> Id , spellInfo -> Effects [ i ]. TriggerSpell );
2008-11-17 22:07:21 -06:00
}
2011-07-26 23:09:28 +02:00
return false ;
2011-06-17 12:00:11 +02:00
}
2011-07-26 23:09:28 +02:00
break ;
2008-11-17 22:07:21 -06:00
}
}
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( need_check_reagents )
{
for ( uint8 j = 0 ; j < MAX_SPELL_REAGENTS ; ++ j )
{
if ( spellInfo -> Reagent [ j ] > 0 && ! sObjectMgr -> GetItemTemplate ( spellInfo -> Reagent [ j ]))
{
if ( msg )
{
2011-11-07 11:18:00 -06:00
if ( player )
ChatHandler ( player ). PSendSysMessage ( "Craft spell %u have not-exist reagent in DB item (Entry: %u) and then..." , spellInfo -> Id , spellInfo -> Reagent [ j ]);
2011-07-26 23:09:28 +02:00
else
sLog -> outErrorDb ( "Craft spell %u have not-exist reagent in DB item (Entry: %u) and then..." , spellInfo -> Id , spellInfo -> Reagent [ j ]);
}
return false ;
}
}
}
2009-10-17 15:51:44 -07:00
2008-11-17 22:07:21 -06:00
return true ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 SpellMgr :: GetSpellDifficultyId ( uint32 spellId ) const
2009-08-06 11:24:14 -05:00
{
2011-07-26 23:09:28 +02:00
SpellDifficultySearcherMap :: const_iterator i = mSpellDifficultySearcherMap . find ( spellId );
return i == mSpellDifficultySearcherMap . end () ? 0 : ( * i ). second ;
2009-08-06 11:24:14 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: SetSpellDifficultyId ( uint32 spellId , uint32 id )
2009-08-06 11:24:14 -05:00
{
2011-07-26 23:09:28 +02:00
mSpellDifficultySearcherMap [ spellId ] = id ;
2009-08-06 11:24:14 -05:00
}
2009-10-17 15:51:44 -07:00
2011-08-19 14:53:40 +02:00
uint32 SpellMgr :: GetSpellIdForDifficulty ( uint32 spellId , Unit const * caster ) const
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
if ( ! GetSpellInfo ( spellId ))
return spellId ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( ! caster || ! caster -> GetMap () || ! caster -> GetMap () -> IsDungeon ())
return spellId ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 mode = uint32 ( caster -> GetMap () -> GetSpawnMode ());
if ( mode >= MAX_DIFFICULTY )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
sLog -> outError ( "SpellMgr::GetSpellIdForDifficulty: Incorrect Difficulty for spell %u." , spellId );
return spellId ; //return source spell
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 difficultyId = GetSpellDifficultyId ( spellId );
if ( ! difficultyId )
return spellId ; //return source spell, it has only REGULAR_DIFFICULTY
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
SpellDifficultyEntry const * difficultyEntry = sSpellDifficultyStore . LookupEntry ( difficultyId );
2011-07-26 23:09:28 +02:00
if ( ! difficultyEntry )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "SpellMgr::GetSpellIdForDifficulty: SpellDifficultyEntry not found for spell %u. This should never happen." , spellId );
return spellId ; //return source spell
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( difficultyEntry -> SpellID [ mode ] <= 0 && mode > DUNGEON_DIFFICULTY_HEROIC )
{
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "SpellMgr::GetSpellIdForDifficulty: spell %u mode %u spell is NULL, using mode %u" , spellId , mode , mode - 2 );
mode -= 2 ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( difficultyEntry -> SpellID [ mode ] <= 0 )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "SpellMgr::GetSpellIdForDifficulty: spell %u mode %u spell is 0. Check spelldifficulty_dbc!" , spellId , mode );
return spellId ;
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "SpellMgr::GetSpellIdForDifficulty: spellid for spell %u in mode %u is %d" , spellId , mode , difficultyEntry -> SpellID [ mode ]);
return uint32 ( difficultyEntry -> SpellID [ mode ]);
}
2009-10-17 15:51:44 -07:00
2011-08-19 14:53:40 +02:00
SpellInfo const * SpellMgr :: GetSpellForDifficultyFromSpell ( SpellInfo const * spell , Unit const * caster ) const
2011-07-26 23:09:28 +02:00
{
uint32 newSpellId = GetSpellIdForDifficulty ( spell -> Id , caster );
SpellInfo const * newSpell = GetSpellInfo ( newSpellId );
if ( ! newSpell )
2009-06-07 22:13:17 +02:00
{
2011-07-26 23:09:28 +02:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "SpellMgr::GetSpellForDifficultyFromSpell: spell %u not found. Check spelldifficulty_dbc!" , newSpellId );
return spell ;
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "SpellMgr::GetSpellForDifficultyFromSpell: Spell id for instance mode is %u (original %u)" , newSpell -> Id , spell -> Id );
return newSpell ;
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellChainNode const * SpellMgr :: GetSpellChainNode ( uint32 spell_id ) const
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
SpellChainMap :: const_iterator itr = mSpellChains . find ( spell_id );
if ( itr == mSpellChains . end ())
return NULL ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
return & itr -> second ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 SpellMgr :: GetFirstSpellInChain ( uint32 spell_id ) const
{
if ( SpellChainNode const * node = GetSpellChainNode ( spell_id ))
return node -> first -> Id ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
return spell_id ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 SpellMgr :: GetLastSpellInChain ( uint32 spell_id ) const
{
if ( SpellChainNode const * node = GetSpellChainNode ( spell_id ))
return node -> last -> Id ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
return spell_id ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 SpellMgr :: GetNextSpellInChain ( uint32 spell_id ) const
{
if ( SpellChainNode const * node = GetSpellChainNode ( spell_id ))
2011-08-03 11:23:08 +02:00
if ( node -> next )
return node -> next -> Id ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
return 0 ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 SpellMgr :: GetPrevSpellInChain ( uint32 spell_id ) const
{
if ( SpellChainNode const * node = GetSpellChainNode ( spell_id ))
2011-08-03 11:23:08 +02:00
if ( node -> prev )
return node -> prev -> Id ;
2010-04-18 23:20:07 +02:00
2011-07-26 23:09:28 +02:00
return 0 ;
}
2010-04-18 23:20:07 +02:00
2011-07-26 23:09:28 +02:00
uint8 SpellMgr :: GetSpellRank ( uint32 spell_id ) const
{
if ( SpellChainNode const * node = GetSpellChainNode ( spell_id ))
return node -> rank ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
return 0 ;
}
2010-04-18 23:20:07 +02:00
2011-07-26 23:09:28 +02:00
uint32 SpellMgr :: GetSpellWithRank ( uint32 spell_id , uint32 rank , bool strict ) const
{
if ( SpellChainNode const * node = GetSpellChainNode ( spell_id ))
{
if ( rank != node -> rank )
return GetSpellWithRank ( node -> rank < rank ? node -> next -> Id : node -> prev -> Id , rank , strict );
}
else if ( strict && rank > 1 )
return 0 ;
return spell_id ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellRequiredMapBounds SpellMgr :: GetSpellsRequiredForSpellBounds ( uint32 spell_id ) const
{
return SpellRequiredMapBounds ( mSpellReq . lower_bound ( spell_id ), mSpellReq . upper_bound ( spell_id ));
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellsRequiringSpellMapBounds SpellMgr :: GetSpellsRequiringSpellBounds ( uint32 spell_id ) const
{
return SpellsRequiringSpellMapBounds ( mSpellsReqSpell . lower_bound ( spell_id ), mSpellsReqSpell . upper_bound ( spell_id ));
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
bool SpellMgr :: IsSpellRequiringSpell ( uint32 spellid , uint32 req_spellid ) const
{
SpellsRequiringSpellMapBounds spellsRequiringSpell = GetSpellsRequiringSpellBounds ( req_spellid );
for ( SpellsRequiringSpellMap :: const_iterator itr = spellsRequiringSpell . first ; itr != spellsRequiringSpell . second ; ++ itr )
2009-05-25 16:50:01 -05:00
{
2011-07-26 23:09:28 +02:00
if ( itr -> second == spellid )
return true ;
2009-05-25 16:50:01 -05:00
}
2011-07-26 23:09:28 +02:00
return false ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
const SpellsRequiringSpellMap SpellMgr :: GetSpellsRequiringSpell ()
{
return this -> mSpellsReqSpell ;
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 SpellMgr :: GetSpellRequired ( uint32 spell_id ) const
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
SpellRequiredMap :: const_iterator itr = mSpellReq . find ( spell_id );
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( itr == mSpellReq . end ())
return 0 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
return itr -> second ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellLearnSkillNode const * SpellMgr :: GetSpellLearnSkill ( uint32 spell_id ) const
{
SpellLearnSkillMap :: const_iterator itr = mSpellLearnSkills . find ( spell_id );
if ( itr != mSpellLearnSkills . end ())
return & itr -> second ;
else
return NULL ;
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellLearnSpellMapBounds SpellMgr :: GetSpellLearnSpellMapBounds ( uint32 spell_id ) const
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
return SpellLearnSpellMapBounds ( mSpellLearnSpells . lower_bound ( spell_id ), mSpellLearnSpells . upper_bound ( spell_id ));
}
2010-12-19 17:06:33 +01:00
2011-07-26 23:09:28 +02:00
bool SpellMgr :: IsSpellLearnSpell ( uint32 spell_id ) const
{
return mSpellLearnSpells . find ( spell_id ) != mSpellLearnSpells . end ();
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
bool SpellMgr :: IsSpellLearnToSpell ( uint32 spell_id1 , uint32 spell_id2 ) const
{
SpellLearnSpellMapBounds bounds = GetSpellLearnSpellMapBounds ( spell_id1 );
for ( SpellLearnSpellMap :: const_iterator i = bounds . first ; i != bounds . second ; ++ i )
if ( i -> second . spell == spell_id2 )
return true ;
return false ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellTargetPosition const * SpellMgr :: GetSpellTargetPosition ( uint32 spell_id ) const
{
SpellTargetPositionMap :: const_iterator itr = mSpellTargetPositions . find ( spell_id );
if ( itr != mSpellTargetPositions . end ())
return & itr -> second ;
return NULL ;
}
SpellSpellGroupMapBounds SpellMgr :: GetSpellSpellGroupMapBounds ( uint32 spell_id ) const
{
spell_id = GetFirstSpellInChain ( spell_id );
return SpellSpellGroupMapBounds ( mSpellSpellGroup . lower_bound ( spell_id ), mSpellSpellGroup . upper_bound ( spell_id ));
}
uint32 SpellMgr :: IsSpellMemberOfSpellGroup ( uint32 spellid , SpellGroup groupid ) const
{
SpellSpellGroupMapBounds spellGroup = GetSpellSpellGroupMapBounds ( spellid );
for ( SpellSpellGroupMap :: const_iterator itr = spellGroup . first ; itr != spellGroup . second ; ++ itr )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
if ( itr -> second == groupid )
return true ;
2008-11-17 22:07:21 -06:00
}
2011-07-26 23:09:28 +02:00
return false ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellGroupSpellMapBounds SpellMgr :: GetSpellGroupSpellMapBounds ( SpellGroup group_id ) const
{
return SpellGroupSpellMapBounds ( mSpellGroupSpell . lower_bound ( group_id ), mSpellGroupSpell . upper_bound ( group_id ));
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: GetSetOfSpellsInSpellGroup ( SpellGroup group_id , std :: set < uint32 >& foundSpells ) const
{
std :: set < SpellGroup > usedGroups ;
GetSetOfSpellsInSpellGroup ( group_id , foundSpells , usedGroups );
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: GetSetOfSpellsInSpellGroup ( SpellGroup group_id , std :: set < uint32 >& foundSpells , std :: set < SpellGroup >& usedGroups ) const
{
if ( usedGroups . find ( group_id ) != usedGroups . end ())
return ;
usedGroups . insert ( group_id );
SpellGroupSpellMapBounds groupSpell = GetSpellGroupSpellMapBounds ( group_id );
for ( SpellGroupSpellMap :: const_iterator itr = groupSpell . first ; itr != groupSpell . second ; ++ itr )
{
if ( itr -> second < 0 )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
SpellGroup currGroup = ( SpellGroup ) abs ( itr -> second );
GetSetOfSpellsInSpellGroup ( currGroup , foundSpells , usedGroups );
2008-11-17 22:07:21 -06:00
}
2011-07-26 23:09:28 +02:00
else
{
foundSpells . insert ( itr -> second );
}
}
}
2009-10-17 15:51:44 -07:00
2011-10-18 23:27:39 +02:00
bool SpellMgr :: AddSameEffectStackRuleSpellGroups ( SpellInfo const * spellInfo , int32 amount , std :: map < SpellGroup , int32 >& groups ) const
{
2011-10-18 23:38:55 +02:00
uint32 spellId = spellInfo -> GetFirstRankSpell () -> Id ;
SpellSpellGroupMapBounds spellGroup = GetSpellSpellGroupMapBounds ( spellId );
// Find group with SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT if it belongs to one
for ( SpellSpellGroupMap :: const_iterator itr = spellGroup . first ; itr != spellGroup . second ; ++ itr )
{
SpellGroup group = itr -> second ;
SpellGroupStackMap :: const_iterator found = mSpellGroupStack . find ( group );
2011-10-18 23:27:39 +02:00
if ( found != mSpellGroupStack . end ())
2011-10-18 23:38:55 +02:00
{
if ( found -> second == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT )
{
// Put the highest amount in the map
if ( groups . find ( group ) == groups . end ())
groups [ group ] = amount ;
else
{
int32 curr_amount = groups [ group ];
// Take absolute value because this also counts for the highest negative aura
if ( abs ( curr_amount ) < abs ( amount ))
groups [ group ] = amount ;
}
// return because a spell should be in only one SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group
return true ;
}
}
}
// Not in a SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group, so return false
return false ;
2011-10-18 23:27:39 +02:00
}
2011-07-26 23:09:28 +02:00
SpellGroupStackRule SpellMgr :: CheckSpellGroupStackRules ( SpellInfo const * spellInfo1 , SpellInfo const * spellInfo2 ) const
{
uint32 spellid_1 = spellInfo1 -> GetFirstRankSpell () -> Id ;
uint32 spellid_2 = spellInfo2 -> GetFirstRankSpell () -> Id ;
if ( spellid_1 == spellid_2 )
return SPELL_GROUP_STACK_RULE_DEFAULT ;
// find SpellGroups which are common for both spells
SpellSpellGroupMapBounds spellGroup1 = GetSpellSpellGroupMapBounds ( spellid_1 );
std :: set < SpellGroup > groups ;
for ( SpellSpellGroupMap :: const_iterator itr = spellGroup1 . first ; itr != spellGroup1 . second ; ++ itr )
{
if ( IsSpellMemberOfSpellGroup ( spellid_2 , itr -> second ))
2008-11-26 15:14:03 -06:00
{
2011-07-26 23:09:28 +02:00
bool add = true ;
SpellGroupSpellMapBounds groupSpell = GetSpellGroupSpellMapBounds ( itr -> second );
for ( SpellGroupSpellMap :: const_iterator itr2 = groupSpell . first ; itr2 != groupSpell . second ; ++ itr2 )
2008-11-26 15:14:03 -06:00
{
2011-07-26 23:09:28 +02:00
if ( itr2 -> second < 0 )
{
SpellGroup currGroup = ( SpellGroup ) abs ( itr2 -> second );
if ( IsSpellMemberOfSpellGroup ( spellid_1 , currGroup ) && IsSpellMemberOfSpellGroup ( spellid_2 , currGroup ))
{
add = false ;
break ;
}
}
2008-11-26 15:14:03 -06:00
}
2011-07-26 23:09:28 +02:00
if ( add )
groups . insert ( itr -> second );
2008-11-26 15:14:03 -06:00
}
2011-07-26 23:09:28 +02:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellGroupStackRule rule = SPELL_GROUP_STACK_RULE_DEFAULT ;
for ( std :: set < SpellGroup >:: iterator itr = groups . begin () ; itr != groups . end () ; ++ itr )
{
SpellGroupStackMap :: const_iterator found = mSpellGroupStack . find ( * itr );
if ( found != mSpellGroupStack . end ())
rule = found -> second ;
if ( rule )
break ;
}
return rule ;
}
SpellProcEventEntry const * SpellMgr :: GetSpellProcEvent ( uint32 spellId ) const
{
SpellProcEventMap :: const_iterator itr = mSpellProcEventMap . find ( spellId );
if ( itr != mSpellProcEventMap . end ())
return & itr -> second ;
return NULL ;
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
bool SpellMgr :: IsSpellProcEventCanTriggeredBy ( SpellProcEventEntry const * spellProcEvent , uint32 EventProcFlag , SpellInfo const * procSpell , uint32 procFlags , uint32 procExtra , bool active )
2008-11-26 15:14:03 -06:00
{
// No extra req need
uint32 procEvent_procEx = PROC_EX_NONE ;
2009-10-17 15:51:44 -07:00
2008-11-26 15:14:03 -06:00
// check prockFlags for condition
2010-04-07 19:14:10 +02:00
if (( procFlags & EventProcFlag ) == 0 )
2008-11-26 15:14:03 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2009-05-17 18:00:33 +02:00
bool hasFamilyMask = false ;
2009-10-17 15:51:44 -07:00
2009-05-15 16:59:27 +02:00
/* Check Periodic Auras
2009-10-17 15:51:44 -07:00
2009-07-18 22:18:47 +02:00
*Dots can trigger if spell has no PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL
nor PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL
2009-10-17 15:51:44 -07:00
2009-07-18 22:18:47 +02:00
*Only Hots can trigger if spell has PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL
2009-10-17 15:51:44 -07:00
2009-07-18 22:18:47 +02:00
*Only dots can trigger if spell has both positivity flags or PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL
2009-10-17 15:51:44 -07:00
2009-07-18 22:18:47 +02:00
*Aura has to have PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL or spellfamily specified to trigger from Hot
2009-10-17 15:51:44 -07:00
2009-05-15 16:59:27 +02:00
*/
2009-10-17 15:51:44 -07:00
2010-10-08 19:17:49 +02:00
if ( procFlags & PROC_FLAG_DONE_PERIODIC )
2009-05-15 16:59:27 +02:00
{
2010-10-08 19:17:49 +02:00
if ( EventProcFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG )
2009-05-15 16:59:27 +02:00
{
2009-06-15 18:27:41 +02:00
if ( ! ( procExtra & PROC_EX_INTERNAL_DOT ))
2009-05-15 16:59:27 +02:00
return false ;
}
2009-07-18 22:18:47 +02:00
else if ( procExtra & PROC_EX_INTERNAL_HOT )
procExtra |= PROC_EX_INTERNAL_REQ_FAMILY ;
2010-10-08 19:17:49 +02:00
else if ( EventProcFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS )
2009-08-23 11:33:00 -05:00
return false ;
2009-05-15 16:59:27 +02:00
}
2009-10-17 15:51:44 -07:00
2010-10-08 19:17:49 +02:00
if ( procFlags & PROC_FLAG_TAKEN_PERIODIC )
2009-05-15 16:59:27 +02:00
{
2010-10-08 19:17:49 +02:00
if ( EventProcFlag & PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS )
2009-05-15 16:59:27 +02:00
{
2009-06-15 18:27:41 +02:00
if ( ! ( procExtra & PROC_EX_INTERNAL_DOT ))
2009-05-15 16:59:27 +02:00
return false ;
}
2009-07-18 22:18:47 +02:00
else if ( procExtra & PROC_EX_INTERNAL_HOT )
procExtra |= PROC_EX_INTERNAL_REQ_FAMILY ;
2010-10-08 19:17:49 +02:00
else if ( EventProcFlag & PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS )
2009-08-23 11:33:00 -05:00
return false ;
2009-05-15 16:59:27 +02:00
}
2009-07-11 20:06:02 +02:00
// Trap casts are active by default
2010-10-08 19:17:49 +02:00
if ( procFlags & PROC_FLAG_DONE_TRAP_ACTIVATION )
2009-07-11 20:06:02 +02:00
active = true ;
2009-10-17 15:51:44 -07:00
2008-11-26 15:14:03 -06:00
// Always trigger for this
2009-07-11 20:06:02 +02:00
if ( procFlags & ( PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH ))
2008-11-26 15:14:03 -06:00
return true ;
2009-10-17 15:51:44 -07:00
2008-11-26 15:14:03 -06:00
if ( spellProcEvent ) // Exist event data
{
// Store extra req
procEvent_procEx = spellProcEvent -> procEx ;
2009-10-17 15:51:44 -07:00
2008-11-26 15:14:03 -06:00
// For melee triggers
if ( procSpell == NULL )
{
// Check (if set) for school (melee attack have Normal school)
2010-04-07 19:14:10 +02:00
if ( spellProcEvent -> schoolMask && ( spellProcEvent -> schoolMask & SPELL_SCHOOL_MASK_NORMAL ) == 0 )
2008-11-26 15:14:03 -06:00
return false ;
}
else // For spells need check school/spell family/family mask
{
// Check (if set) for school
2010-04-07 19:14:10 +02:00
if ( spellProcEvent -> schoolMask && ( spellProcEvent -> schoolMask & procSpell -> SchoolMask ) == 0 )
2008-11-26 15:14:03 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2008-11-26 15:14:03 -06:00
// Check (if set) for spellFamilyName
2010-04-07 19:14:10 +02:00
if ( spellProcEvent -> spellFamilyName && ( spellProcEvent -> spellFamilyName != procSpell -> SpellFamilyName ))
2008-11-26 15:14:03 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2008-11-26 15:14:03 -06:00
// spellFamilyName is Ok need check for spellFamilyMask if present
2010-04-07 19:14:10 +02:00
if ( spellProcEvent -> spellFamilyMask )
2008-11-26 15:14:03 -06:00
{
2011-06-28 13:53:48 +02:00
if ( ! ( spellProcEvent -> spellFamilyMask & procSpell -> SpellFamilyFlags ))
2008-11-26 15:14:03 -06:00
return false ;
2009-05-17 18:00:33 +02:00
hasFamilyMask = true ;
2009-07-09 23:49:46 +02:00
// Some spells are not considered as active even with have spellfamilyflags
if ( ! ( procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL ))
active = true ;
2008-11-26 15:14:03 -06:00
}
}
}
2009-10-17 15:51:44 -07:00
2009-07-18 22:18:47 +02:00
if ( procExtra & ( PROC_EX_INTERNAL_REQ_FAMILY ))
2009-05-17 18:00:33 +02:00
{
if ( ! hasFamilyMask )
return false ;
}
2009-10-17 15:51:44 -07:00
2008-11-26 15:14:03 -06:00
// Check for extra req (if none) and hit/crit
if ( procEvent_procEx == PROC_EX_NONE )
{
2009-07-02 21:32:19 +02:00
// No extra req, so can trigger only for hit/crit - spell has to be active
2010-04-07 19:14:10 +02:00
if (( procExtra & ( PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT )) && active )
2008-11-26 15:14:03 -06:00
return true ;
}
else // Passive spells hits here only if resist/reflect/immune/evade
{
2009-07-02 21:32:19 +02:00
if ( procExtra & AURA_SPELL_PROC_EX_MASK )
{
2009-07-09 23:49:46 +02:00
// if spell marked as procing only from not active spells
if ( active && procEvent_procEx & PROC_EX_NOT_ACTIVE_SPELL )
return false ;
// if spell marked as procing only from active spells
if ( ! active && procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL )
return false ;
2009-07-02 21:32:19 +02:00
// Exist req for PROC_EX_EX_TRIGGER_ALWAYS
if ( procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS )
return true ;
2009-07-09 23:49:46 +02:00
// PROC_EX_NOT_ACTIVE_SPELL and PROC_EX_ONLY_ACTIVE_SPELL flags handle: if passed checks before
2010-01-10 01:23:15 +01:00
if (( procExtra & ( PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT )) && (( procEvent_procEx & ( AURA_SPELL_PROC_EX_MASK )) == 0 ))
2009-07-09 23:49:46 +02:00
return true ;
2009-07-02 21:32:19 +02:00
}
2009-07-13 18:05:53 +02:00
// Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other)
if ( procEvent_procEx & procExtra )
return true ;
2008-11-26 15:14:03 -06:00
}
return false ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellProcEntry const * SpellMgr :: GetSpellProcEntry ( uint32 spellId ) const
2011-06-26 13:54:44 +02:00
{
2011-07-26 23:09:28 +02:00
SpellProcMap :: const_iterator itr = mSpellProcMap . find ( spellId );
if ( itr != mSpellProcMap . end ())
return & itr -> second ;
return NULL ;
}
2011-06-26 13:54:44 +02:00
2011-07-26 23:09:28 +02:00
bool SpellMgr :: CanSpellTriggerProcOnEvent ( SpellProcEntry const & procEntry , ProcEventInfo & eventInfo )
{
// proc type doesn't match
if ( ! ( eventInfo . GetTypeMask () & procEntry . typeMask ))
return false ;
2011-06-26 13:54:44 +02:00
2011-07-26 23:09:28 +02:00
// check XP or honor target requirement
if ( procEntry . attributesMask & PROC_ATTR_REQ_EXP_OR_HONOR )
if ( Player * actor = eventInfo . GetActor () -> ToPlayer ())
if ( eventInfo . GetActionTarget () && ! actor -> isHonorOrXPTarget ( eventInfo . GetActionTarget ()))
return false ;
2011-06-26 13:54:44 +02:00
2011-07-26 23:09:28 +02:00
// always trigger for these types
if ( eventInfo . GetTypeMask () & ( PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH ))
return true ;
2011-07-10 13:13:02 +02:00
// check school mask (if set) for other trigger types
if ( procEntry . schoolMask && ! ( eventInfo . GetSchoolMask () & procEntry . schoolMask ))
return false ;
// check spell family name/flags (if set) for spells
if ( eventInfo . GetTypeMask () & ( PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION ))
{
if ( procEntry . spellFamilyName && ( procEntry . spellFamilyName != eventInfo . GetSpellInfo () -> SpellFamilyName ))
return false ;
if ( procEntry . spellFamilyMask && ! ( procEntry . spellFamilyMask & eventInfo . GetSpellInfo () -> SpellFamilyFlags ))
return false ;
}
// check spell type mask (if set)
if ( eventInfo . GetTypeMask () & ( SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK ))
{
if ( procEntry . spellTypeMask && ! ( eventInfo . GetSpellTypeMask () & procEntry . spellTypeMask ))
return false ;
}
// check spell phase mask
if ( eventInfo . GetTypeMask () & REQ_SPELL_PHASE_PROC_FLAG_MASK )
{
if ( ! ( eventInfo . GetSpellPhaseMask () & procEntry . spellPhaseMask ))
return false ;
}
// check hit mask (on taken hit or on done hit, but not on spell cast phase)
if (( eventInfo . GetTypeMask () & TAKEN_HIT_PROC_FLAG_MASK ) || (( eventInfo . GetTypeMask () & DONE_HIT_PROC_FLAG_MASK ) && ! ( eventInfo . GetSpellPhaseMask () & PROC_SPELL_PHASE_CAST )))
{
uint32 hitMask = procEntry . hitMask ;
// get default values if hit mask not set
if ( ! hitMask )
{
// for taken procs allow normal + critical hits by default
if ( eventInfo . GetTypeMask () & TAKEN_HIT_PROC_FLAG_MASK )
hitMask |= PROC_HIT_NORMAL | PROC_HIT_CRITICAL ;
// for done procs allow normal + critical + absorbs by default
else
hitMask |= PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB ;
}
if ( ! ( eventInfo . GetHitMask () & hitMask ))
return false ;
}
return true ;
}
2011-07-26 23:09:28 +02:00
SpellBonusEntry const * SpellMgr :: GetSpellBonusData ( uint32 spellId ) const
2011-06-26 13:54:44 +02:00
{
2011-07-26 23:09:28 +02:00
// Lookup data
SpellBonusMap :: const_iterator itr = mSpellBonusMap . find ( spellId );
if ( itr != mSpellBonusMap . end ())
return & itr -> second ;
// Not found, try lookup for 1 spell rank if exist
if ( uint32 rank_1 = GetFirstSpellInChain ( spellId ))
2011-06-26 13:54:44 +02:00
{
2011-07-26 23:09:28 +02:00
SpellBonusMap :: const_iterator itr2 = mSpellBonusMap . find ( rank_1 );
if ( itr2 != mSpellBonusMap . end ())
return & itr2 -> second ;
2011-06-26 13:54:44 +02:00
}
2011-07-26 23:09:28 +02:00
return NULL ;
}
2011-06-26 13:54:44 +02:00
2011-08-21 12:00:36 +02:00
SpellThreatEntry const * SpellMgr :: GetSpellThreatEntry ( uint32 spellID ) const
2011-07-26 23:09:28 +02:00
{
2011-08-21 12:00:36 +02:00
SpellThreatMap :: const_iterator itr = mSpellThreatMap . find ( spellID );
if ( itr != mSpellThreatMap . end ())
return & itr -> second ;
else
{
uint32 firstSpell = GetFirstSpellInChain ( spellID );
2011-11-23 19:17:33 +01:00
itr = mSpellThreatMap . find ( firstSpell );
2011-08-21 12:00:36 +02:00
if ( itr != mSpellThreatMap . end ())
return & itr -> second ;
}
return NULL ;
2011-07-26 23:09:28 +02:00
}
2011-06-26 13:54:44 +02:00
2011-07-26 23:09:28 +02:00
SkillLineAbilityMapBounds SpellMgr :: GetSkillLineAbilityMapBounds ( uint32 spell_id ) const
{
return SkillLineAbilityMapBounds ( mSkillLineAbilityMap . lower_bound ( spell_id ), mSkillLineAbilityMap . upper_bound ( spell_id ));
}
2011-06-26 13:54:44 +02:00
2011-07-26 23:09:28 +02:00
PetAura const * SpellMgr :: GetPetAura ( uint32 spell_id , uint8 eff )
{
SpellPetAuraMap :: const_iterator itr = mSpellPetAuraMap . find (( spell_id << 8 ) + eff );
if ( itr != mSpellPetAuraMap . end ())
return & itr -> second ;
else
return NULL ;
}
2011-06-26 13:54:44 +02:00
2011-07-26 23:09:28 +02:00
SpellEnchantProcEntry const * SpellMgr :: GetSpellEnchantProcEvent ( uint32 enchId ) const
{
SpellEnchantProcEventMap :: const_iterator itr = mSpellEnchantProcEventMap . find ( enchId );
if ( itr != mSpellEnchantProcEventMap . end ())
return & itr -> second ;
return NULL ;
2011-06-26 13:54:44 +02:00
}
2011-07-26 23:09:28 +02:00
bool SpellMgr :: IsArenaAllowedEnchancment ( uint32 ench_id ) const
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
return mEnchantCustomAttr [ ench_id ];
}
2010-12-19 17:06:33 +01:00
2011-07-26 23:09:28 +02:00
const std :: vector < int32 >* SpellMgr :: GetSpellLinked ( int32 spell_id ) const
{
SpellLinkedMap :: const_iterator itr = mSpellLinkedMap . find ( spell_id );
return itr != mSpellLinkedMap . end () ? & ( itr -> second ) : NULL ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
PetLevelupSpellSet const * SpellMgr :: GetPetLevelupSpellList ( uint32 petFamily ) const
{
PetLevelupSpellMap :: const_iterator itr = mPetLevelupSpellMap . find ( petFamily );
if ( itr != mPetLevelupSpellMap . end ())
return & itr -> second ;
else
return NULL ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
PetDefaultSpellsEntry const * SpellMgr :: GetPetDefaultSpellsEntry ( int32 id ) const
{
PetDefaultSpellsMap :: const_iterator itr = mPetDefaultSpellsMap . find ( id );
if ( itr != mPetDefaultSpellsMap . end ())
return & itr -> second ;
return NULL ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellAreaMapBounds SpellMgr :: GetSpellAreaMapBounds ( uint32 spell_id ) const
{
return SpellAreaMapBounds ( mSpellAreaMap . lower_bound ( spell_id ), mSpellAreaMap . upper_bound ( spell_id ));
}
2010-02-02 22:35:01 +01:00
2011-07-26 23:09:28 +02:00
SpellAreaForQuestMapBounds SpellMgr :: GetSpellAreaForQuestMapBounds ( uint32 quest_id , bool active ) const
{
if ( active )
return SpellAreaForQuestMapBounds ( mSpellAreaForActiveQuestMap . lower_bound ( quest_id ), mSpellAreaForActiveQuestMap . upper_bound ( quest_id ));
else
return SpellAreaForQuestMapBounds ( mSpellAreaForQuestMap . lower_bound ( quest_id ), mSpellAreaForQuestMap . upper_bound ( quest_id ));
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellAreaForQuestMapBounds SpellMgr :: GetSpellAreaForQuestEndMapBounds ( uint32 quest_id ) const
{
return SpellAreaForQuestMapBounds ( mSpellAreaForQuestEndMap . lower_bound ( quest_id ), mSpellAreaForQuestEndMap . upper_bound ( quest_id ));
}
2010-02-02 22:35:01 +01:00
2011-07-26 23:09:28 +02:00
SpellAreaForAuraMapBounds SpellMgr :: GetSpellAreaForAuraMapBounds ( uint32 spell_id ) const
{
return SpellAreaForAuraMapBounds ( mSpellAreaForAuraMap . lower_bound ( spell_id ), mSpellAreaForAuraMap . upper_bound ( spell_id ));
}
2010-02-01 19:22:32 +01:00
2011-07-26 23:09:28 +02:00
SpellAreaForAreaMapBounds SpellMgr :: GetSpellAreaForAreaMapBounds ( uint32 area_id ) const
{
return SpellAreaForAreaMapBounds ( mSpellAreaForAreaMap . lower_bound ( area_id ), mSpellAreaForAreaMap . upper_bound ( area_id ));
}
2010-02-02 22:35:01 +01:00
2011-07-26 23:09:28 +02:00
bool SpellArea :: IsFitToRequirements ( Player const * player , uint32 newZone , uint32 newArea ) const
{
if ( gender != GENDER_NONE ) // not in expected gender
if ( ! player || gender != player -> getGender ())
return false ;
if ( raceMask ) // not in expected race
if ( ! player || ! ( raceMask & player -> getRaceMask ()))
return false ;
if ( areaId ) // not in expected zone
if ( newZone != areaId && newArea != areaId )
return false ;
if ( questStart ) // not in expected required quest state
if ( ! player || (( ! questStartCanActive || ! player -> IsActiveQuest ( questStart )) && ! player -> GetQuestRewardStatus ( questStart )))
return false ;
if ( questEnd ) // not in expected forbidden quest state
if ( ! player || player -> GetQuestRewardStatus ( questEnd ))
return false ;
if ( auraSpell ) // not have expected aura
if ( ! player || ( auraSpell > 0 && ! player -> HasAura ( auraSpell )) || ( auraSpell < 0 && player -> HasAura ( - auraSpell )))
return false ;
// Extra conditions -- leaving the possibility add extra conditions...
switch ( spellId )
2010-02-02 22:35:01 +01:00
{
2011-07-26 23:09:28 +02:00
case 58600 : // No fly Zone - Dalaran
2010-02-01 19:22:32 +01:00
{
2011-07-26 23:09:28 +02:00
if ( ! player )
return false ;
AreaTableEntry const * pArea = GetAreaEntryByAreaID ( player -> GetAreaId ());
if ( ! ( pArea && pArea -> flags & AREA_FLAG_NO_FLY_ZONE ))
return false ;
if ( ! player -> HasAuraType ( SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED ) && ! player -> HasAuraType ( SPELL_AURA_FLY ))
return false ;
break ;
2008-11-17 22:07:21 -06:00
}
2011-07-26 23:09:28 +02:00
case 68719 : // Oil Refinery - Isle of Conquest.
case 68720 : // Quarry - Isle of Conquest.
2010-02-01 19:22:32 +01:00
{
2011-07-26 23:09:28 +02:00
if ( player -> GetBattlegroundTypeId () != BATTLEGROUND_IC || ! player -> GetBattleground ())
return false ;
2010-02-02 22:35:01 +01:00
2011-07-26 23:09:28 +02:00
uint8 nodeType = spellId == 68719 ? NODE_TYPE_REFINERY : NODE_TYPE_QUARRY ;
uint8 nodeState = player -> GetTeamId () == TEAM_ALLIANCE ? NODE_STATE_CONTROLLED_A : NODE_STATE_CONTROLLED_H ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
BattlegroundIC * pIC = static_cast < BattlegroundIC *> ( player -> GetBattleground ());
if ( pIC -> GetNodeState ( nodeType ) == nodeState )
return true ;
2010-02-02 22:35:01 +01:00
2011-07-26 23:09:28 +02:00
return false ;
2010-02-02 22:35:01 +01:00
}
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
return true ;
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellInfos ()
{
}
void SpellMgr :: LoadSpellRanks ()
2010-01-23 17:05:20 +01:00
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2011-07-26 23:09:28 +02:00
// cleanup core data before reload - remove reference to ChainNode from SpellInfo
for ( SpellChainMap :: iterator itr = mSpellChains . begin (); itr != mSpellChains . end (); ++ itr )
{
mSpellInfoMap [ itr -> first ] -> ChainEntry = NULL ;
}
mSpellChains . clear ();
2010-01-23 17:05:20 +01:00
2011-09-29 12:43:05 +02:00
QueryResult result = WorldDatabase . Query ( "SELECT first_spell_id, spell_id, rank from spell_ranks ORDER BY first_spell_id, rank" );
2010-01-23 17:05:20 +01:00
2010-04-07 22:59:46 +02:00
if ( ! result )
2010-01-23 17:05:20 +01:00
{
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded 0 spell rank records" );
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "`spell_ranks` table is empty!" );
2010-01-23 17:05:20 +01:00
return ;
}
2011-07-26 23:09:28 +02:00
uint32 rows = 0 ;
bool finished = false ;
2010-01-23 17:05:20 +01:00
do
{
2011-07-26 23:09:28 +02:00
// spellid, rank
std :: list < std :: pair < int32 , int32 > > rankChain ;
int32 currentSpell = - 1 ;
int32 lastSpell = - 1 ;
2010-01-23 17:05:20 +01:00
2011-07-26 23:09:28 +02:00
// fill one chain
while ( currentSpell == lastSpell && ! finished )
2010-02-02 22:35:01 +01:00
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2010-01-23 17:05:20 +01:00
2011-07-26 23:09:28 +02:00
currentSpell = fields [ 0 ]. GetUInt32 ();
if ( lastSpell == - 1 )
lastSpell = currentSpell ;
uint32 spell_id = fields [ 1 ]. GetUInt32 ();
uint32 rank = fields [ 2 ]. GetUInt32 ();
2010-01-23 17:05:20 +01:00
2011-07-26 23:09:28 +02:00
// don't drop the row if we're moving to the next rank
if ( currentSpell == lastSpell )
{
rankChain . push_back ( std :: make_pair ( spell_id , rank ));
if ( ! result -> NextRow ())
finished = true ;
}
else
break ;
}
// check if chain is made with valid first spell
2011-08-04 13:16:09 +02:00
SpellInfo const * first = GetSpellInfo ( lastSpell );
2011-07-26 23:09:28 +02:00
if ( ! first )
2010-01-23 17:05:20 +01:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell rank identifier(first_spell_id) %u listed in `spell_ranks` does not exist!" , lastSpell );
2010-01-23 17:05:20 +01:00
continue ;
}
2011-07-26 23:09:28 +02:00
// check if chain is long enough
if ( rankChain . size () < 2 )
{
sLog -> outErrorDb ( "There is only 1 spell rank for identifier(first_spell_id) %u in `spell_ranks`, entry is not needed!" , lastSpell );
continue ;
}
int32 curRank = 0 ;
bool valid = true ;
// check spells in chain
for ( std :: list < std :: pair < int32 , int32 > >:: iterator itr = rankChain . begin () ; itr != rankChain . end (); ++ itr )
{
2011-08-04 13:16:09 +02:00
SpellInfo const * spell = GetSpellInfo ( itr -> first );
2011-07-26 23:09:28 +02:00
if ( ! spell )
{
sLog -> outErrorDb ( "Spell %u (rank %u) listed in `spell_ranks` for chain %u does not exist!" , itr -> first , itr -> second , lastSpell );
valid = false ;
break ;
}
++ curRank ;
if ( itr -> second != curRank )
{
sLog -> outErrorDb ( "Spell %u (rank %u) listed in `spell_ranks` for chain %u does not have proper rank value(should be %u)!" , itr -> first , itr -> second , lastSpell , curRank );
valid = false ;
break ;
}
}
if ( ! valid )
continue ;
int32 prevRank = 0 ;
// insert the chain
std :: list < std :: pair < int32 , int32 > >:: iterator itr = rankChain . begin ();
do
{
++ rows ;
int32 addedSpell = itr -> first ;
mSpellChains [ addedSpell ]. first = GetSpellInfo ( lastSpell );
mSpellChains [ addedSpell ]. last = GetSpellInfo ( rankChain . back (). first );
mSpellChains [ addedSpell ]. rank = itr -> second ;
mSpellChains [ addedSpell ]. prev = GetSpellInfo ( prevRank );
mSpellInfoMap [ addedSpell ] -> ChainEntry = & mSpellChains [ addedSpell ];
prevRank = addedSpell ;
++ itr ;
if ( itr == rankChain . end ())
{
mSpellChains [ addedSpell ]. next = NULL ;
break ;
}
else
mSpellChains [ addedSpell ]. next = GetSpellInfo ( itr -> first );
}
while ( true );
} while ( ! finished );
2010-01-23 17:05:20 +01:00
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u spell rank records in %u ms" , rows , GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2010-01-23 17:05:20 +01:00
}
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellRequired ()
2008-11-17 22:07:21 -06:00
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2011-07-26 23:09:28 +02:00
mSpellsReqSpell . clear (); // need for reload case
mSpellReq . clear (); // need for reload case
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
QueryResult result = WorldDatabase . Query ( "SELECT spell_id, req_spell from spell_required" );
2009-10-17 15:51:44 -07:00
2010-01-01 14:19:29 -06:00
if ( ! result )
2009-07-30 11:37:08 +08:00
{
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded 0 spell required records" );
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "`spell_required` table is empty!" );
2009-07-30 11:37:08 +08:00
return ;
}
2011-07-26 23:09:28 +02:00
uint32 rows = 0 ;
2009-10-17 15:51:44 -07:00
2009-07-30 11:37:08 +08:00
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 spell_id = fields [ 0 ]. GetUInt32 ();
uint32 spell_req = fields [ 1 ]. GetUInt32 ();
// check if chain is made with valid first spell
2011-08-04 13:16:09 +02:00
SpellInfo const * spell = GetSpellInfo ( spell_id );
2011-07-26 23:09:28 +02:00
if ( ! spell )
2009-07-30 11:37:08 +08:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "spell_id %u in `spell_required` table is not found in dbcs, skipped" , spell_id );
continue ;
}
2011-08-04 13:16:09 +02:00
SpellInfo const * req_spell = GetSpellInfo ( spell_req );
2011-07-26 23:09:28 +02:00
if ( ! req_spell )
{
sLog -> outErrorDb ( "req_spell %u in `spell_required` table is not found in dbcs, skipped" , spell_req );
continue ;
}
if ( GetFirstSpellInChain ( spell_id ) == GetFirstSpellInChain ( spell_req ))
{
sLog -> outErrorDb ( "req_spell %u and spell_id %u in `spell_required` table are ranks of the same spell, entry not needed, skipped" , spell_req , spell_id );
continue ;
}
if ( IsSpellRequiringSpell ( spell_id , spell_req ))
{
sLog -> outErrorDb ( "duplicated entry of req_spell %u and spell_id %u in `spell_required`, skipped" , spell_req , spell_id );
2009-07-30 11:37:08 +08:00
continue ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mSpellReq . insert ( std :: pair < uint32 , uint32 > ( spell_id , spell_req ));
mSpellsReqSpell . insert ( std :: pair < uint32 , uint32 > ( spell_req , spell_id ));
++ rows ;
2010-01-01 14:19:29 -06:00
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u spell required records in %u ms" , rows , GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellLearnSkills ()
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mSpellLearnSkills . clear (); // need for reload case
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// search auto-learned skills and add its to map also for use in unlearn spells/talents
uint32 dbc_count = 0 ;
2011-08-26 09:41:33 +02:00
for ( uint32 spell = 0 ; spell < GetSpellInfoStoreSize (); ++ spell )
2011-07-26 23:09:28 +02:00
{
2011-08-04 13:16:09 +02:00
SpellInfo const * entry = GetSpellInfo ( spell );
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( ! entry )
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2009-01-25 16:35:14 -06:00
{
2011-07-26 23:09:28 +02:00
if ( entry -> Effects [ i ]. Effect == SPELL_EFFECT_SKILL )
{
SpellLearnSkillNode dbc_node ;
dbc_node . skill = entry -> Effects [ i ]. MiscValue ;
dbc_node . step = entry -> Effects [ i ]. CalcValue ();
if ( dbc_node . skill != SKILL_RIDING )
dbc_node . value = 1 ;
else
dbc_node . value = dbc_node . step * 75 ;
dbc_node . maxvalue = dbc_node . step * 75 ;
mSpellLearnSkills [ spell ] = dbc_node ;
++ dbc_count ;
2009-01-25 16:35:14 -06:00
break ;
2011-07-26 23:09:28 +02:00
}
2009-01-25 16:35:14 -06:00
}
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u Spell Learn Skills from DBC in %u ms" , dbc_count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellLearnSpells ()
2009-01-16 15:53:34 -06:00
{
2011-07-26 23:09:28 +02:00
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mSpellLearnSpells . clear (); // need for reload case
2009-10-17 15:51:44 -07:00
2010-01-01 14:19:29 -06:00
// 0 1 2
2010-09-11 21:10:54 +02:00
QueryResult result = WorldDatabase . Query ( "SELECT entry, SpellID, Active FROM spell_learn_spell" );
2010-01-01 14:19:29 -06:00
if ( ! result )
2008-11-17 22:07:21 -06:00
{
2010-12-23 23:25:44 +01:00
sLog -> outString ( ">> Loaded 0 spell learn spells" );
sLog -> outString ();
sLog -> outErrorDb ( "`spell_learn_spell` table is empty!" );
2008-11-17 22:07:21 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-15 16:26:00 -05:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2008-11-17 22:07:21 -06:00
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2010-01-01 14:19:29 -06:00
uint32 spell_id = fields [ 0 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2009-05-15 16:26:00 -05:00
SpellLearnSpellNode node ;
node . spell = fields [ 1 ]. GetUInt32 ();
node . active = fields [ 2 ]. GetBool ();
node . autoLearned = false ;
2009-10-17 15:51:44 -07:00
2011-08-04 13:16:09 +02:00
if ( ! GetSpellInfo ( spell_id ))
2009-05-15 16:26:00 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Spell %u listed in `spell_learn_spell` does not exist" , spell_id );
2009-05-15 16:26:00 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2011-08-04 13:16:09 +02:00
if ( ! GetSpellInfo ( node . spell ))
2009-05-15 16:26:00 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Spell %u listed in `spell_learn_spell` learning not existed spell %u" , spell_id , node . spell );
2009-07-01 18:07:57 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2010-01-01 14:19:29 -06:00
if ( GetTalentSpellCost ( node . spell ))
2009-07-01 18:07:57 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped" , spell_id , node . spell );
2009-05-15 16:26:00 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
mSpellLearnSpells . insert ( SpellLearnSpellMap :: value_type ( spell_id , node ));
2009-10-17 15:51:44 -07:00
2009-05-15 16:26:00 -05:00
++ count ;
2010-01-01 14:19:29 -06:00
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2009-05-15 16:26:00 -05:00
// search auto-learned spells and add its to map also for use in unlearn spells/talents
uint32 dbc_count = 0 ;
2011-08-04 13:16:09 +02:00
for ( uint32 spell = 0 ; spell < GetSpellInfoStoreSize (); ++ spell )
2009-05-15 16:26:00 -05:00
{
2011-08-04 13:16:09 +02:00
SpellInfo const * entry = GetSpellInfo ( spell );
2009-10-17 15:51:44 -07:00
2010-01-01 14:19:29 -06:00
if ( ! entry )
2009-05-15 16:26:00 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-01-01 14:19:29 -06:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
if ( entry -> Effects [ i ]. Effect == SPELL_EFFECT_LEARN_SPELL )
2009-05-15 16:26:00 -05:00
{
SpellLearnSpellNode dbc_node ;
2011-07-26 23:09:28 +02:00
dbc_node . spell = entry -> Effects [ i ]. TriggerSpell ;
2010-01-01 14:19:29 -06:00
dbc_node . active = true ; // all dbc based learned spells is active (show in spell book or hide by client itself)
2009-10-17 15:51:44 -07:00
2009-05-15 16:26:00 -05:00
// ignore learning not existed spells (broken/outdated/or generic learnig spell 483
2011-08-04 13:16:09 +02:00
if ( ! GetSpellInfo ( dbc_node . spell ))
2009-05-15 16:26:00 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-05-15 16:26:00 -05:00
// talent or passive spells or skill-step spells auto-casted and not need dependent learning,
2011-06-28 13:53:48 +02:00
// pet teaching spells must not be dependent learning (casted)
2009-05-15 16:26:00 -05:00
// other required explicit dependent learning
2011-07-27 12:35:59 +02:00
dbc_node . autoLearned = entry -> Effects [ i ]. TargetA . GetTarget () == TARGET_UNIT_PET || GetTalentSpellCost ( spell ) > 0 || entry -> IsPassive () || entry -> HasEffect ( SPELL_EFFECT_SKILL_STEP );
2009-10-17 15:51:44 -07:00
2009-08-27 20:27:55 -05:00
SpellLearnSpellMapBounds db_node_bounds = GetSpellLearnSpellMapBounds ( spell );
2009-10-17 15:51:44 -07:00
2009-05-15 16:26:00 -05:00
bool found = false ;
2009-10-17 16:20:24 -07:00
for ( SpellLearnSpellMap :: const_iterator itr = db_node_bounds . first ; itr != db_node_bounds . second ; ++ itr )
2009-05-15 16:26:00 -05:00
{
2010-01-01 14:19:29 -06:00
if ( itr -> second . spell == dbc_node . spell )
2009-05-15 16:26:00 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Spell %u auto-learn spell %u in spell.dbc then the record in `spell_learn_spell` is redundant, please fix DB." ,
2011-04-29 20:47:02 +02:00
spell , dbc_node . spell );
2009-05-15 16:26:00 -05:00
found = true ;
break ;
}
}
2009-10-17 15:51:44 -07:00
2010-01-01 14:19:29 -06:00
if ( ! found ) // add new spell-spell pair if not found
2009-05-15 16:26:00 -05:00
{
2011-04-29 20:47:02 +02:00
mSpellLearnSpells . insert ( SpellLearnSpellMap :: value_type ( spell , dbc_node ));
2009-05-15 16:26:00 -05:00
++ dbc_count ;
}
}
}
2008-12-22 02:11:11 +01:00
}
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sLog -> outString ( ">> Loaded %u spell learn spells + %u found in DBC in %u ms" , count , dbc_count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2009-05-15 16:26:00 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellTargetPositions ()
2009-05-15 16:26:00 -05:00
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mSpellTargetPositions . clear (); // need for reload case
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// 0 1 2 3 4 5
QueryResult result = WorldDatabase . Query ( "SELECT id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM spell_target_position" );
2009-11-19 03:53:49 -08:00
if ( ! result )
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded 0 spell target coordinates. DB table `spell_target_position` is empty." );
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2009-05-15 16:26:00 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-12-19 17:06:33 +01:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2009-05-15 16:26:00 -05:00
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 Spell_ID = fields [ 0 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellTargetPosition st ;
st . target_mapId = fields [ 1 ]. GetUInt32 ();
st . target_X = fields [ 2 ]. GetFloat ();
st . target_Y = fields [ 3 ]. GetFloat ();
st . target_Z = fields [ 4 ]. GetFloat ();
st . target_Orientation = fields [ 5 ]. GetFloat ();
MapEntry const * mapEntry = sMapStore . LookupEntry ( st . target_mapId );
if ( ! mapEntry )
2008-12-22 02:11:11 +01:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell (ID:%u) target map (ID: %u) does not exist in `Map.dbc`." , Spell_ID , st . target_mapId );
continue ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( st . target_X == 0 && st . target_Y == 0 && st . target_Z == 0 )
{
sLog -> outErrorDb ( "Spell (ID:%u) target coordinates not provided." , Spell_ID );
continue ;
}
2011-08-04 13:16:09 +02:00
SpellInfo const * spellInfo = GetSpellInfo ( Spell_ID );
2011-07-26 23:09:28 +02:00
if ( ! spellInfo )
{
sLog -> outErrorDb ( "Spell (ID:%u) listed in `spell_target_position` does not exist." , Spell_ID );
continue ;
}
bool found = false ;
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
{
2011-08-16 19:44:18 +02:00
if ( spellInfo -> Effects [ i ]. TargetA . GetTarget () == TARGET_DEST_DB || spellInfo -> Effects [ i ]. TargetB . GetTarget () == TARGET_DEST_DB )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
// additional requirements
if ( spellInfo -> Effects [ i ]. Effect == SPELL_EFFECT_BIND && spellInfo -> Effects [ i ]. MiscValue )
{
uint32 area_id = sMapMgr -> GetAreaId ( st . target_mapId , st . target_X , st . target_Y , st . target_Z );
if ( area_id != uint32 ( spellInfo -> Effects [ i ]. MiscValue ))
{
sLog -> outErrorDb ( "Spell (Id: %u) listed in `spell_target_position` expected point to zone %u bit point to zone %u." , Spell_ID , spellInfo -> Effects [ i ]. MiscValue , area_id );
break ;
}
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
found = true ;
break ;
}
}
if ( ! found )
{
2011-08-16 19:44:18 +02:00
sLog -> outErrorDb ( "Spell (Id: %u) listed in `spell_target_position` does not have target TARGET_DEST_DB (17)." , Spell_ID );
2011-07-26 23:09:28 +02:00
continue ;
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mSpellTargetPositions [ Spell_ID ] = st ;
2009-05-15 16:26:00 -05:00
++ count ;
2011-07-26 23:09:28 +02:00
2009-11-19 03:53:49 -08:00
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
/*
// Check all spells
for (uint32 i = 1; i < GetSpellInfoStoreSize; ++i)
{
SpellInfo const* spellInfo = GetSpellInfo(i);
if (!spellInfo)
continue;
bool found = false;
for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
{
switch (spellInfo->Effects[j].TargetA)
{
2011-08-16 19:44:18 +02:00
case TARGET_DEST_DB:
2011-07-26 23:09:28 +02:00
found = true;
break;
}
if (found)
break;
switch (spellInfo->Effects[j].TargetB)
{
2011-08-16 19:44:18 +02:00
case TARGET_DEST_DB:
2011-07-26 23:09:28 +02:00
found = true;
break;
}
if (found)
break;
}
if (found)
{
if (!sSpellMgr->GetSpellTargetPosition(i))
sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell (ID: %u) does not have record in `spell_target_position`", i);
}
}*/
sLog -> outString ( ">> Loaded %u spell teleport coordinates in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellGroups ()
2008-11-17 22:07:21 -06:00
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2011-07-26 23:09:28 +02:00
mSpellSpellGroup . clear (); // need for reload case
mSpellGroupSpell . clear ();
2009-10-17 15:51:44 -07:00
2009-05-15 16:36:59 -05:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// 0 1
QueryResult result = WorldDatabase . Query ( "SELECT id, spell_id FROM spell_group" );
if ( ! result )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
sLog -> outString ();
sLog -> outString ( ">> Loaded %u spell group definitions" , count );
return ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
std :: set < uint32 > groups ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 group_id = fields [ 0 ]. GetUInt32 ();
if ( group_id <= SPELL_GROUP_DB_RANGE_MIN && group_id >= SPELL_GROUP_CORE_RANGE_MAX )
{
sLog -> outErrorDb ( "SpellGroup id %u listed in `spell_groups` is in core range, but is not defined in core!" , group_id );
continue ;
2008-11-17 22:07:21 -06:00
}
2011-07-26 23:09:28 +02:00
int32 spell_id = fields [ 1 ]. GetInt32 ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
groups . insert ( std :: set < uint32 >:: value_type ( group_id ));
mSpellGroupSpell . insert ( SpellGroupSpellMap :: value_type (( SpellGroup ) group_id , spell_id ));
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
} while ( result -> NextRow ());
for ( SpellGroupSpellMap :: iterator itr = mSpellGroupSpell . begin (); itr != mSpellGroupSpell . end () ;)
2009-05-24 12:16:12 -05:00
{
2011-07-26 23:09:28 +02:00
if ( itr -> second < 0 )
2009-05-24 12:16:12 -05:00
{
2011-07-26 23:09:28 +02:00
if ( groups . find ( abs ( itr -> second )) == groups . end ())
{
sLog -> outErrorDb ( "SpellGroup id %u listed in `spell_groups` does not exist" , abs ( itr -> second ));
mSpellGroupSpell . erase ( itr ++ );
}
else
++ itr ;
2009-05-24 12:16:12 -05:00
}
2011-07-26 23:09:28 +02:00
else
2009-05-24 12:16:12 -05:00
{
2011-08-04 13:16:09 +02:00
SpellInfo const * spellInfo = GetSpellInfo ( itr -> second );
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( ! spellInfo )
2009-05-24 12:16:12 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_group` does not exist" , itr -> second );
mSpellGroupSpell . erase ( itr ++ );
2009-05-24 12:16:12 -05:00
}
2011-07-26 23:09:28 +02:00
else if ( spellInfo -> GetRank () > 1 )
{
sLog -> outErrorDb ( "Spell %u listed in `spell_group` is not first rank of spell" , itr -> second );
mSpellGroupSpell . erase ( itr ++ );
}
else
++ itr ;
2009-05-24 12:16:12 -05:00
}
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
for ( std :: set < uint32 >:: iterator groupItr = groups . begin () ; groupItr != groups . end () ; ++ groupItr )
2009-05-24 12:16:12 -05:00
{
2011-07-26 23:09:28 +02:00
std :: set < uint32 > spells ;
GetSetOfSpellsInSpellGroup ( SpellGroup ( * groupItr ), spells );
for ( std :: set < uint32 >:: iterator spellItr = spells . begin () ; spellItr != spells . end () ; ++ spellItr )
2009-05-24 12:16:12 -05:00
{
2011-07-26 23:09:28 +02:00
++ count ;
mSpellSpellGroup . insert ( SpellSpellGroupMap :: value_type ( * spellItr , SpellGroup ( * groupItr )));
2009-05-24 12:16:12 -05:00
}
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u spell group definitions in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2009-05-24 12:16:12 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellGroupStackRules ()
2009-05-24 12:16:12 -05:00
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2011-07-26 23:09:28 +02:00
mSpellGroupStack . clear (); // need for reload case
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// 0 1
QueryResult result = WorldDatabase . Query ( "SELECT group_id, stack_rule FROM spell_group_stack_rules" );
if ( ! result )
2009-05-24 12:16:12 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded 0 spell group stack rules" );
sLog -> outString ();
return ;
}
2010-01-01 14:19:29 -06:00
2011-07-26 23:09:28 +02:00
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 group_id = fields [ 0 ]. GetUInt32 ();
uint8 stack_rule = fields [ 1 ]. GetUInt32 ();
if ( stack_rule >= SPELL_GROUP_STACK_RULE_MAX )
{
sLog -> outErrorDb ( "SpellGroupStackRule %u listed in `spell_group_stack_rules` does not exist" , stack_rule );
2009-05-24 12:16:12 -05:00
continue ;
2011-07-26 23:09:28 +02:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellGroupSpellMapBounds spellGroup = GetSpellGroupSpellMapBounds (( SpellGroup ) group_id );
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( spellGroup . first == spellGroup . second )
2009-05-24 12:16:12 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "SpellGroup id %u listed in `spell_group_stack_rules` does not exist" , group_id );
continue ;
2009-05-24 12:16:12 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mSpellGroupStack [( SpellGroup ) group_id ] = ( SpellGroupStackRule ) stack_rule ;
++ count ;
} while ( result -> NextRow ());
sLog -> outString ( ">> Loaded %u spell group stack rules in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2011-07-26 23:09:28 +02:00
}
2010-12-19 17:06:33 +01:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellProcEvents ()
{
uint32 oldMSTime = getMSTime ();
2010-12-19 17:06:33 +01:00
2011-07-26 23:09:28 +02:00
mSpellProcEventMap . clear (); // need for reload case
uint32 count = 0 ;
// 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 )
2009-05-24 12:16:12 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u spell proc event conditions" , count );
sLog -> outString ();
return ;
}
2010-01-01 14:19:29 -06:00
2011-07-26 23:09:28 +02:00
uint32 customProc = 0 ;
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 entry = fields [ 0 ]. GetUInt32 ();
2011-08-04 13:16:09 +02:00
SpellInfo const * spell = GetSpellInfo ( entry );
2011-07-26 23:09:28 +02:00
if ( ! spell )
2009-05-24 12:16:12 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_proc_event` does not exist" , entry );
continue ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellProcEventEntry spe ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
spe . schoolMask = fields [ 1 ]. GetUInt32 ();
spe . spellFamilyName = fields [ 2 ]. GetUInt32 ();
spe . spellFamilyMask [ 0 ] = fields [ 3 ]. GetUInt32 ();
spe . spellFamilyMask [ 1 ] = fields [ 4 ]. GetUInt32 ();
spe . spellFamilyMask [ 2 ] = 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 ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mSpellProcEventMap [ entry ] = spe ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( spell -> ProcFlags == 0 )
{
if ( spe . procFlags == 0 )
{
sLog -> outErrorDb ( "Spell %u listed in `spell_proc_event` probally not triggered spell" , entry );
continue ;
2009-05-24 12:16:12 -05:00
}
2011-07-26 23:09:28 +02:00
customProc ++ ;
2009-05-24 12:16:12 -05:00
}
2011-07-26 23:09:28 +02:00
++ count ;
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( customProc )
sLog -> outString ( ">> Loaded %u extra and %u custom spell proc event conditions in %u ms" , count , customProc , GetMSTimeDiffToNow ( oldMSTime ));
else
sLog -> outString ( ">> Loaded %u extra spell proc event conditions in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2009-05-24 12:16:12 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellProcs ()
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mSpellProcMap . clear (); // need for reload case
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 count = 0 ;
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
QueryResult result = WorldDatabase . Query ( "SELECT spellId, schoolMask, spellFamilyName, spellFamilyMask0, spellFamilyMask1, spellFamilyMask2, typeMask, spellTypeMask, spellPhaseMask, hitMask, attributesMask, ratePerMinute, chance, cooldown, charges FROM spell_proc" );
if ( ! result )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u spell proc conditions and data" , count );
sLog -> outString ();
return ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
do
{
Field * fields = result -> Fetch ();
2010-02-14 19:13:14 -07:00
2011-07-26 23:09:28 +02:00
int32 spellId = fields [ 0 ]. GetInt32 ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
bool allRanks = false ;
if ( spellId <= 0 )
{
allRanks = true ;
spellId = - spellId ;
}
2011-08-04 13:16:09 +02:00
SpellInfo const * spellEntry = GetSpellInfo ( spellId );
2011-07-26 23:09:28 +02:00
if ( ! spellEntry )
{
sLog -> outErrorDb ( "Spell %u listed in `spell_proc` does not exist" , spellId );
continue ;
}
if ( allRanks )
{
2011-08-04 13:16:09 +02:00
if ( GetFirstSpellInChain ( spellId ) != uint32 ( spellId ))
2011-07-26 23:09:28 +02:00
{
sLog -> outErrorDb ( "Spell %u listed in `spell_proc` is not first rank of spell." , fields [ 0 ]. GetInt32 ());
continue ;
2009-05-15 16:26:00 -05:00
}
2011-07-26 23:09:28 +02:00
}
SpellProcEntry baseProcEntry ;
baseProcEntry . schoolMask = fields [ 1 ]. GetUInt32 ();
baseProcEntry . spellFamilyName = fields [ 2 ]. GetUInt32 ();
baseProcEntry . spellFamilyMask [ 0 ] = fields [ 3 ]. GetUInt32 ();
baseProcEntry . spellFamilyMask [ 1 ] = fields [ 4 ]. GetUInt32 ();
baseProcEntry . spellFamilyMask [ 2 ] = fields [ 5 ]. GetUInt32 ();
baseProcEntry . typeMask = fields [ 6 ]. GetUInt32 ();
baseProcEntry . spellTypeMask = fields [ 7 ]. GetUInt32 ();
baseProcEntry . spellPhaseMask = fields [ 8 ]. GetUInt32 ();
baseProcEntry . hitMask = fields [ 9 ]. GetUInt32 ();
baseProcEntry . attributesMask = fields [ 10 ]. GetUInt32 ();
baseProcEntry . ratePerMinute = fields [ 11 ]. GetFloat ();
baseProcEntry . chance = fields [ 12 ]. GetFloat ();
float cooldown = fields [ 13 ]. GetFloat ();
baseProcEntry . cooldown = uint32 ( cooldown );
baseProcEntry . charges = fields [ 14 ]. GetUInt32 ();
2011-09-29 12:43:05 +02:00
while ( true )
2011-07-26 23:09:28 +02:00
{
if ( mSpellProcMap . find ( spellId ) != mSpellProcMap . end ())
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_proc` has duplicate entry in the table" , spellId );
2009-05-15 16:26:00 -05:00
break ;
}
2011-07-26 23:09:28 +02:00
SpellProcEntry procEntry = SpellProcEntry ( baseProcEntry );
// take defaults from dbcs
if ( ! procEntry . typeMask )
procEntry . typeMask = spellEntry -> ProcFlags ;
if ( ! procEntry . charges )
procEntry . charges = spellEntry -> ProcCharges ;
if ( ! procEntry . chance && ! procEntry . ratePerMinute )
procEntry . chance = float ( spellEntry -> ProcChance );
// validate data
if ( procEntry . schoolMask & ~ SPELL_SCHOOL_MASK_ALL )
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u has wrong `schoolMask` set: %u" , spellId , procEntry . schoolMask );
if ( procEntry . spellFamilyName && ( procEntry . spellFamilyName < 3 || procEntry . spellFamilyName > 17 || procEntry . spellFamilyName == 14 || procEntry . spellFamilyName == 16 ))
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u has wrong `spellFamilyName` set: %u" , spellId , procEntry . spellFamilyName );
if ( procEntry . chance < 0 )
{
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u has negative value in `chance` field" , spellId );
procEntry . chance = 0 ;
}
if ( procEntry . ratePerMinute < 0 )
{
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u has negative value in `ratePerMinute` field" , spellId );
procEntry . ratePerMinute = 0 ;
}
if ( cooldown < 0 )
{
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u has negative value in `cooldown` field" , spellId );
procEntry . cooldown = 0 ;
}
if ( procEntry . chance == 0 && procEntry . ratePerMinute == 0 )
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u doesn't have `chance` and `ratePerMinute` values defined, proc will not be triggered" , spellId );
if ( procEntry . charges > 99 )
{
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u has too big value in `charges` field" , spellId );
procEntry . charges = 99 ;
}
if ( ! procEntry . typeMask )
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u doesn't have `typeMask` value defined, proc will not be triggered" , spellId );
if ( procEntry . spellTypeMask & ~ PROC_SPELL_PHASE_MASK_ALL )
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u has wrong `spellTypeMask` set: %u" , spellId , procEntry . spellTypeMask );
if ( procEntry . spellTypeMask && ! ( procEntry . typeMask & ( SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK )))
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u has `spellTypeMask` value defined, but it won't be used for defined `typeMask` value" , spellId );
if ( ! procEntry . spellPhaseMask && procEntry . typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK )
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u doesn't have `spellPhaseMask` value defined, but it's required for defined `typeMask` value, proc will not be triggered" , spellId );
if ( procEntry . spellPhaseMask & ~ PROC_SPELL_PHASE_MASK_ALL )
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u has wrong `spellPhaseMask` set: %u" , spellId , procEntry . spellPhaseMask );
if ( procEntry . spellPhaseMask && ! ( procEntry . typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK ))
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u has `spellPhaseMask` value defined, but it won't be used for defined `typeMask` value" , spellId );
if ( procEntry . hitMask & ~ PROC_HIT_MASK_ALL )
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u has wrong `hitMask` set: %u" , spellId , procEntry . hitMask );
if ( procEntry . hitMask && ! ( procEntry . typeMask & TAKEN_HIT_PROC_FLAG_MASK || ( procEntry . typeMask & DONE_HIT_PROC_FLAG_MASK && ( ! procEntry . spellPhaseMask || procEntry . spellPhaseMask & ( PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH )))))
sLog -> outErrorDb ( "`spell_proc` table entry for spellId %u has `hitMask` value defined, but it won't be used for defined `typeMask` and `spellPhaseMask` values" , spellId );
mSpellProcMap [ spellId ] = procEntry ;
if ( allRanks )
{
2011-08-04 13:16:09 +02:00
spellId = GetNextSpellInChain ( spellId );
spellEntry = GetSpellInfo ( spellId );
2011-07-26 23:09:28 +02:00
}
else
break ;
2009-05-15 16:26:00 -05:00
}
2011-07-26 23:09:28 +02:00
++ count ;
} while ( result -> NextRow ());
sLog -> outString ( ">> Loaded %u spell proc conditions and data in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
}
void SpellMgr :: LoadSpellBonusess ()
{
uint32 oldMSTime = getMSTime ();
mSpellBonusMap . clear (); // need for reload case
uint32 count = 0 ;
// 0 1 2 3 4
QueryResult result = WorldDatabase . Query ( "SELECT entry, direct_bonus, dot_bonus, ap_bonus, ap_dot_bonus FROM spell_bonus_data" );
if ( ! result )
{
sLog -> outString ( ">> Loaded %u spell bonus data" , count );
sLog -> outString ();
return ;
2009-05-15 16:26:00 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
do
2009-05-15 16:26:00 -05:00
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2011-07-26 23:09:28 +02:00
uint32 entry = fields [ 0 ]. GetUInt32 ();
2011-08-04 13:16:09 +02:00
SpellInfo const * spell = GetSpellInfo ( entry );
2011-07-26 23:09:28 +02:00
if ( ! spell )
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_bonus_data` does not exist" , entry );
continue ;
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellBonusEntry & sbe = mSpellBonusMap [ entry ];
sbe . direct_damage = fields [ 1 ]. GetFloat ();
sbe . dot_damage = fields [ 2 ]. GetFloat ();
sbe . ap_bonus = fields [ 3 ]. GetFloat ();
sbe . ap_dot_bonus = fields [ 4 ]. GetFloat ();
++ count ;
} while ( result -> NextRow ());
sLog -> outString ( ">> Loaded %u extra spell bonus data in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellThreats ()
2008-11-17 22:07:21 -06:00
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2011-07-26 23:09:28 +02:00
mSpellThreatMap . clear (); // need for reload case
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2011-08-21 12:00:36 +02:00
// 0 1 2 3
QueryResult result = WorldDatabase . Query ( "SELECT entry, flatMod, pctMod, apPctMod FROM spell_threat" );
2009-11-19 03:53:49 -08:00
if ( ! result )
2008-11-17 22:07:21 -06:00
{
2011-08-04 13:16:09 +02:00
sLog -> outString ( ">> Loaded 0 aggro generating spells" );
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2008-11-17 22:07:21 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-11-17 22:07:21 -06:00
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 entry = fields [ 0 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2011-08-04 13:16:09 +02:00
if ( ! GetSpellInfo ( entry ))
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_threat` does not exist" , entry );
2008-11-17 22:07:21 -06:00
continue ;
}
2009-10-17 15:51:44 -07:00
2011-08-21 12:00:36 +02:00
SpellThreatEntry ste ;
ste . flatMod = fields [ 1 ]. GetInt16 ();
ste . pctMod = fields [ 2 ]. GetFloat ();
ste . apPctMod = fields [ 3 ]. GetFloat ();
2009-10-17 15:51:44 -07:00
2011-08-21 12:00:36 +02:00
mSpellThreatMap [ entry ] = ste ;
2011-09-13 14:15:35 +02:00
++ count ;
2011-07-26 23:09:28 +02:00
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2011-08-21 12:00:36 +02:00
sLog -> outString ( ">> Loaded %u SpellThreatEntries in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
2011-07-26 23:09:28 +02:00
sLog -> outString ();
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSkillLineAbilityMap ()
{
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mSkillLineAbilityMap . clear ();
uint32 count = 0 ;
2011-09-13 14:15:35 +02:00
for ( uint32 i = 0 ; i < sSkillLineAbilityStore . GetNumRows (); ++ i )
2011-07-26 23:09:28 +02:00
{
SkillLineAbilityEntry const * SkillInfo = sSkillLineAbilityStore . LookupEntry ( i );
if ( ! SkillInfo )
2008-11-17 22:07:21 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mSkillLineAbilityMap . insert ( SkillLineAbilityMap :: value_type ( SkillInfo -> spellId , SkillInfo ));
++ count ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u SkillLineAbility MultiMap Data in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellPetAuras ()
{
uint32 oldMSTime = getMSTime ();
mSpellPetAuraMap . clear (); // need for reload case
// 0 1 2 3
QueryResult result = WorldDatabase . Query ( "SELECT spell, effectId, pet, aura FROM spell_pet_auras" );
if ( ! result )
{
sLog -> outString ( ">> Loaded 0 spell pet auras. DB table `spell_pet_auras` is empty." );
sLog -> outString ();
return ;
}
uint32 count = 0 ;
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2011-07-26 23:09:28 +02:00
uint32 spell = fields [ 0 ]. GetUInt32 ();
uint8 eff = fields [ 1 ]. GetUInt8 ();
uint32 pet = fields [ 2 ]. GetUInt32 ();
uint32 aura = fields [ 3 ]. GetUInt32 ();
SpellPetAuraMap :: iterator itr = mSpellPetAuraMap . find (( spell << 8 ) + eff );
if ( itr != mSpellPetAuraMap . end ())
itr -> second . AddAura ( pet , aura );
else
2009-05-15 16:26:00 -05:00
{
2011-08-04 13:16:09 +02:00
SpellInfo const * spellInfo = GetSpellInfo ( spell );
2009-11-19 03:53:49 -08:00
if ( ! spellInfo )
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_pet_auras` does not exist" , spell );
2009-05-15 16:26:00 -05:00
continue ;
}
2011-07-26 23:09:28 +02:00
if ( spellInfo -> Effects [ eff ]. Effect != SPELL_EFFECT_DUMMY &&
( spellInfo -> Effects [ eff ]. Effect != SPELL_EFFECT_APPLY_AURA ||
spellInfo -> Effects [ eff ]. ApplyAuraName != SPELL_AURA_DUMMY ))
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outError ( "Spell %u listed in `spell_pet_auras` does not have dummy aura or dummy effect" , spell );
2009-05-15 16:26:00 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2011-08-04 13:16:09 +02:00
SpellInfo const * spellInfo2 = GetSpellInfo ( aura );
2011-07-26 23:09:28 +02:00
if ( ! spellInfo2 )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Aura %u listed in `spell_pet_auras` does not exist" , aura );
continue ;
2009-05-15 16:26:00 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-27 12:35:59 +02:00
PetAura pa ( pet , aura , spellInfo -> Effects [ eff ]. TargetA . GetTarget () == TARGET_UNIT_PET , spellInfo -> Effects [ eff ]. CalcValue ());
2011-07-26 23:09:28 +02:00
mSpellPetAuraMap [( spell << 8 ) + eff ] = pa ;
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2008-11-17 22:07:21 -06:00
++ count ;
2010-04-07 19:13:19 +02:00
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u spell pet auras in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// Fill custom data about enchancments
void SpellMgr :: LoadEnchantCustomAttr ()
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 size = sSpellItemEnchantmentStore . GetNumRows ();
mEnchantCustomAttr . resize ( size );
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
for ( uint32 i = 0 ; i < size ; ++ i )
mEnchantCustomAttr [ i ] = 0 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
for ( uint32 i = 0 ; i < GetSpellInfoStoreSize (); ++ i )
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
SpellInfo const * spellInfo = GetSpellInfo ( i );
if ( ! spellInfo )
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// TODO: find a better check
if ( ! ( spellInfo -> AttributesEx2 & SPELL_ATTR2_UNK13 ) || ! ( spellInfo -> Attributes & SPELL_ATTR0_NOT_SHAPESHIFT ))
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
for ( uint32 j = 0 ; j < MAX_SPELL_EFFECTS ; ++ j )
2009-09-23 00:45:47 -07:00
{
2011-07-26 23:09:28 +02:00
if ( spellInfo -> Effects [ j ]. Effect == SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY )
2009-09-23 00:45:47 -07:00
{
2011-07-26 23:09:28 +02:00
uint32 enchId = spellInfo -> Effects [ j ]. MiscValue ;
SpellItemEnchantmentEntry const * ench = sSpellItemEnchantmentStore . LookupEntry ( enchId );
if ( ! ench )
continue ;
mEnchantCustomAttr [ enchId ] = true ;
++ count ;
break ;
2009-09-23 00:45:47 -07:00
}
}
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u custom enchant attributes in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellEnchantProcData ()
2008-11-17 22:07:21 -06:00
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2011-07-26 23:09:28 +02:00
mSpellEnchantProcEventMap . clear (); // need for reload case
2009-10-17 15:51:44 -07:00
2008-11-17 22:07:21 -06:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// 0 1 2 3
QueryResult result = WorldDatabase . Query ( "SELECT entry, customChance, PPMChance, procEx FROM spell_enchant_proc_data" );
if ( ! result )
2011-06-17 22:35:05 +02:00
{
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u spell enchant proc event conditions" , count );
sLog -> outString ();
return ;
2011-06-17 22:35:05 +02:00
}
2011-07-26 23:09:28 +02:00
do
2008-11-17 22:07:21 -06:00
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 enchantId = fields [ 0 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellItemEnchantmentEntry const * ench = sSpellItemEnchantmentStore . LookupEntry ( enchantId );
if ( ! ench )
2011-05-15 18:55:38 +07:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Enchancment %u listed in `spell_enchant_proc_data` does not exist" , enchantId );
continue ;
2011-05-15 18:55:38 +07:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellEnchantProcEntry spe ;
2010-02-14 19:13:14 -07:00
2011-07-26 23:09:28 +02:00
spe . customChance = fields [ 1 ]. GetUInt32 ();
spe . PPMChance = fields [ 2 ]. GetFloat ();
spe . procEx = fields [ 3 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mSpellEnchantProcEventMap [ enchantId ] = spe ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
++ count ;
} while ( result -> NextRow ());
2010-12-27 22:27:11 +01:00
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u enchant proc data definitions in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2010-12-27 22:27:11 +01:00
}
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellLinked ()
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mSpellLinkedMap . clear (); // need for reload case
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// 0 1 2
QueryResult result = WorldDatabase . Query ( "SELECT spell_trigger, spell_effect, type FROM spell_linked_spell" );
if ( ! result )
{
sLog -> outString ( ">> Loaded 0 linked spells. DB table `spell_linked_spell` is empty." );
sLog -> outString ();
return ;
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
int32 trigger = fields [ 0 ]. GetInt32 ();
int32 effect = fields [ 1 ]. GetInt32 ();
int32 type = fields [ 2 ]. GetInt32 ();
2010-02-14 19:13:14 -07:00
2011-08-04 13:16:09 +02:00
SpellInfo const * spellInfo = GetSpellInfo ( abs ( trigger ));
2011-07-26 23:09:28 +02:00
if ( ! spellInfo )
2011-06-28 13:53:48 +02:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_linked_spell` does not exist" , abs ( trigger ));
continue ;
2011-06-28 13:53:48 +02:00
}
2011-08-04 13:16:09 +02:00
spellInfo = GetSpellInfo ( abs ( effect ));
2011-07-26 23:09:28 +02:00
if ( ! spellInfo )
2011-06-28 13:53:48 +02:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_linked_spell` does not exist" , abs ( effect ));
continue ;
}
2010-06-16 19:36:50 +02:00
2011-07-26 23:09:28 +02:00
if ( type ) //we will find a better way when more types are needed
{
if ( trigger > 0 )
trigger += SPELL_LINKED_MAX_SPELLS * type ;
else
trigger -= SPELL_LINKED_MAX_SPELLS * type ;
2011-06-28 13:53:48 +02:00
}
2011-07-26 23:09:28 +02:00
mSpellLinkedMap [ trigger ]. push_back ( effect );
2010-01-21 01:28:18 +01:00
2011-07-26 23:09:28 +02:00
++ count ;
} while ( result -> NextRow ());
sLog -> outString ( ">> Loaded %u linked spells in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadPetLevelupSpellMap ()
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
uint32 oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
mPetLevelupSpellMap . clear (); // need for reload case
2010-01-23 17:05:20 +01:00
2011-07-26 23:09:28 +02:00
uint32 count = 0 ;
uint32 family_count = 0 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
for ( uint32 i = 0 ; i < sCreatureFamilyStore . GetNumRows (); ++ i )
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
CreatureFamilyEntry const * creatureFamily = sCreatureFamilyStore . LookupEntry ( i );
if ( ! creatureFamily ) // not exist
continue ;
2009-10-17 16:20:24 -07:00
2011-07-26 23:09:28 +02:00
for ( uint8 j = 0 ; j < 2 ; ++ j )
2009-08-23 10:22:58 -05:00
{
2011-07-26 23:09:28 +02:00
if ( ! creatureFamily -> skillLine [ j ])
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
for ( uint32 k = 0 ; k < sSkillLineAbilityStore . GetNumRows (); ++ k )
{
SkillLineAbilityEntry const * skillLine = sSkillLineAbilityStore . LookupEntry ( k );
if ( ! skillLine )
continue ;
2011-02-27 03:53:24 +01:00
2011-07-26 23:09:28 +02:00
//if (skillLine->skillId != creatureFamily->skillLine[0] &&
// (!creatureFamily->skillLine[1] || skillLine->skillId != creatureFamily->skillLine[1]))
// continue;
2011-02-27 03:53:24 +01:00
2011-07-26 23:09:28 +02:00
if ( skillLine -> skillId != creatureFamily -> skillLine [ j ])
continue ;
2011-02-27 03:53:24 +01:00
2011-07-26 23:09:28 +02:00
if ( skillLine -> learnOnGetSkill != ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL )
continue ;
2011-02-27 03:53:24 +01:00
2011-08-04 13:16:09 +02:00
SpellInfo const * spell = GetSpellInfo ( skillLine -> spellId );
2011-07-26 23:09:28 +02:00
if ( ! spell ) // not exist or triggered or talent
continue ;
2011-02-27 03:53:24 +01:00
2011-07-26 23:09:28 +02:00
if ( ! spell -> SpellLevel )
continue ;
2011-02-27 03:53:24 +01:00
2011-07-26 23:09:28 +02:00
PetLevelupSpellSet & spellSet = mPetLevelupSpellMap [ creatureFamily -> ID ];
if ( spellSet . empty ())
++ family_count ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
spellSet . insert ( PetLevelupSpellSet :: value_type ( spell -> SpellLevel , spell -> Id ));
++ count ;
}
}
2009-08-23 10:22:58 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u pet levelup and default spells for %u families in %u ms" , count , family_count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2009-05-15 16:26:00 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
bool LoadPetDefaultSpells_helper ( CreatureTemplate const * cInfo , PetDefaultSpellsEntry & petDefSpells )
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
// skip empty list;
bool have_spell = false ;
for ( uint8 j = 0 ; j < MAX_CREATURE_SPELL_DATA_SLOT ; ++ j )
{
if ( petDefSpells . spellid [ j ])
{
have_spell = true ;
break ;
}
}
if ( ! have_spell )
2009-05-16 20:23:56 +02:00
return false ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// remove duplicates with levelupSpells if any
if ( PetLevelupSpellSet const * levelupSpells = cInfo -> family ? sSpellMgr -> GetPetLevelupSpellList ( cInfo -> family ) : NULL )
{
for ( uint8 j = 0 ; j < MAX_CREATURE_SPELL_DATA_SLOT ; ++ j )
{
if ( ! petDefSpells . spellid [ j ])
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
for ( PetLevelupSpellSet :: const_iterator itr = levelupSpells -> begin (); itr != levelupSpells -> end (); ++ itr )
{
if ( itr -> second == petDefSpells . spellid [ j ])
{
petDefSpells . spellid [ j ] = 0 ;
break ;
}
}
}
}
2010-07-26 19:27:28 +02:00
2011-07-26 23:09:28 +02:00
// skip empty list;
have_spell = false ;
for ( uint8 j = 0 ; j < MAX_CREATURE_SPELL_DATA_SLOT ; ++ j )
{
if ( petDefSpells . spellid [ j ])
{
have_spell = true ;
break ;
}
}
2010-07-26 19:27:28 +02:00
2011-07-26 23:09:28 +02:00
return have_spell ;
2010-07-26 19:27:28 +02:00
}
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadPetDefaultSpells ()
2010-07-26 19:27:28 +02:00
{
2011-07-26 23:09:28 +02:00
uint32 oldMSTime = getMSTime ();
2010-07-26 19:27:28 +02:00
2011-07-26 23:09:28 +02:00
mPetDefaultSpellsMap . clear ();
2010-07-26 19:27:28 +02:00
2011-07-26 23:09:28 +02:00
uint32 countCreature = 0 ;
uint32 countData = 0 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
CreatureTemplateContainer const * ctc = sObjectMgr -> GetCreatureTemplates ();
for ( CreatureTemplateContainer :: const_iterator itr = ctc -> begin (); itr != ctc -> end (); ++ itr )
{
2010-12-19 17:06:33 +01:00
2011-07-26 23:09:28 +02:00
if ( ! itr -> second . PetSpellDataId )
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// for creature with PetSpellDataId get default pet spells from dbc
CreatureSpellDataEntry const * spellDataEntry = sCreatureSpellDataStore . LookupEntry ( itr -> second . PetSpellDataId );
if ( ! spellDataEntry )
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
int32 petSpellsId = - int32 ( itr -> second . PetSpellDataId );
PetDefaultSpellsEntry petDefSpells ;
for ( uint8 j = 0 ; j < MAX_CREATURE_SPELL_DATA_SLOT ; ++ j )
petDefSpells . spellid [ j ] = spellDataEntry -> spellId [ j ];
if ( LoadPetDefaultSpells_helper ( & itr -> second , petDefSpells ))
{
mPetDefaultSpellsMap [ petSpellsId ] = petDefSpells ;
++ countData ;
}
2009-07-31 13:21:01 +02:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded addition spells for %u pet spell data entries in %u ms" , countData , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
sLog -> outString ( "Loading summonable creature templates..." );
oldMSTime = getMSTime ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// different summon spells
for ( uint32 i = 0 ; i < GetSpellInfoStoreSize (); ++ i )
{
2011-08-04 13:16:09 +02:00
SpellInfo const * spellEntry = GetSpellInfo ( i );
2011-07-26 23:09:28 +02:00
if ( ! spellEntry )
continue ;
for ( uint8 k = 0 ; k < MAX_SPELL_EFFECTS ; ++ k )
2009-07-31 13:21:01 +02:00
{
2011-07-26 23:09:28 +02:00
if ( spellEntry -> Effects [ k ]. Effect == SPELL_EFFECT_SUMMON || spellEntry -> Effects [ k ]. Effect == SPELL_EFFECT_SUMMON_PET )
{
uint32 creature_id = spellEntry -> Effects [ k ]. MiscValue ;
CreatureTemplate const * cInfo = sObjectMgr -> GetCreatureTemplate ( creature_id );
if ( ! cInfo )
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// already loaded
if ( cInfo -> PetSpellDataId )
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// for creature without PetSpellDataId get default pet spells from creature_template
int32 petSpellsId = cInfo -> Entry ;
if ( mPetDefaultSpellsMap . find ( cInfo -> Entry ) != mPetDefaultSpellsMap . end ())
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
PetDefaultSpellsEntry petDefSpells ;
for ( uint8 j = 0 ; j < MAX_CREATURE_SPELL_DATA_SLOT ; ++ j )
petDefSpells . spellid [ j ] = cInfo -> spells [ j ];
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( LoadPetDefaultSpells_helper ( cInfo , petDefSpells ))
{
mPetDefaultSpellsMap [ petSpellsId ] = petDefSpells ;
++ countCreature ;
}
}
}
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded %u summonable creature templates in %u ms" , countCreature , GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2009-07-31 13:21:01 +02:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellAreas ()
2009-05-15 16:26:00 -05:00
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2011-07-26 23:09:28 +02:00
mSpellAreaMap . clear (); // need for reload case
mSpellAreaForQuestMap . clear ();
mSpellAreaForActiveQuestMap . clear ();
mSpellAreaForQuestEndMap . clear ();
mSpellAreaForAuraMap . clear ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// 0 1 2 3 4 5 6 7 8
QueryResult result = WorldDatabase . Query ( "SELECT spell, area, quest_start, quest_start_active, quest_end, aura_spell, racemask, gender, autocast FROM spell_area" );
2009-10-17 15:51:44 -07:00
2010-01-01 14:19:29 -06:00
if ( ! result )
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loaded 0 spell area requirements. DB table `spell_area` is empty." );
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2009-05-15 16:26:00 -05:00
return ;
}
2011-07-26 23:09:28 +02:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2009-05-15 16:26:00 -05:00
do
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 spell = fields [ 0 ]. GetUInt32 ();
SpellArea spellArea ;
spellArea . spellId = spell ;
spellArea . areaId = fields [ 1 ]. GetUInt32 ();
spellArea . questStart = fields [ 2 ]. GetUInt32 ();
spellArea . questStartCanActive = fields [ 3 ]. GetBool ();
spellArea . questEnd = fields [ 4 ]. GetUInt32 ();
spellArea . auraSpell = fields [ 5 ]. GetInt32 ();
spellArea . raceMask = fields [ 6 ]. GetUInt32 ();
spellArea . gender = Gender ( fields [ 7 ]. GetUInt8 ());
spellArea . autocast = fields [ 8 ]. GetBool ();
2011-08-04 13:16:09 +02:00
if ( SpellInfo const * spellInfo = GetSpellInfo ( spell ))
2010-01-30 19:25:04 +01:00
{
2011-07-26 23:09:28 +02:00
if ( spellArea . autocast )
const_cast < SpellInfo *> ( spellInfo ) -> Attributes |= SPELL_ATTR0_CANT_CANCEL ;
2010-01-30 19:25:04 +01:00
}
2011-07-26 23:09:28 +02:00
else
2010-01-30 19:25:04 +01:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_area` does not exist" , spell );
2010-01-30 19:25:04 +01:00
continue ;
}
2009-10-17 15:51:44 -07:00
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
bool ok = true ;
SpellAreaMapBounds sa_bounds = GetSpellAreaMapBounds ( spellArea . spellId );
for ( SpellAreaMap :: const_iterator itr = sa_bounds . first ; itr != sa_bounds . second ; ++ itr )
{
if ( spellArea . spellId != itr -> second . spellId )
continue ;
if ( spellArea . areaId != itr -> second . areaId )
continue ;
if ( spellArea . questStart != itr -> second . questStart )
continue ;
if ( spellArea . auraSpell != itr -> second . auraSpell )
continue ;
if (( spellArea . raceMask & itr -> second . raceMask ) == 0 )
continue ;
if ( spellArea . gender != itr -> second . gender )
continue ;
2010-01-29 17:54:29 +01:00
2011-07-26 23:09:28 +02:00
// duplicate by requirements
ok = false ;
break ;
}
2010-01-29 17:54:29 +01:00
2011-07-26 23:09:28 +02:00
if ( ! ok )
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_area` already listed with similar requirements." , spell );
continue ;
2009-05-15 16:26:00 -05:00
}
2010-01-29 17:54:29 +01:00
}
2011-07-26 23:09:28 +02:00
if ( spellArea . areaId && ! GetAreaEntryByAreaID ( spellArea . areaId ))
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_area` have wrong area (%u) requirement" , spell , spellArea . areaId );
2009-05-15 16:26:00 -05:00
continue ;
}
2011-07-26 23:09:28 +02:00
if ( spellArea . questStart && ! sObjectMgr -> GetQuestTemplate ( spellArea . questStart ))
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_area` have wrong start quest (%u) requirement" , spell , spellArea . questStart );
2010-01-29 17:54:29 +01:00
continue ;
2009-05-15 16:26:00 -05:00
}
2011-07-26 23:09:28 +02:00
if ( spellArea . questEnd )
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
if ( ! sObjectMgr -> GetQuestTemplate ( spellArea . questEnd ))
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_area` have wrong end quest (%u) requirement" , spell , spellArea . questEnd );
continue ;
2010-01-29 17:54:29 +01:00
}
2011-07-26 23:09:28 +02:00
if ( spellArea . questEnd == spellArea . questStart && ! spellArea . questStartCanActive )
2010-01-29 17:54:29 +01:00
{
2011-07-26 23:09:28 +02:00
sLog -> outErrorDb ( "Spell %u listed in `spell_area` have quest (%u) requirement for start and end in same time" , spell , spellArea . questEnd );
continue ;
2009-05-15 16:26:00 -05:00
}
}
2011-07-26 23:09:28 +02:00
if ( spellArea . auraSpell )
{
2011-08-04 13:16:09 +02:00
SpellInfo const * spellInfo = GetSpellInfo ( abs ( spellArea . auraSpell ));
2011-07-26 23:09:28 +02:00
if ( ! spellInfo )
{
sLog -> outErrorDb ( "Spell %u listed in `spell_area` have wrong aura spell (%u) requirement" , spell , abs ( spellArea . auraSpell ));
continue ;
}
if ( uint32 ( abs ( spellArea . auraSpell )) == spellArea . spellId )
{
sLog -> outErrorDb ( "Spell %u listed in `spell_area` have aura spell (%u) requirement for itself" , spell , abs ( spellArea . auraSpell ));
continue ;
}
// not allow autocast chains by auraSpell field (but allow use as alternative if not present)
if ( spellArea . autocast && spellArea . auraSpell > 0 )
{
bool chain = false ;
SpellAreaForAuraMapBounds saBound = GetSpellAreaForAuraMapBounds ( spellArea . spellId );
for ( SpellAreaForAuraMap :: const_iterator itr = saBound . first ; itr != saBound . second ; ++ itr )
{
if ( itr -> second -> autocast && itr -> second -> auraSpell > 0 )
{
chain = true ;
break ;
}
}
if ( chain )
{
sLog -> outErrorDb ( "Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura" , spell , spellArea . auraSpell );
continue ;
}
SpellAreaMapBounds saBound2 = GetSpellAreaMapBounds ( spellArea . auraSpell );
for ( SpellAreaMap :: const_iterator itr2 = saBound2 . first ; itr2 != saBound2 . second ; ++ itr2 )
{
if ( itr2 -> second . autocast && itr2 -> second . auraSpell > 0 )
{
chain = true ;
break ;
}
}
if ( chain )
{
sLog -> outErrorDb ( "Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura" , spell , spellArea . auraSpell );
continue ;
}
}
}
if ( spellArea . raceMask && ( spellArea . raceMask & RACEMASK_ALL_PLAYABLE ) == 0 )
{
sLog -> outErrorDb ( "Spell %u listed in `spell_area` have wrong race mask (%u) requirement" , spell , spellArea . raceMask );
2009-05-15 16:26:00 -05:00
continue ;
2011-07-26 23:09:28 +02:00
}
if ( spellArea . gender != GENDER_NONE && spellArea . gender != GENDER_FEMALE && spellArea . gender != GENDER_MALE )
{
sLog -> outErrorDb ( "Spell %u listed in `spell_area` have wrong gender (%u) requirement" , spell , spellArea . gender );
continue ;
}
SpellArea const * sa = & mSpellAreaMap . insert ( SpellAreaMap :: value_type ( spell , spellArea )) -> second ;
// for search by current zone/subzone at zone/subzone change
if ( spellArea . areaId )
mSpellAreaForAreaMap . insert ( SpellAreaForAreaMap :: value_type ( spellArea . areaId , sa ));
// for search at quest start/reward
if ( spellArea . questStart )
2010-01-29 17:54:29 +01:00
{
2011-07-26 23:09:28 +02:00
if ( spellArea . questStartCanActive )
mSpellAreaForActiveQuestMap . insert ( SpellAreaForQuestMap :: value_type ( spellArea . questStart , sa ));
2010-01-29 17:54:29 +01:00
else
2011-07-26 23:09:28 +02:00
mSpellAreaForQuestMap . insert ( SpellAreaForQuestMap :: value_type ( spellArea . questStart , sa ));
2009-05-15 16:26:00 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
// for search at quest start/reward
if ( spellArea . questEnd )
mSpellAreaForQuestEndMap . insert ( SpellAreaForQuestMap :: value_type ( spellArea . questEnd , sa ));
// for search at aura apply
if ( spellArea . auraSpell )
mSpellAreaForAuraMap . insert ( SpellAreaForAuraMap :: value_type ( abs ( spellArea . auraSpell ), sa ));
++ count ;
} while ( result -> NextRow ());
sLog -> outString ( ">> Loaded %u spell area requirements in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2008-11-17 22:07:21 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellInfoStore ()
2008-11-17 22:07:21 -06:00
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2011-07-26 23:09:28 +02:00
UnloadSpellInfoStore ();
mSpellInfoMap . resize ( sSpellStore . GetNumRows (), NULL );
2010-01-01 14:19:29 -06:00
2010-12-27 22:27:11 +01:00
for ( uint32 i = 0 ; i < sSpellStore . GetNumRows (); ++ i )
2008-11-17 22:07:21 -06:00
{
2011-07-26 23:09:28 +02:00
if ( SpellEntry const * spellEntry = sSpellStore . LookupEntry ( i ))
mSpellInfoMap [ i ] = new SpellInfo ( spellEntry );
}
sLog -> outString ( ">> Loaded spell custom attributes in %u ms" , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
}
void SpellMgr :: UnloadSpellInfoStore ()
{
for ( uint32 i = 0 ; i < mSpellInfoMap . size (); ++ i )
{
if ( mSpellInfoMap [ i ])
2012-02-21 20:03:27 +01:00
delete mSpellInfoMap [ i ];
2011-07-26 23:09:28 +02:00
}
mSpellInfoMap . clear ();
}
2012-02-21 20:03:27 +01:00
void SpellMgr :: UnloadSpellInfoImplicitTargetConditionLists ()
{
for ( uint32 i = 0 ; i < mSpellInfoMap . size (); ++ i )
{
if ( mSpellInfoMap [ i ])
mSpellInfoMap [ i ] -> _UnloadImplicitTargetConditionLists ();
}
}
2011-07-26 23:09:28 +02:00
void SpellMgr :: LoadSpellCustomAttr ()
{
uint32 oldMSTime = getMSTime ();
SpellInfo * spellInfo = NULL ;
for ( uint32 i = 0 ; i < GetSpellInfoStoreSize (); ++ i )
{
spellInfo = mSpellInfoMap [ i ];
2009-11-20 19:11:28 -08:00
if ( ! spellInfo )
2009-05-15 16:26:00 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-01-01 14:19:29 -06:00
for ( uint8 j = 0 ; j < MAX_SPELL_EFFECTS ; ++ j )
2009-05-15 16:26:00 -05:00
{
2011-07-26 23:09:28 +02:00
switch ( spellInfo -> Effects [ j ]. ApplyAuraName )
{
case SPELL_AURA_MOD_POSSESS :
case SPELL_AURA_MOD_CONFUSE :
case SPELL_AURA_MOD_CHARM :
case SPELL_AURA_AOE_CHARM :
case SPELL_AURA_MOD_FEAR :
case SPELL_AURA_MOD_STUN :
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_AURA_CC ;
break ;
2011-08-21 12:00:36 +02:00
case SPELL_AURA_PERIODIC_HEAL :
case SPELL_AURA_PERIODIC_DAMAGE :
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT :
case SPELL_AURA_PERIODIC_LEECH :
case SPELL_AURA_PERIODIC_MANA_LEECH :
case SPELL_AURA_PERIODIC_HEALTH_FUNNEL :
case SPELL_AURA_PERIODIC_ENERGIZE :
case SPELL_AURA_OBS_MOD_HEALTH :
case SPELL_AURA_OBS_MOD_POWER :
2011-09-03 18:07:27 +02:00
case SPELL_AURA_POWER_BURN :
2011-08-21 12:00:36 +02:00
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT ;
break ;
2011-07-26 23:09:28 +02:00
}
2011-08-26 09:41:33 +02:00
2011-07-26 23:09:28 +02:00
switch ( spellInfo -> Effects [ j ]. Effect )
2009-05-15 16:26:00 -05:00
{
case SPELL_EFFECT_SCHOOL_DAMAGE :
case SPELL_EFFECT_WEAPON_DAMAGE :
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL :
case SPELL_EFFECT_NORMALIZED_WEAPON_DMG :
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE :
case SPELL_EFFECT_HEAL :
2011-07-26 23:09:28 +02:00
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_DIRECT_DAMAGE ;
2009-05-15 16:26:00 -05:00
break ;
2011-08-21 12:00:36 +02:00
case SPELL_EFFECT_POWER_DRAIN :
case SPELL_EFFECT_POWER_BURN :
case SPELL_EFFECT_HEAL_MAX_HEALTH :
case SPELL_EFFECT_HEALTH_LEECH :
case SPELL_EFFECT_HEAL_PCT :
case SPELL_EFFECT_ENERGIZE_PCT :
case SPELL_EFFECT_ENERGIZE :
case SPELL_EFFECT_HEAL_MECHANICAL :
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT ;
break ;
2009-05-15 16:26:00 -05:00
case SPELL_EFFECT_CHARGE :
2010-07-19 19:22:05 +02:00
case SPELL_EFFECT_CHARGE_DEST :
2009-05-15 16:26:00 -05:00
case SPELL_EFFECT_JUMP :
2010-07-19 21:24:09 +02:00
case SPELL_EFFECT_JUMP_DEST :
2009-08-27 20:14:50 -05:00
case SPELL_EFFECT_LEAP_BACK :
2011-07-26 23:09:28 +02:00
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_CHARGE ;
2009-05-15 16:26:00 -05:00
break ;
2010-01-13 18:22:31 +01:00
case SPELL_EFFECT_PICKPOCKET :
2011-07-26 23:09:28 +02:00
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_PICKPOCKET ;
2009-05-15 16:26:00 -05:00
break ;
2010-12-27 22:27:11 +01:00
case SPELL_EFFECT_ENCHANT_ITEM :
case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY :
case SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC :
case SPELL_EFFECT_ENCHANT_HELD_ITEM :
{
// only enchanting profession enchantments procs can stack
if ( IsPartOfSkillLine ( SKILL_ENCHANTING , i ))
{
2011-07-26 23:09:28 +02:00
uint32 enchantId = spellInfo -> Effects [ j ]. MiscValue ;
2011-06-28 23:48:59 +07:00
SpellItemEnchantmentEntry const * enchant = sSpellItemEnchantmentStore . LookupEntry ( enchantId );
2010-12-27 22:27:11 +01:00
for ( uint8 s = 0 ; s < MAX_ITEM_ENCHANTMENT_EFFECTS ; ++ s )
{
if ( enchant -> type [ s ] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL )
continue ;
2011-08-26 09:41:33 +02:00
SpellInfo * procInfo = ( SpellInfo * ) GetSpellInfo ( enchant -> spellid [ s ]);
2010-12-27 22:27:11 +01:00
if ( ! procInfo )
continue ;
// if proced directly from enchantment, not via proc aura
// NOTE: Enchant Weapon - Blade Ward also has proc aura spell and is proced directly
// however its not expected to stack so this check is good
2011-07-26 23:09:28 +02:00
if ( procInfo -> HasAura ( SPELL_AURA_PROC_TRIGGER_SPELL ))
2010-12-27 22:27:11 +01:00
continue ;
2011-07-26 23:09:28 +02:00
procInfo -> AttributesCu |= SPELL_ATTR0_CU_ENCHANT_PROC ;
2010-12-27 22:27:11 +01:00
}
}
break ;
}
2009-05-15 16:26:00 -05:00
}
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( ! spellInfo -> _IsPositiveEffect ( EFFECT_0 , false ))
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF0 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( ! spellInfo -> _IsPositiveEffect ( EFFECT_1 , false ))
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF1 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( ! spellInfo -> _IsPositiveEffect ( EFFECT_2 , false ))
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF2 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( spellInfo -> SpellVisual [ 0 ] == 3879 )
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_CONE_BACK ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
switch ( spellInfo -> Id )
2009-05-15 16:26:00 -05:00
{
2011-08-01 12:05:30 +02:00
case 1776 : // Gouge
case 1777 :
case 8629 :
case 11285 :
case 11286 :
case 12540 :
case 13579 :
case 24698 :
case 28456 :
case 29425 :
case 34940 :
case 36862 :
case 38764 :
case 38863 :
case 52743 : // Head Smack
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER ;
break ;
case 53 : // Backstab
case 2589 :
case 2590 :
case 2591 :
case 8721 :
case 11279 :
case 11280 :
case 11281 :
case 25300 :
case 26863 :
case 48656 :
case 48657 :
case 703 : // Garrote
case 8631 :
case 8632 :
case 8633 :
case 11289 :
case 11290 :
case 26839 :
case 26884 :
case 48675 :
case 48676 :
case 5221 : // Shred
case 6800 :
case 8992 :
case 9829 :
case 9830 :
case 27001 :
case 27002 :
case 48571 :
case 48572 :
case 8676 : // Ambush
case 8724 :
case 8725 :
case 11267 :
case 11268 :
case 11269 :
case 27441 :
case 48689 :
case 48690 :
case 48691 :
2011-12-05 10:20:06 -05:00
case 6785 : // Ravage
case 6787 :
case 9866 :
2011-12-05 23:11:53 +02:00
case 9867 :
2011-12-05 10:20:06 -05:00
case 27005 :
case 48578 :
case 48579 :
2011-08-01 12:05:30 +02:00
case 21987 : // Lash of Pain
case 23959 : // Test Stab R50
case 24825 : // Test Backstab
case 58563 : // Assassinate Restless Lookout
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET ;
break ;
case 26029 : // Dark Glare
case 37433 : // Spout
case 43140 : // Flame Breath
case 43215 : // Flame Breath
case 70461 : // Coldflame Trap
2011-10-05 20:48:34 +02:00
case 72133 : // Pain and Suffering
case 73788 : // Pain and Suffering
case 73789 : // Pain and Suffering
case 73790 : // Pain and Suffering
2011-08-01 12:05:30 +02:00
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_CONE_LINE ;
break ;
case 24340 : // Meteor
case 26558 : // Meteor
case 28884 : // Meteor
case 36837 : // Meteor
case 38903 : // Meteor
case 41276 : // Meteor
case 57467 : // Meteor
case 26789 : // Shard of the Fallen Star
case 31436 : // Malevolent Cleave
case 35181 : // Dive Bomb
case 40810 : // Saber Lash
case 43267 : // Saber Lash
case 43268 : // Saber Lash
case 42384 : // Brutal Swipe
case 45150 : // Meteor Slash
case 64688 : // Sonic Screech
case 72373 : // Shared Suffering
case 71904 : // Chaos Bane
case 70492 : // Ooze Eruption
case 72505 : // Ooze Eruption
case 72624 : // Ooze Eruption
case 72625 : // Ooze Eruption
// ONLY SPELLS WITH SPELLFAMILY_GENERIC and EFFECT_SCHOOL_DAMAGE
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_SHARE_DAMAGE ;
break ;
case 18500 : // Wing Buffet
case 33086 : // Wild Bite
case 49749 : // Piercing Blow
case 52890 : // Penetrating Strike
case 53454 : // Impale
case 59446 : // Impale
case 62383 : // Shatter
case 64777 : // Machine Gun
case 65239 : // Machine Gun
case 65919 : // Impale
case 67858 : // Impale
case 67859 : // Impale
case 67860 : // Impale
case 69293 : // Wing Buffet
case 74439 : // Machine Gun
case 63278 : // Mark of the Faceless (General Vezax)
2012-01-30 00:21:42 +01:00
case 62544 : // Thrust (Argent Tournament)
case 64588 : // Thrust (Argent Tournament)
case 66479 : // Thrust (Argent Tournament)
case 68505 : // Thrust (Argent Tournament)
2012-02-05 13:17:10 +01:00
case 62709 : // Counterattack! (Argent Tournament)
2012-01-30 00:21:42 +01:00
case 62626 : // Break-Shield (Argent Tournament, Player)
case 64590 : // Break-Shield (Argent Tournament, Player)
case 64342 : // Break-Shield (Argent Tournament, NPC)
case 64686 : // Break-Shield (Argent Tournament, NPC)
case 65147 : // Break-Shield (Argent Tournament, NPC)
case 68504 : // Break-Shield (Argent Tournament, NPC)
case 62874 : // Charge (Argent Tournament, Player)
case 68498 : // Charge (Argent Tournament, Player)
case 64591 : // Charge (Argent Tournament, Player)
case 63003 : // Charge (Argent Tournament, NPC)
case 63010 : // Charge (Argent Tournament, NPC)
case 68321 : // Charge (Argent Tournament, NPC)
2011-09-27 21:44:29 +02:00
case 72255 : // Mark of the Fallen Champion (Deathbringer Saurfang)
case 72444 : // Mark of the Fallen Champion (Deathbringer Saurfang)
case 72445 : // Mark of the Fallen Champion (Deathbringer Saurfang)
case 72446 : // Mark of the Fallen Champion (Deathbringer Saurfang)
2011-08-01 12:05:30 +02:00
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_IGNORE_ARMOR ;
break ;
case 64422 : // Sonic Screech (Auriaya)
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_SHARE_DAMAGE ;
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_IGNORE_ARMOR ;
break ;
2011-09-16 11:29:35 +02:00
case 72293 : // Mark of the Fallen Champion (Deathbringer Saurfang)
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF0 ;
break ;
2011-08-26 09:41:33 +02:00
default :
break ;
2011-07-26 23:09:28 +02:00
}
switch ( spellInfo -> SpellFamilyName )
{
case SPELLFAMILY_WARRIOR :
// Shout
if ( spellInfo -> SpellFamilyFlags [ 0 ] & 0x20000 || spellInfo -> SpellFamilyFlags [ 1 ] & 0x20 )
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_AURA_CC ;
break ;
case SPELLFAMILY_DRUID :
// Roar
if ( spellInfo -> SpellFamilyFlags [ 0 ] & 0x8 )
spellInfo -> AttributesCu |= SPELL_ATTR0_CU_AURA_CC ;
break ;
default :
break ;
}
}
CreatureAI :: FillAISpellInfo ();
sLog -> outString ( ">> Loaded spell custom attributes in %u ms" , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
}
void SpellMgr :: LoadDbcDataCorrections ()
{
uint32 oldMSTime = getMSTime ();
2011-11-23 13:16:45 +01:00
/*SpellEntry* spellInfo = NULL;
2011-07-26 23:09:28 +02:00
for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i)
{
spellInfo = (SpellEntry*)sSpellStore.LookupEntry(i);
if (!spellInfo)
continue;
for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
{
switch (spellInfo->Effect[j])
{
case SPELL_EFFECT_CHARGE:
case SPELL_EFFECT_CHARGE_DEST:
case SPELL_EFFECT_JUMP:
case SPELL_EFFECT_JUMP_DEST:
case SPELL_EFFECT_LEAP_BACK:
if (!spellInfo->speed && !spellInfo->SpellFamilyName)
spellInfo->speed = SPEED_CHARGE;
break;
}
}
if (spellInfo->activeIconID == 2158) // flight
spellInfo->Attributes |= SPELL_ATTR0_PASSIVE;
switch (spellInfo->Id)
{
2012-01-06 01:19:07 +01:00
case 40244: case 40245: // Simon Game Visual
case 40246: case 40247: // Simon Game Visual
case 42835: // Spout, remove damage effect, only anim is needed
spellInfo->Effect[0] = 0;
2011-08-21 15:01:40 +02:00
break;
case 30657: // Quake
spellInfo->EffectTriggerSpell[0] = 30571;
break;
case 30541: // Blaze (needs conditions entry)
spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ENEMY;
spellInfo->EffectImplicitTargetB[0] = 0;
break;
2012-01-30 00:21:42 +01:00
case 63665: // Charge (Argent Tournament emote on riders)
2011-08-21 15:01:40 +02:00
case 31447: // Mark of Kaz'rogal (needs target selection script)
case 31298: // Sleep (needs target selection script)
2011-11-26 21:42:40 +02:00
case 51904: // Summon Ghouls On Scarlet Crusade (this should use conditions table, script for this spell needs to be fixed)
case 2895: // Wrath of Air Totem rank 1 (Aura)
case 68933: // Wrath of Air Totem rank 2 (Aura)
2011-11-26 14:59:56 -07:00
case 29200: // Purify Helboar Meat
2011-08-21 15:01:40 +02:00
spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER;
spellInfo->EffectImplicitTargetB[0] = 0;
break;
case 31344: // Howl of Azgalor
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_100_YARDS; // 100yards instead of 50000?!
2011-08-21 15:01:40 +02:00
break;
case 42818: // Headless Horseman - Wisp Flight Port
case 42821: // Headless Horseman - Wisp Flight Missile
spellInfo->rangeIndex = 6; // 100 yards
break;
case 36350: //They Must Burn Bomb Aura (self)
spellInfo->EffectTriggerSpell[0] = 36325; // They Must Burn Bomb Drop (DND)
break;
case 49838: // Stop Time
spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO;
break;
case 61407: // Energize Cores
case 62136: // Energize Cores
case 54069: // Energize Cores
case 56251: // Energize Cores
2011-08-26 18:04:35 +01:00
spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_SRC_AREA_ENTRY;
break;
2011-08-21 15:01:40 +02:00
case 50785: // Energize Cores
case 59372: // Energize Cores
spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_SRC_AREA_ENEMY;
break;
case 8494: // Mana Shield (rank 2)
// because of bug in dbc
spellInfo->procChance = 0;
break;
case 20335: // Heart of the Crusader
case 20336:
case 20337:
case 63320: // Glyph of Life Tap
// Entries were not updated after spell effect change, we have to do that manually :/
spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED;
break;
case 59725: // Improved Spell Reflection - aoe aura
// Target entry seems to be wrong for this spell :/
spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER_AREA_PARTY;
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_10_YARDS_2;
2011-08-21 15:01:40 +02:00
break;
2011-11-26 21:42:40 +02:00
case 44978: // Wild Magic
case 45001:
case 45002:
case 45004:
case 45006:
case 45010:
2011-08-21 15:01:40 +02:00
case 31347: // Doom
case 41635: // Prayer of Mending
case 44869: // Spectral Blast
case 45027: // Revitalize
case 45976: // Muru Portal Channel
case 39365: // Thundering Storm
case 41071: // Raise Dead (HACK)
case 52124: // Sky Darkener Assault
case 42442: // Vengeance Landing Cannonfire
case 45863: // Cosmetic - Incinerate to Random Target
case 25425: // Shoot
case 45761: // Shoot
case 42611: // Shoot
case 61588: // Blazing Harpoon
case 52479: // Gift of the Harvester
2012-01-08 23:07:31 +00:00
case 48246: // Ball of Flame
2011-08-21 15:01:40 +02:00
spellInfo->MaxAffectedTargets = 1;
break;
case 41376: // Spite
case 39992: // Needle Spine
case 29576: // Multi-Shot
case 40816: // Saber Lash
case 37790: // Spread Shot
case 46771: // Flame Sear
case 45248: // Shadow Blades
case 41303: // Soul Drain
case 54172: // Divine Storm (heal)
case 29213: // Curse of the Plaguebringer - Noth
case 28542: // Life Drain - Sapphiron
case 66588: // Flaming Spear
case 54171: // Divine Storm
spellInfo->MaxAffectedTargets = 3;
break;
case 38310: // Multi-Shot
case 53385: // Divine Storm (Damage)
spellInfo->MaxAffectedTargets = 4;
break;
case 42005: // Bloodboil
case 38296: // Spitfire Totem
case 37676: // Insidious Whisper
case 46008: // Negative Energy
case 45641: // Fire Bloom
case 55665: // Life Drain - Sapphiron (H)
case 28796: // Poison Bolt Volly - Faerlina
spellInfo->MaxAffectedTargets = 5;
break;
case 40827: // Sinful Beam
case 40859: // Sinister Beam
case 40860: // Vile Beam
case 40861: // Wicked Beam
case 54835: // Curse of the Plaguebringer - Noth (H)
case 54098: // Poison Bolt Volly - Faerlina (H)
spellInfo->MaxAffectedTargets = 10;
break;
case 50312: // Unholy Frenzy
spellInfo->MaxAffectedTargets = 15;
break;
2011-11-26 21:42:40 +02:00
case 33711: //Murmur's Touch
case 38794:
2011-08-21 15:01:40 +02:00
spellInfo->MaxAffectedTargets = 1;
spellInfo->EffectTriggerSpell[0] = 33760;
break;
case 17941: // Shadow Trance
case 22008: // Netherwind Focus
case 31834: // Light's Grace
case 34754: // Clearcasting
case 34936: // Backlash
case 48108: // Hot Streak
case 51124: // Killing Machine
case 54741: // Firestarter
case 57761: // Fireball!
case 39805: // Lightning Overload
case 64823: // Item - Druid T8 Balance 4P Bonus
2011-09-03 18:26:39 +02:00
case 34477: // Misdirection
2011-08-21 15:01:40 +02:00
case 44401: // Missile Barrage
spellInfo->procCharges = 1;
break;
case 44544: // Fingers of Frost
spellInfo->EffectSpellClassMask[0] = flag96(685904631, 1151048, 0);
break;
case 74396: // Fingers of Frost visual buff
spellInfo->procCharges = 2;
spellInfo->StackAmount = 0;
break;
case 28200: // Ascendance (Talisman of Ascendance trinket)
spellInfo->procCharges = 6;
break;
case 47201: // Everlasting Affliction
case 47202:
case 47203:
case 47204:
case 47205:
// add corruption to affected spells
spellInfo->EffectSpellClassMask[1][0] |= 2;
break;
case 51852: // The Eye of Acherus (no spawn in phase 2 in db)
spellInfo->EffectMiscValue[0] |= 1;
break;
case 29809: // Desecration Arm - 36 instead of 37 - typo? :/
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_7_YARDS;
2011-08-21 15:01:40 +02:00
break;
// Master Shapeshifter: missing stance data for forms other than bear - bear version has correct data
// To prevent aura staying on target after talent unlearned
case 48420:
spellInfo->Stances = 1 << (FORM_CAT - 1);
break;
case 48421:
spellInfo->Stances = 1 << (FORM_MOONKIN - 1);
break;
case 48422:
spellInfo->Stances = 1 << (FORM_TREE - 1);
break;
2011-10-10 18:01:02 -03:00
case 51466: // Elemental Oath (Rank 1)
case 51470: // Elemental Oath (Rank 2)
spellInfo->Effect[EFFECT_1] = SPELL_EFFECT_APPLY_AURA;
spellInfo->EffectApplyAuraName[EFFECT_1] = SPELL_AURA_ADD_FLAT_MODIFIER;
spellInfo->EffectMiscValue[EFFECT_1] = SPELLMOD_EFFECT2;
spellInfo->EffectSpellClassMask[EFFECT_1] = flag96(0x00000000, 0x00004000, 0x00000000);
break;
2011-08-21 15:01:40 +02:00
case 47569: // Improved Shadowform (Rank 1)
// with this spell atrribute aura can be stacked several times
spellInfo->Attributes &= ~SPELL_ATTR0_NOT_SHAPESHIFT;
break;
2011-10-12 01:11:52 +03:00
case 64904: // Hymn of Hope
2011-09-26 20:12:25 +03:00
spellInfo->EffectApplyAuraName[EFFECT_1] = SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT;
break;
2011-12-23 19:49:59 -05:00
case 19465: // Improved Stings (Rank 2)
spellInfo->EffectImplicitTargetA[EFFECT_2] = TARGET_UNIT_CASTER;
break;
2011-08-21 15:01:40 +02:00
case 30421: // Nether Portal - Perseverence
spellInfo->EffectBasePoints[2] += 30000;
break;
case 16834: // Natural shapeshifter
case 16835:
spellInfo->DurationIndex = 21;
break;
case 51735: // Ebon Plague
case 51734:
case 51726:
spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
spellInfo->SpellFamilyFlags[2] = 0x10;
2011-10-18 23:38:55 +02:00
spellInfo->EffectApplyAuraName[1] = SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN;
2011-08-21 15:01:40 +02:00
break;
2011-08-25 10:21:19 +02:00
case 41913: // Parasitic Shadowfiend Passive
2011-11-26 21:42:40 +02:00
spellInfo->EffectApplyAuraName[0] = SPELL_AURA_DUMMY; // proc debuff, and summon infinite fiends
2011-08-21 15:01:40 +02:00
break;
case 27892: // To Anchor 1
case 27928: // To Anchor 1
case 27935: // To Anchor 1
case 27915: // Anchor to Skulls
case 27931: // Anchor to Skulls
case 27937: // Anchor to Skulls
spellInfo->rangeIndex = 13;
break;
// target allys instead of enemies, target A is src_caster, spells with effect like that have ally target
// this is the only known exception, probably just wrong data
case 29214: // Wrath of the Plaguebringer
case 54836: // Wrath of the Plaguebringer
spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ALLY;
spellInfo->EffectImplicitTargetB[1] = TARGET_UNIT_SRC_AREA_ALLY;
break;
case 57994: // Wind Shear - improper data for EFFECT_1 in 3.3.5 DBC, but is correct in 4.x
spellInfo->Effect[EFFECT_1] = SPELL_EFFECT_MODIFY_THREAT_PERCENT;
spellInfo->EffectBasePoints[EFFECT_1] = -6; // -5%
break;
case 63675: // Improved Devouring Plague
spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
break;
case 8145: // Tremor Totem (instant pulse)
case 6474: // Earthbind Totem (instant pulse)
spellInfo->AttributesEx5 |= SPELL_ATTR5_START_PERIODIC_AT_APPLY;
break;
2011-10-19 18:35:21 +02:00
case 52109: // Flametongue Totem rank 1 (Aura)
case 52110: // Flametongue Totem rank 2 (Aura)
case 52111: // Flametongue Totem rank 3 (Aura)
case 52112: // Flametongue Totem rank 4 (Aura)
case 52113: // Flametongue Totem rank 5 (Aura)
case 58651: // Flametongue Totem rank 6 (Aura)
case 58654: // Flametongue Totem rank 7 (Aura)
case 58655: // Flametongue Totem rank 8 (Aura)
spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER;
spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_CASTER;
spellInfo->EffectImplicitTargetB[0] = 0;
spellInfo->EffectImplicitTargetB[1] = 0;
break;
2011-08-21 15:01:40 +02:00
case 53241: // Marked for Death (Rank 1)
case 53243: // Marked for Death (Rank 2)
case 53244: // Marked for Death (Rank 3)
case 53245: // Marked for Death (Rank 4)
case 53246: // Marked for Death (Rank 5)
2011-11-26 21:42:40 +02:00
spellInfo->EffectSpellClassMask[0] = flag96(0x00067801, 0x10820001, 0x00000801);
2011-08-21 15:01:40 +02:00
break;
2011-09-25 13:29:17 +02:00
case 70728: // Exploit Weakness (needs target selection script)
case 70840: // Devious Minds (needs target selection script)
2011-08-21 15:01:40 +02:00
spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER;
spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_PET;
break;
2011-09-25 13:29:17 +02:00
case 70893: // Culling The Herd (needs target selection script)
2011-08-21 15:01:40 +02:00
spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER;
spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_MASTER;
break;
case 54800: // Sigil of the Frozen Conscience - change class mask to custom extended flags of Icy Touch
// this is done because another spell also uses the same SpellFamilyFlags as Icy Touch
// SpellFamilyFlags[0] & 0x00000040 in SPELLFAMILY_DEATHKNIGHT is currently unused (3.3.5a)
// this needs research on modifier applying rules, does not seem to be in Attributes fields
spellInfo->EffectSpellClassMask[0] = flag96(0x00000040, 0x00000000, 0x00000000);
break;
2011-12-18 23:44:15 +00:00
case 63163: // Apply Enchanted Bridle (Argent Tournament)
spellInfo->EffectDieSides[0] = 0; // was 1, that should probably mean seat 0, but instead it's treated as spell 1
spellInfo->EffectBasePoints[0] = 52391; // Ride Vehicle (forces seat 0)
break;
2011-08-21 15:01:40 +02:00
case 19970: // Entangling Roots (Rank 6) -- Nature's Grasp Proc
case 19971: // Entangling Roots (Rank 5) -- Nature's Grasp Proc
case 19972: // Entangling Roots (Rank 4) -- Nature's Grasp Proc
case 19973: // Entangling Roots (Rank 3) -- Nature's Grasp Proc
case 19974: // Entangling Roots (Rank 2) -- Nature's Grasp Proc
case 19975: // Entangling Roots (Rank 1) -- Nature's Grasp Proc
case 27010: // Entangling Roots (Rank 7) -- Nature's Grasp Proc
case 53313: // Entangling Roots (Rank 8) -- Nature's Grasp Proc
spellInfo->CastingTimeIndex = 1;
break;
case 61719: // Easter Lay Noblegarden Egg Aura - Interrupt flags copied from aura which this aura is linked with
spellInfo->AuraInterruptFlags = AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE;
break;
// ULDUAR SPELLS
//
2011-10-07 13:47:03 +02:00
case 62374: // Pursued (Flame Leviathan)
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
2011-10-07 13:47:03 +02:00
break;
2011-08-21 15:01:40 +02:00
case 63342: // Focused Eyebeam Summon Trigger (Kologarn)
spellInfo->MaxAffectedTargets = 1;
break;
case 62716: // Growth of Nature (Freya)
case 65584: // Growth of Nature (Freya)
case 64381: // Strength of the Pack (Auriaya)
spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
break;
case 63018: // Searing Light (XT-002)
case 65121: // Searing Light (25m) (XT-002)
case 63024: // Gravity Bomb (XT-002)
case 64234: // Gravity Bomb (25m) (XT-002)
spellInfo->MaxAffectedTargets = 1;
break;
case 62834: // Boom (XT-002)
// This hack is here because we suspect our implementation of spell effect execution on targets
// is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets,
// then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc.
// The above situation causes the visual for this spell to be bugged, so we remove the instakill
// effect and implement a script hack for that.
spellInfo->Effect[EFFECT_1] = 0;
break;
case 64386: // Terrifying Screech (Auriaya)
case 64389: // Sentinel Blast (Auriaya)
case 64678: // Sentinel Blast (Auriaya)
spellInfo->DurationIndex = 28; // 5 seconds, wrong DBC data?
break;
case 64321: // Potent Pheromones (Freya)
// spell should dispel area aura, but doesn't have the attribute
// may be db data bug, or blizz may keep reapplying area auras every update with checking immunity
// that will be clear if we get more spells with problem like this
spellInfo->AttributesEx |= SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY;
break;
2011-09-08 13:50:01 +02:00
case 62584: // Lifebinder's Gift
case 64185: // Lifebinder's Gift
spellInfo->EffectImplicitTargetB[1] = TARGET_UNIT_NEARBY_ENTRY;
spellInfo->EffectImplicitTargetB[2] = TARGET_UNIT_NEARBY_ENTRY;
break;
2011-08-21 15:01:40 +02:00
// ENDOF ULDUAR SPELLS
//
// TRIAL OF THE CRUSADER SPELLS
//
case 66258: // Infernal Eruption (10N)
case 67901: // Infernal Eruption (25N)
// increase duration from 15 to 18 seconds because caster is already
// unsummoned when spell missile hits the ground so nothing happen in result
spellInfo->DurationIndex = 85;
break;
// ENDOF TRIAL OF THE CRUSADER SPELLS
//
// ICECROWN CITADEL SPELLS
//
// THESE SPELLS ARE WORKING CORRECTLY EVEN WITHOUT THIS HACK
// THE ONLY REASON ITS HERE IS THAT CURRENT GRID SYSTEM
// DOES NOT ALLOW FAR OBJECT SELECTION (dist > 333)
case 70781: // Light's Hammer Teleport
case 70856: // Oratory of the Damned Teleport
case 70857: // Rampart of Skulls Teleport
case 70858: // Deathbringer's Rise Teleport
case 70859: // Upper Spire Teleport
case 70860: // Frozen Throne Teleport
case 70861: // Sindragosa's Lair Teleport
spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DB;
break;
case 69055: // Saber Lash (Lord Marrowgar)
case 70814: // Saber Lash (Lord Marrowgar)
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_5_YARDS; // 5yd
2011-08-21 15:01:40 +02:00
break;
case 69075: // Bone Storm (Lord Marrowgar)
case 70834: // Bone Storm (Lord Marrowgar)
case 70835: // Bone Storm (Lord Marrowgar)
case 70836: // Bone Storm (Lord Marrowgar)
case 72864: // Death Plague (Rotting Frost Giant)
case 72378: // Blood Nova (Deathbringer Saurfang)
case 73058: // Blood Nova (Deathbringer Saurfang)
case 71160: // Plague Stench (Stinky)
case 71161: // Plague Stench (Stinky)
case 71123: // Decimate (Stinky & Precious)
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_100_YARDS; // 100yd
2011-08-21 15:01:40 +02:00
break;
case 72723: // Resistant Skin (Deathbringer Saurfang adds)
// this spell initially granted Shadow damage immunity, however it was removed but the data was left in client
spellInfo->Effect[2] = 0;
break;
case 70460: // Coldflame Jets (Traps after Saurfang)
spellInfo->DurationIndex = 1; // 10 seconds
break;
case 71413: // Green Ooze Summon (Professor Putricide)
case 71414: // Orange Ooze Summon (Professor Putricide)
spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST;
break;
2011-08-26 10:29:23 +02:00
case 71159: // Awaken Plagued Zombies
spellInfo->DurationIndex = 21;
break;
2011-08-21 15:01:40 +02:00
// THIS IS HERE BECAUSE COOLDOWN ON CREATURE PROCS IS NOT IMPLEMENTED
case 71604: // Mutated Strength (Professor Putricide)
case 72673: // Mutated Strength (Professor Putricide)
case 72674: // Mutated Strength (Professor Putricide)
case 72675: // Mutated Strength (Professor Putricide)
spellInfo->Effect[1] = 0;
break;
case 72454: // Mutated Plague (Professor Putricide)
case 72464: // Mutated Plague (Professor Putricide)
case 72506: // Mutated Plague (Professor Putricide)
case 72507: // Mutated Plague (Professor Putricide)
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
2011-08-21 15:01:40 +02:00
break;
2011-09-25 13:29:17 +02:00
case 70911: // Unbound Plague (Professor Putricide) (needs target selection script)
case 72854: // Unbound Plague (Professor Putricide) (needs target selection script)
case 72855: // Unbound Plague (Professor Putricide) (needs target selection script)
case 72856: // Unbound Plague (Professor Putricide) (needs target selection script)
2011-08-21 15:01:40 +02:00
spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_TARGET_ENEMY;
break;
case 71518: // Unholy Infusion Quest Credit (Professor Putricide)
case 72934: // Blood Infusion Quest Credit (Blood-Queen Lana'thel)
case 72289: // Frost Infusion Quest Credit (Sindragosa)
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // another missing radius
2011-08-21 15:01:40 +02:00
break;
case 71708: // Empowered Flare (Blood Prince Council)
case 72785: // Empowered Flare (Blood Prince Council)
case 72786: // Empowered Flare (Blood Prince Council)
case 72787: // Empowered Flare (Blood Prince Council)
spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
break;
case 71266: // Swarming Shadows
case 72890: // Swarming Shadows
spellInfo->AreaGroupId = 0; // originally, these require area 4522, which is... outside of Icecrown Citadel
break;
case 70602: // Corruption
2012-01-08 23:07:31 +00:00
case 48278: // Paralyze
2011-08-21 15:01:40 +02:00
spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
break;
case 70715: // Column of Frost (visual marker)
spellInfo->DurationIndex = 32; // 6 seconds (missing)
break;
case 71085: // Mana Void (periodic aura)
spellInfo->DurationIndex = 9; // 30 seconds (missing)
break;
2011-09-25 13:29:17 +02:00
case 70936: // Summon Suppressor (needs target selection script)
2011-08-21 15:01:40 +02:00
spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY;
spellInfo->EffectImplicitTargetB[0] = 0;
break;
case 72706: // Achievement Check (Valithria Dreamwalker)
case 71357: // Order Whelp
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
2011-08-21 15:01:40 +02:00
break;
case 70598: // Sindragosa's Fury
spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_CASTER;
break;
case 69846: // Frost Bomb
spellInfo->speed = 10;
spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_TARGET_ANY;
spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_TARGET_ANY;
spellInfo->Effect[1] = 0;
break;
2011-10-05 20:48:34 +02:00
case 71614: // Ice Lock
spellInfo->Mechanic = MECHANIC_STUN;
break;
case 72762: // Defile
spellInfo->DurationIndex = 559; // 53 seconds
break;
case 72743: // Defile
spellInfo->DurationIndex = 22; // 45 seconds
break;
case 72754: // Defile
case 73708: // Defile
case 73709: // Defile
case 73710: // Defile
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
2011-10-05 20:48:34 +02:00
break;
case 69030: // Val'kyr Target Search
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
2011-10-05 20:48:34 +02:00
break;
case 69198: // Raging Spirit Visual
spellInfo->rangeIndex = 13; // 50000yd
break;
case 73654: // Harvest Souls
case 74295: // Harvest Souls
case 74296: // Harvest Souls
case 74297: // Harvest Souls
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_50000_YARDS; // 50000yd
spellInfo->EffectRadiusIndex[2] = EFFECT_RADIUS_50000_YARDS; // 50000yd
2011-10-05 20:48:34 +02:00
break;
case 73655: // Harvest Soul
spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
break;
case 73540: // Summon Shadow Trap
spellInfo->DurationIndex = 23; // 90 seconds
break;
case 73530: // Shadow Trap (visual)
spellInfo->DurationIndex = 28; // 5 seconds
break;
case 73529: // Shadow Trap
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_10_YARDS; // 10yd
2011-10-05 20:48:34 +02:00
break;
case 74282: // Shadow Trap (searcher)
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_3_YARDS; // 3yd
2011-10-05 20:48:34 +02:00
break;
case 72595: // Restore Soul
case 73650: // Restore Soul
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
2011-10-05 20:48:34 +02:00
break;
case 74086: // Destroy Soul
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
2011-10-05 20:48:34 +02:00
break;
case 74302: // Summon Spirit Bomb
case 74342: // Summon Spirit Bomb
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
2011-10-05 20:48:34 +02:00
spellInfo->MaxAffectedTargets = 1;
break;
case 74341: // Summon Spirit Bomb
case 74343: // Summon Spirit Bomb
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
2011-10-05 20:48:34 +02:00
spellInfo->MaxAffectedTargets = 3;
break;
case 73579: // Summon Spirit Bomb
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_25_YARDS; // 25yd
2011-10-05 20:48:34 +02:00
break;
case 72350: // Fury of Frostmourne
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_50000_YARDS; // 50000yd
2011-10-05 20:48:34 +02:00
break;
case 75127: // Kill Frostmourne Players
case 72351: // Fury of Frostmourne
2011-10-06 14:30:33 +02:00
case 72431: // Jump (removes Fury of Frostmourne debuff)
2011-10-05 20:48:34 +02:00
case 72429: // Mass Resurrection
case 73159: // Play Movie
case 73582: // Trigger Vile Spirit (Inside, Heroic)
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
2011-10-05 20:48:34 +02:00
break;
case 72376: // Raise Dead
spellInfo->MaxAffectedTargets = 3;
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
2011-10-05 20:48:34 +02:00
break;
case 71809: // Jump
spellInfo->rangeIndex = 3; // 20yd
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_25_YARDS; // 25yd
2011-10-05 20:48:34 +02:00
break;
2011-10-06 17:57:28 +02:00
case 72405: // Broken Frostmourne
2011-10-27 21:30:23 +02:00
spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
2011-10-06 17:57:28 +02:00
break;
2012-01-06 01:19:07 +01:00
case 40055: // Introspection
case 40165: // Introspection
case 40166: // Introspection
case 40167: // Introspection
spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1;
2011-08-21 15:01:40 +02:00
default:
break;
2009-05-15 16:26:00 -05:00
}
2009-10-17 15:51:44 -07:00
2011-02-07 17:21:44 +01:00
switch (spellInfo->SpellFamilyName)
2009-05-15 16:26:00 -05:00
{
case SPELLFAMILY_DRUID:
2009-05-18 10:22:43 -05:00
// Starfall Target Selection
2010-04-07 19:14:10 +02:00
if (spellInfo->SpellFamilyFlags[2] & 0x100)
2009-05-15 16:26:00 -05:00
spellInfo->MaxAffectedTargets = 2;
break;
2011-05-31 23:10:58 +07:00
case SPELLFAMILY_PALADIN:
// Seals of the Pure should affect Seal of Righteousness
if (spellInfo->SpellIconID == 25 && spellInfo->Attributes & SPELL_ATTR0_PASSIVE)
spellInfo->EffectSpellClassMask[0][1] |= 0x20000000;
break;
2011-03-31 23:44:39 +02:00
case SPELLFAMILY_DEATHKNIGHT:
// Icy Touch - extend FamilyFlags (unused value) for Sigil of the Frozen Conscience to use
if (spellInfo->SpellIconID == 2721 && spellInfo->SpellFamilyFlags[0] & 0x2)
spellInfo->SpellFamilyFlags[0] |= 0x40;
break;
2009-05-15 16:26:00 -05:00
}
}
2009-10-17 15:51:44 -07:00
2011-06-28 23:48:59 +07:00
SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(121));
2009-05-15 16:26:00 -05:00
properties->Type = SUMMON_TYPE_TOTEM;
2009-08-17 23:09:17 -05:00
properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(647)); // 52893
properties->Type = SUMMON_TYPE_TOTEM;
2011-11-23 13:16:45 +01:00
*/
2011-07-26 23:09:28 +02:00
sLog -> outString ( ">> Loading spell dbc data corrections in %u ms" , GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2011-08-03 08:18:24 +02:00
}