diff options
Diffstat (limited to 'src/game/Spell.cpp')
| -rw-r--r-- | src/game/Spell.cpp | 1132 | 
1 files changed, 747 insertions, 385 deletions
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index f74bf664c5c..b5046a18491 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -1,7 +1,7 @@  /* - * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>   * - * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> + * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -43,7 +43,6 @@  #include "CellImpl.h"  #include "Policies/SingletonImp.h"  #include "SharedDefines.h" -#include "Tools.h"  #include "LootMgr.h"  #include "VMapFactory.h"  #include "BattleGround.h" @@ -120,6 +119,14 @@ void SpellCastTargets::setDestination(Unit *target, bool send)          m_targetMask |= TARGET_FLAG_DEST_LOCATION;  } +void SpellCastTargets::setSource(float x, float y, float z) +{ +    m_srcX = x; +    m_srcY = y; +    m_srcZ = z; +    m_targetMask |= TARGET_FLAG_SOURCE_LOCATION; +} +  void SpellCastTargets::setGOTarget(GameObject *target)  {      m_GOTarget = target; @@ -178,16 +185,20 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )          return true;      // TARGET_FLAG_UNK2 is used for non-combat pets, maybe other? -    if( m_targetMask & (TARGET_FLAG_UNIT|TARGET_FLAG_UNK2) ) -        if(!readGUID(*data, m_unitTargetGUID)) +    if( m_targetMask & ( TARGET_FLAG_UNIT | TARGET_FLAG_UNK2 )) +        if(!data->readPackGUID(m_unitTargetGUID))              return false; -    if( m_targetMask & ( TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK )) -        if(!readGUID(*data, m_GOTargetGUID)) +    if( m_targetMask & ( TARGET_FLAG_OBJECT )) +        if(!data->readPackGUID(m_GOTargetGUID))              return false;      if(( m_targetMask & ( TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM )) && caster->GetTypeId() == TYPEID_PLAYER) -        if(!readGUID(*data, m_itemTargetGUID)) +        if(!data->readPackGUID(m_itemTargetGUID)) +            return false; + +    if( m_targetMask & (TARGET_FLAG_CORPSE | TARGET_FLAG_PVP_CORPSE ) ) +        if(!data->readPackGUID(m_CorpseTargetGUID))              return false;      /*if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION ) @@ -202,7 +213,10 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )      if( m_targetMask & (TARGET_FLAG_SOURCE_LOCATION | TARGET_FLAG_DEST_LOCATION) )      { -        if(data->rpos()+4+4+4 > data->size()) +        if(data->rpos()+1+4+4+4 > data->size()) +            return false; + +        if(!data->readPackGUID(m_unitTargetGUID))              return false;          *data >> m_destX >> m_destY >> m_destZ; @@ -219,10 +233,6 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )          *data >> m_strTarget;      } -    if( m_targetMask & (TARGET_FLAG_CORPSE | TARGET_FLAG_PVP_CORPSE ) ) -        if(!readGUID(*data, m_CorpseTargetGUID)) -            return false; -      // find real units/GOs      Update(caster);      return true; @@ -242,7 +252,7 @@ void SpellCastTargets::write ( WorldPacket * data )              else                  *data << uint8(0);          } -        else if( m_targetMask & ( TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK ) ) +        else if( m_targetMask & TARGET_FLAG_OBJECT )          {              if(m_GOTarget)                  data->append(m_GOTarget->GetPackGUID()); @@ -267,7 +277,14 @@ void SpellCastTargets::write ( WorldPacket * data )          *data << m_srcX << m_srcY << m_srcZ;      if( m_targetMask & TARGET_FLAG_DEST_LOCATION ) +    { +        if(m_unitTarget) +            data->append(m_unitTarget->GetPackGUID()); +        else +            *data << uint8(0); +          *data << m_destX << m_destY << m_destZ; +    }      if( m_targetMask & TARGET_FLAG_STRING )          *data << m_strTarget; @@ -305,7 +322,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi              break;          default:                                                              // Wands -            if (m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_WAND) +            if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG)                  m_attackType = RANGED_ATTACK;              else                  m_attackType = BASE_ATTACK; @@ -355,14 +372,14 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi      gameObjTarget = NULL;      focusObject = NULL;      m_cast_count = 0; +    m_glyphIndex = 0; +    m_preCastSpell = 0;      m_triggeredByAuraSpell  = NULL; -    //Auto Shot & Shoot -    if( m_spellInfo->AttributesEx2 == 0x000020 && !triggered ) -        m_autoRepeat = true; -    else -        m_autoRepeat = false; +    //Auto Shot & Shoot (wand) +    m_autoRepeat = IsAutoRepeatRangedSpell(m_spellInfo); +    m_runesState = 0;      m_powerCost = 0;                                        // setup to correct value in Spell::prepare, don't must be used before.      m_casttime = 0;                                         // setup to correct value in Spell::prepare, don't must be used before.      m_timer = 0;                                            // will set to castime in prepare @@ -372,7 +389,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi      // determine reflection      m_canReflect = false; -    if(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && (m_spellInfo->AttributesEx2 & 0x4)==0) +    if(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !(m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED))      {          for(int j=0;j<3;j++)          { @@ -457,11 +474,11 @@ void Spell::FillTargetMap()                          {                              // non-standard target selection                              SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); -                            float max_range = GetSpellMaxRange(srange); +                            float max_range = GetSpellMaxRangeForHostile(srange);                              WorldObject* result = NULL;                              Trinity::CannibalizeObjectCheck u_check(m_caster, max_range); -                            Trinity::WorldObjectSearcher<Trinity::CannibalizeObjectCheck > searcher(result, u_check); +                            Trinity::WorldObjectSearcher<Trinity::CannibalizeObjectCheck > searcher(m_caster, result, u_check);                              m_caster->VisitNearbyGridObject(max_range, searcher);                              if(!result)                                  m_caster->VisitNearbyWorldObject(max_range, searcher); @@ -511,6 +528,8 @@ void Spell::FillTargetMap()                  case SPELL_EFFECT_CREATE_ITEM:                  case SPELL_EFFECT_TRIGGER_SPELL:                  case SPELL_EFFECT_SKILL_STEP: +                case SPELL_EFFECT_PROFICIENCY: +                case SPELL_EFFECT_SUMMON_OBJECT_WILD:                  case SPELL_EFFECT_SELF_RESURRECT:                  case SPELL_EFFECT_REPUTATION:                  case SPELL_EFFECT_LEARN_SPELL: @@ -543,7 +562,9 @@ void Spell::FillTargetMap()                      break;                  case SPELL_EFFECT_SUMMON_CHANGE_ITEM:                  case SPELL_EFFECT_ADD_FARSIGHT: +                case SPELL_EFFECT_APPLY_GLYPH:                  case SPELL_EFFECT_STUCK: +                case SPELL_EFFECT_FEED_PET:                  case SPELL_EFFECT_DESTROY_ALL_TOTEMS:                      tmpUnitMap.push_back(m_caster);                      break; @@ -553,9 +574,10 @@ void Spell::FillTargetMap()                      break;                  /*case SPELL_EFFECT_ENCHANT_ITEM:                  case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY: +                case SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC:                  case SPELL_EFFECT_DISENCHANT: -                case SPELL_EFFECT_FEED_PET:                  case SPELL_EFFECT_PROSPECTING: +                case SPELL_EFFECT_MILLING:                      if(m_targets.getItemTarget())                          AddItemTarget(m_targets.getItemTarget(), i);                      break;*/ @@ -596,7 +618,6 @@ void Spell::FillTargetMap()              }          } -          if(IsChanneledSpell(m_spellInfo) && !tmpUnitMap.empty())              m_needAliveTargetMask  |= (1<<i); @@ -633,34 +654,43 @@ void Spell::prepareDataForTriggerSystem()      // Ņan spell trigger another or not ( m_canTrigger )      // Create base triggers flags for Attacker and Victim ( m_procAttacker and  m_procVictim)      //========================================================================================== -      // Fill flag can spell trigger or not -    if (!m_IsTriggeredSpell) +    // TODO: possible exist spell attribute for this +    m_canTrigger = false; + +    if (m_CastItem) +        m_canTrigger = false;         // Do not trigger from item cast spell +    else if (!m_IsTriggeredSpell)          m_canTrigger = true;          // Normal cast - can trigger      else if (!m_triggeredByAuraSpell)          m_canTrigger = true;          // Triggered from SPELL_EFFECT_TRIGGER_SPELL - can trigger -    else                              // Exceptions (some periodic triggers) + +    if (!m_canTrigger)                // Exceptions (some periodic triggers)      { -        m_canTrigger = false;         // Triggered spells can`t trigger another          switch (m_spellInfo->SpellFamilyName)          {              case SPELLFAMILY_MAGE:    // Arcane Missles / Blizzard triggers need do it -                if (m_spellInfo->SpellFamilyFlags & 0x0000000000200080LL) m_canTrigger = true; +                if (m_spellInfo->SpellFamilyFlags[0] & 0x200080) m_canTrigger = true;              break;              case SPELLFAMILY_WARLOCK: // For Hellfire Effect / Rain of Fire / Seed of Corruption triggers need do it -                if (m_spellInfo->SpellFamilyFlags & 0x0000800000000060LL) m_canTrigger = true; +                if (m_spellInfo->SpellFamilyFlags[1] & 0x00008000 || m_spellInfo->SpellFamilyFlags[0] & 0x00000060) m_canTrigger = true;              break; -            case SPELLFAMILY_HUNTER:  // Hunter Explosive Trap Effect/Immolation Trap Effect/Frost Trap Aura/Snake Trap Effect -                if (m_spellInfo->SpellFamilyFlags & 0x0000200000000014LL) m_canTrigger = true; +            case SPELLFAMILY_PRIEST:  // For Penance heal/damage triggers need do it +                if (m_spellInfo->SpellFamilyFlags[1] & 0x00018000) m_canTrigger = true;              break; -            case SPELLFAMILY_PALADIN: // For Holy Shock triggers need do it -                if (m_spellInfo->SpellFamilyFlags & 0x0001000000200000LL) m_canTrigger = true; +            case SPELLFAMILY_ROGUE:   // For poisons need do it +                if (m_spellInfo->SpellFamilyFlags[1] & 0x00000010 || m_spellInfo->SpellFamilyFlags[0] & 0x1001E000) m_canTrigger = true; +            break; +            case SPELLFAMILY_HUNTER:  // Hunter Rapid Killing/Explosive Trap Effect/Immolation Trap Effect/Frost Trap Aura/Snake Trap Effect/Explosive Shot +                if (m_spellInfo->SpellFamilyFlags[1] & 0x01002000  +                    || m_spellInfo->SpellFamilyFlags[0] & 0x00000214 || +                    m_spellInfo->SpellFamilyFlags[2] & 0x200) m_canTrigger = true; +            break; +            case SPELLFAMILY_PALADIN: // For Judgements (all) / Holy Shock triggers need do it +                if (m_spellInfo->SpellFamilyFlags[1] & 0x00010009 || m_spellInfo->SpellFamilyFlags[0] & 0x00B80400) m_canTrigger = true;              break;          }      } -    // Do not trigger from item cast spell -    if (m_CastItem) -       m_canTrigger = false;      // Get data for type of attack and fill base info for trigger      switch (m_spellInfo->DmgClass) @@ -670,21 +700,30 @@ void Spell::prepareDataForTriggerSystem()              m_procVictim   = PROC_FLAG_TAKEN_MELEE_SPELL_HIT;              break;          case SPELL_DAMAGE_CLASS_RANGED: -            m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT; -            m_procVictim   = PROC_FLAG_TAKEN_RANGED_SPELL_HIT; +            // Auto attack +            if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG) +            { +                m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT; +                m_procVictim   = PROC_FLAG_TAKEN_RANGED_HIT; +            } +            else // Ranged spell attack +            { +                m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT; +                m_procVictim   = PROC_FLAG_TAKEN_RANGED_SPELL_HIT; +            }              break;          default: -            if (IsPositiveSpell(m_spellInfo->Id))          // Check for positive spell +            if (IsPositiveSpell(m_spellInfo->Id))                                 // Check for positive spell              {                  m_procAttacker = PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL;                  m_procVictim   = PROC_FLAG_TAKEN_POSITIVE_SPELL;              } -            else if (m_spellInfo->Id == 5019) // Wands +            else if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG) // Wands auto attack              { -                m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT; -                m_procVictim   = PROC_FLAG_TAKEN_RANGED_SPELL_HIT; +                m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT; +                m_procVictim   = PROC_FLAG_TAKEN_RANGED_HIT;              } -            else +            else                                           // Negative spell              {                  m_procAttacker = PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT;                  m_procVictim   = PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT; @@ -693,7 +732,7 @@ void Spell::prepareDataForTriggerSystem()      }      // Hunter traps spells (for Entrapment trigger)      // Gives your Immolation Trap, Frost Trap, Explosive Trap, and Snake Trap .... -    if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && m_spellInfo->SpellFamilyFlags & 0x0000200000000014LL) +    if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && (m_spellInfo->SpellFamilyFlags[1] & 0x00002000 || m_spellInfo->SpellFamilyFlags[0] & 0x1C))          m_procAttacker |= PROC_FLAG_ON_TRAP_ACTIVATION;  } @@ -702,8 +741,6 @@ void Spell::CleanupTargetList()      m_UniqueTargetInfo.clear();      m_UniqueGOTargetInfo.clear();      m_UniqueItemInfo.clear(); -    m_countOfHit = 0; -    m_countOfMiss = 0;      m_delayMoment = 0;  } @@ -712,6 +749,9 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)      if( m_spellInfo->Effect[effIndex]==0 )          return; +    // Check for effect immune skip if immuned +    bool immuned = pVictim->IsImmunedToSpellEffect(m_spellInfo, effIndex); +      uint64 targetGUID = pVictim->GetGUID();      // Lookup target in already in list @@ -719,7 +759,8 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)      {          if (targetGUID == ihit->targetGUID)                 // Found in list          { -            ihit->effectMask |= 1<<effIndex;                // Add only effect mask +            if (!immuned) +                ihit->effectMask |= 1<<effIndex;            // Add only effect mask if not immuned              return;          }      } @@ -729,7 +770,7 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)      // Get spell hit result on target      TargetInfo target;      target.targetGUID = targetGUID;                         // Store target GUID -    target.effectMask = 1<<effIndex;                        // Store index of effect +    target.effectMask = immuned ? 0 : 1<<effIndex;          // Store index of effect if not immuned      target.processed  = false;                              // Effects not apply on target      target.damage     = 0; @@ -743,11 +784,6 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)      else          target.missCondition = SPELL_MISS_EVADE; //SPELL_MISS_NONE; -    if (target.missCondition == SPELL_MISS_NONE) -        ++m_countOfHit; -    else -        ++m_countOfMiss; -      // Spell have speed - need calculate incoming time      if (m_spellInfo->speed > 0.0f)      { @@ -828,8 +864,6 @@ void Spell::AddGOTarget(GameObject* pVictim, uint32 effIndex)      else          target.timeDelay = 0LL; -    ++m_countOfHit; -      // Add target to list      m_UniqueGOTargetInfo.push_back(target);  } @@ -863,83 +897,6 @@ void Spell::AddItemTarget(Item* pitem, uint32 effIndex)      target.effectMask = 1<<effIndex;      m_UniqueItemInfo.push_back(target);  } -/* -void Spell::doTriggers(SpellMissInfo missInfo, uint32 damage, SpellSchoolMask damageSchoolMask, uint32 block, uint32 absorb, bool crit) -{ -    // Do triggers depends from hit result (triggers on hit do in effects) -    // Set aura states depends from hit result -    if (missInfo!=SPELL_MISS_NONE) -    { -        // Miss/dodge/parry/block only for melee based spells -        // Resist only for magic based spells -        switch (missInfo) -        { -            case SPELL_MISS_MISS: -                if(m_caster->GetTypeId()== TYPEID_PLAYER) -                    ((Player*)m_caster)->UpdateWeaponSkill(BASE_ATTACK); - -                m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_MISS, m_spellInfo, m_IsTriggeredSpell); -                break; -            case SPELL_MISS_RESIST: -                m_caster->ProcDamageAndSpell(unitTarget, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, damageSchoolMask, m_spellInfo, m_IsTriggeredSpell); -                break; -            case SPELL_MISS_DODGE: -                if(unitTarget->GetTypeId() == TYPEID_PLAYER) -                    ((Player*)unitTarget)->UpdateDefense(); - -                // Overpower -                if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->getClass() == CLASS_WARRIOR) -                { -                    ((Player*) m_caster)->AddComboPoints(unitTarget, 1); -                    m_caster->StartReactiveTimer( REACTIVE_OVERPOWER ); -                } - -                // Riposte -                if (unitTarget->getClass() != CLASS_ROGUE) -                { -                    unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true); -                    unitTarget->StartReactiveTimer( REACTIVE_DEFENSE ); -                } - -                m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_DODGE, m_spellInfo, m_IsTriggeredSpell); -                break; -            case SPELL_MISS_PARRY: -                // Update victim defense ? -                if(unitTarget->GetTypeId() == TYPEID_PLAYER) -                    ((Player*)unitTarget)->UpdateDefense(); -                // Mongoose bite - set only Counterattack here -                if (unitTarget->getClass() == CLASS_HUNTER) -                { -                    unitTarget->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true); -                    unitTarget->StartReactiveTimer( REACTIVE_HUNTER_PARRY ); -                } -                else -                { -                    unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true); -                    unitTarget->StartReactiveTimer( REACTIVE_DEFENSE ); -                } -                m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_PARRY, m_spellInfo, m_IsTriggeredSpell); -                break; -            case SPELL_MISS_BLOCK: -                unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true); -                unitTarget->StartReactiveTimer( REACTIVE_DEFENSE ); - -                m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_BLOCK, m_spellInfo, m_IsTriggeredSpell); -                break; -                // Trigger from this events not supported -            case SPELL_MISS_EVADE: -            case SPELL_MISS_IMMUNE: -            case SPELL_MISS_IMMUNE2: -            case SPELL_MISS_DEFLECT: -            case SPELL_MISS_ABSORB: -                // Trigger from reflects need do after get reflect result -            case SPELL_MISS_REFLECT: -                break; -            default: -                break; -        } -    } -}*/  void Spell::DoAllEffectOnTarget(TargetInfo *target)  { @@ -949,15 +906,13 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)      // Get mask of effects for target      uint32 mask = target->effectMask; -    if (mask == 0)                                          // No effects -        return;      Unit* unit = m_caster->GetGUID()==target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster,target->targetGUID);      if (!unit)          return;      // Get original caster (if exist) and calculate damage/healing from him data -    Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; +    Unit *caster = m_originalCaster ? m_originalCaster : m_caster;      // Skip if m_originalCaster not avaiable      if (!caster) @@ -1005,7 +960,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)          if (crit)          {              procEx |= PROC_EX_CRITICAL_HIT; -            addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, NULL); +            addhealth = caster->SpellCriticalHealingBonus(m_spellInfo, addhealth, NULL);          }          else              procEx |= PROC_EX_NORMAL_HIT; @@ -1044,44 +999,12 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)          caster->DealSpellDamage(&damageInfo, true); -        // Shadow Word: Death - deals damage equal to damage done to caster if victim is not killed -        if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellInfo->SpellFamilyFlags&0x0000000200000000LL && -            caster != unitTarget && unitTarget->isAlive()) -        { -            // Redirect damage to caster if victim Alive -            damageInfo.target = caster; -            damageInfo.absorb = 0; -            damageInfo.resist = 0; -            damageInfo.blocked = 0; -            // Send log damage message to client -            caster->SendSpellNonMeleeDamageLog(&damageInfo); -            caster->DealSpellDamage(&damageInfo, true); -        }          // Judgement of Blood -        else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL && m_spellInfo->SpellIconID==153) +        if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && m_spellInfo->SpellFamilyFlags[1] & 0x00000008 && m_spellInfo->SpellIconID==153)          {              int32 damagePoint  = damageInfo.damage * 33 / 100;              m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true);          } -        // Bloodthirst -        else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellInfo->SpellFamilyFlags & 0x40000000000LL) -        { -            uint32 BTAura = 0; -            switch(m_spellInfo->Id) -            { -                case 23881: BTAura = 23885; break; -                case 23892: BTAura = 23886; break; -                case 23893: BTAura = 23887; break; -                case 23894: BTAura = 23888; break; -                case 25251: BTAura = 25252; break; -                case 30335: BTAura = 30339; break; -                default: -                    sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id); -                    break; -            } -            if (BTAura) -                m_caster->CastSpell(m_caster,BTAura,true); -        }      }      // Passive spell hits/misses or active spells only misses (only triggers)      else @@ -1105,14 +1028,14 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)      if( !m_caster->IsFriendlyTo(unit) && !IsPositiveSpell(m_spellInfo->Id))      { -        if( !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) ) +        if( !(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO) )          {              m_caster->CombatStart(unit);          }          else if(m_customAttr & SPELL_ATTR_CU_AURA_CC)          {              if(!unit->IsStandState()) -                unit->SetStandState(PLAYER_STATE_NONE); +                unit->SetStandState(UNIT_STAND_STATE_STAND);          }      }  } @@ -1125,25 +1048,37 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)      // Recheck immune (only for delayed spells)      if( m_spellInfo->speed &&          !(m_spellInfo->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) -        && (unit->IsImmunedToDamage(GetSpellSchoolMask(m_spellInfo),true) || -        unit->IsImmunedToSpell(m_spellInfo,true) )) +        && (unit->IsImmunedToDamage(GetSpellSchoolMask(m_spellInfo)) || +        unit->IsImmunedToSpell(m_spellInfo)))      {          m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_IMMUNE);          m_damage = 0;          return;      } +    if (unit->GetTypeId() == TYPEID_PLAYER) +    { +        ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, m_spellInfo->Id); +        ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, m_spellInfo->Id); +    } + +    if(m_caster->GetTypeId() == TYPEID_PLAYER) +    { +        ((Player*)m_caster)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, m_spellInfo->Id, 0, unit); +    } +      if( m_caster != unit )      { -        if (unit->GetCharmerOrOwnerGUID() != m_caster->GetGUID()) +        // Recheck  UNIT_FLAG_NON_ATTACKABLE for delayed spells +        if (m_spellInfo->speed > 0.0f && +            unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE) && +            unit->GetCharmerOrOwnerGUID() != m_caster->GetGUID())          { -            if (unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) -            { -                m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE); +            m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE);                  m_damage = 0; -                return; -            } +            return;          } +          if( !m_caster->IsFriendlyTo(unit) )          {              // for delayed spells ignore not visible explicit target @@ -1172,7 +1107,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)              // assisting case, healing and resurrection              if(unit->hasUnitState(UNIT_STAT_ATTACK_PLAYER))                  m_caster->SetContestedPvP(); -            if( unit->isInCombat() && !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) ) +            if( unit->isInCombat() && !(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO) )              {                  m_caster->SetInCombatState(unit->GetCombatTimer() > 0);                  unit->getHostilRefManager().threatAssist(m_caster, 0.0f); @@ -1190,6 +1125,10 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)              unit->IncrDiminishing(m_diminishGroup);      } +    // Apply additional spell effects to target +    if (m_preCastSpell) +        m_caster->CastSpell(unit,m_preCastSpell, true, m_CastItem); +      for(uint32 effectNumber=0;effectNumber<3;effectNumber++)      {          if (effectMask & (1<<effectNumber)) @@ -1349,6 +1288,16 @@ void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uin      if(!cur)          return; +    // Get spell max affected targets +    /*uint32 unMaxTargets = m_spellInfo->MaxAffectedTargets; +    Unit::AuraList const& mod = m_caster->GetAurasByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS); +    for(Unit::AuraList::const_iterator m = mod.begin(); m != mod.end(); ++m) +    { +        if (!(*m)->isAffectedOnSpell(m_spellInfo)) +            continue; +        unMaxTargets+=(*m)->GetModifier()->m_amount; +    }*/ +      //FIXME: This very like horrible hack and wrong for most spells      if(m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE)          max_range += num * CHAIN_SPELL_JUMP_RADIUS; @@ -1460,7 +1409,7 @@ Unit* Spell::SearchNearbyTarget(float radius, SpellTargets TargetType, uint32 en              {                  Creature* target = NULL;                  Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster, entry, true, radius); -                Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(target, u_check); +                Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(m_caster, target, u_check);                  m_caster->VisitNearbyObject(radius, searcher);                  return target;              } @@ -1474,13 +1423,13 @@ Unit* Spell::SearchNearbyTarget(float radius, SpellTargets TargetType, uint32 en          case SPELL_TARGETS_ENEMY:          {              Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, radius); -            Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(target, u_check); +            Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(m_caster, target, u_check);              m_caster->VisitNearbyObject(radius, searcher);          }break;          case SPELL_TARGETS_ALLY:          {              Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, radius); -            Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(target, u_check); +            Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(m_caster, target, u_check);              m_caster->VisitNearbyObject(radius, searcher);          }break;      } @@ -1489,21 +1438,35 @@ Unit* Spell::SearchNearbyTarget(float radius, SpellTargets TargetType, uint32 en  void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)  { -    float radius; +    float radius_h, radius_f;      if (m_spellInfo->EffectRadiusIndex[i]) -        radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); +    { +        radius_h = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); +        radius_f = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); +    }      else -        radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); +    { +        radius_h = GetSpellMaxRangeForHostile(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); +        radius_f = GetSpellMaxRangeForFriend(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); +    }      //Chain: 2, 6, 22, 25, 45, 77      uint32 EffectChainTarget = m_spellInfo->EffectChainTarget[i];      uint32 unMaxTargets = m_spellInfo->MaxAffectedTargets; +    Unit::AuraList const& Auras = m_caster->GetAurasByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS); +    for(Unit::AuraList::const_iterator j = Auras.begin();j != Auras.end(); ++j) +    { +        if((*j)->isAffectedOnSpell(m_spellInfo)) +            unMaxTargets+=(*j)->GetModifier()->m_amount; +    } +      if(m_originalCaster)      {          if(Player* modOwner = m_originalCaster->GetSpellModOwner())          { -            modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius,this); +            modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius_f,this); +            modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius_h,this);              modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, EffectChainTarget, this);          }      } @@ -1534,13 +1497,14 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)                          TagUnitMap.push_back(pet);                      break;                  case TARGET_UNIT_PARTY_CASTER: -                    m_caster->GetPartyMember(TagUnitMap, radius); +                    m_caster->GetPartyMember(TagUnitMap, radius_f);                      break;                  case TARGET_UNIT_RAID: -                    if(Unit *target = m_targets.getUnitTarget()) -                        TagUnitMap.push_back(target); -                    else -                        m_caster->GetRaidMember(TagUnitMap, radius); +                    //if(Unit *target = m_targets.getUnitTarget()) +                    //    TagUnitMap.push_back(target); +                    //else +                    m_caster->GetRaidMember(TagUnitMap, radius_f); +                    TagUnitMap.push_back(m_caster);                      break;              }          }break; @@ -1564,23 +1528,22 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)                  case TARGET_UNIT_TARGET_RAID:                  case TARGET_UNIT_TARGET_ANY: // SelectMagnetTarget()?                  case TARGET_UNIT_TARGET_PARTY: -                case TARGET_UNIT_SINGLE_UNKNOWN:                      TagUnitMap.push_back(target);                      break;                  case TARGET_UNIT_PARTY_TARGET: -                    target->GetPartyMember(TagUnitMap, radius); +                    target->GetPartyMember(TagUnitMap, radius_f);                      break;                  case TARGET_UNIT_TARGET_ENEMY:                      if(EffectChainTarget <= 1)                          TagUnitMap.push_back(SelectMagnetTarget());                      else if(SelectMagnetTarget())   //TODO: chain target should also use magnet target -                        SearchChainTarget(TagUnitMap, radius, EffectChainTarget, SPELL_TARGETS_ENEMY); +                        SearchChainTarget(TagUnitMap, radius_h, EffectChainTarget, SPELL_TARGETS_ENEMY);                      break;                  case TARGET_UNIT_CHAINHEAL:                      if(EffectChainTarget <= 1)                          TagUnitMap.push_back(target);                      else -                        SearchChainTarget(TagUnitMap, radius, EffectChainTarget, SPELL_TARGETS_CHAINHEAL); +                        SearchChainTarget(TagUnitMap, radius_f, EffectChainTarget, SPELL_TARGETS_CHAINHEAL);                      break;              }          }break; @@ -1627,17 +1590,17 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)                  case TARGET_UNIT_AREA_ENEMY_GROUND:                      m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION;                  case TARGET_UNIT_AREA_ENEMY: -                    SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_ENEMY); +                    SearchAreaTarget(TagUnitMap, radius_h, PUSH_DEST_CENTER, SPELL_TARGETS_ENEMY);                      break;                  case TARGET_UNIT_AREA_ALLY_GROUND:                      m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION;                  case TARGET_UNIT_AREA_ALLY: -                    SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_ALLY); +                    SearchAreaTarget(TagUnitMap, radius_f, PUSH_DEST_CENTER, SPELL_TARGETS_ALLY);                      break;                  case TARGET_UNIT_AREA_PARTY_GROUND:                      m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION;                  case TARGET_UNIT_AREA_PARTY: -                    m_caster->GetPartyMember(TagUnitMap, radius); +                    m_caster->GetPartyMember(TagUnitMap, radius_f);                      break;                  case TARGET_UNIT_AREA_ENTRY_GROUND:                      m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION; @@ -1647,7 +1610,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)                      SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id);                      if(lower==upper)                      { -                        SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_ENEMY); +                        SearchAreaTarget(TagUnitMap, radius_h, PUSH_DEST_CENTER, SPELL_TARGETS_ENEMY);                          sLog.outErrorDb("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry());                          break;                      } @@ -1659,7 +1622,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)                              sLog.outError( "SPELL: spell ID %u requires non-creature target\n", m_spellInfo->Id );                              continue;                          } -                        SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_ENTRY, i_spellST->second.targetEntry); +                        SearchAreaTarget(TagUnitMap, radius_f, PUSH_DEST_CENTER, SPELL_TARGETS_ENTRY, i_spellST->second.targetEntry);                      }                  }                  break; @@ -1703,41 +1666,41 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)                  m_targets.setDestination(((Player*)m_caster)->m_homebindX,((Player*)m_caster)->m_homebindY,((Player*)m_caster)->m_homebindZ, true, ((Player*)m_caster)->m_homebindMapId);              break; -          case TARGET_IN_FRONT_OF_CASTER:          case TARGET_UNIT_CONE_ENEMY_UNKNOWN:              if(m_customAttr & SPELL_ATTR_CU_CONE_BACK) -                SearchAreaTarget(TagUnitMap, radius, PUSH_IN_BACK, SPELL_TARGETS_ENEMY); +                SearchAreaTarget(TagUnitMap, radius_h, PUSH_IN_BACK, SPELL_TARGETS_ENEMY);              else if(m_customAttr & SPELL_ATTR_CU_CONE_LINE) -                SearchAreaTarget(TagUnitMap, radius, PUSH_IN_LINE, SPELL_TARGETS_ENEMY); +                SearchAreaTarget(TagUnitMap, radius_h, PUSH_IN_LINE, SPELL_TARGETS_ENEMY);              else -                SearchAreaTarget(TagUnitMap, radius, PUSH_IN_FRONT, SPELL_TARGETS_ENEMY); +                SearchAreaTarget(TagUnitMap, radius_h, PUSH_IN_FRONT, SPELL_TARGETS_ENEMY);              break;          case TARGET_UNIT_CONE_ALLY: -            SearchAreaTarget(TagUnitMap, radius, PUSH_IN_FRONT, SPELL_TARGETS_ALLY); +            SearchAreaTarget(TagUnitMap, radius_f, PUSH_IN_FRONT, SPELL_TARGETS_ALLY);              break;          // nearby target          case TARGET_UNIT_NEARBY_ALLY: +        case TARGET_UNIT_NEARBY_ALLY_UNK:              if(!m_targets.getUnitTarget()) -                m_targets.setUnitTarget(SearchNearbyTarget(radius, SPELL_TARGETS_ALLY)); +                m_targets.setUnitTarget(SearchNearbyTarget(radius_f, SPELL_TARGETS_ALLY));              if(m_targets.getUnitTarget())              {                  if(EffectChainTarget <= 1)                      TagUnitMap.push_back(m_targets.getUnitTarget());                  else -                    SearchChainTarget(TagUnitMap, radius, EffectChainTarget, SPELL_TARGETS_ALLY); +                    SearchChainTarget(TagUnitMap, radius_f, EffectChainTarget, SPELL_TARGETS_ALLY);              }              break; -        case TARGET_RANDOM_ENEMY_CHAIN_IN_AREA: +        case TARGET_UNIT_NEARBY_ENEMY:              if(!m_targets.getUnitTarget()) -                m_targets.setUnitTarget(SearchNearbyTarget(radius, SPELL_TARGETS_ENEMY)); +                m_targets.setUnitTarget(SearchNearbyTarget(radius_h, SPELL_TARGETS_ENEMY));              if(m_targets.getUnitTarget())              {                  if(EffectChainTarget <= 1)                      TagUnitMap.push_back(m_targets.getUnitTarget());                  else -                    SearchChainTarget(TagUnitMap, radius, EffectChainTarget, SPELL_TARGETS_ENEMY); +                    SearchChainTarget(TagUnitMap, radius_h, EffectChainTarget, SPELL_TARGETS_ENEMY);              }              break;          case TARGET_SCRIPT: @@ -1754,7 +1717,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)              }              SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); -            float range = GetSpellMaxRange(srange); +            float range = GetSpellMaxRangeForHostile(srange);              Creature* creatureScriptTarget = NULL;              GameObject* goScriptTarget = NULL; @@ -1770,7 +1733,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)                          if(i_spellST->second.targetEntry)                          {                              Trinity::NearestGameObjectEntryInObjectRangeCheck go_check(*m_caster,i_spellST->second.targetEntry,range); -                            Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(p_GameObject,go_check); +                            Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(m_caster, p_GameObject,go_check);                              m_caster->VisitNearbyGridObject(range, checker);                              if(p_GameObject) @@ -1800,7 +1763,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)                          Creature *p_Creature = NULL;                          Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type!=SPELL_TARGET_TYPE_DEAD,range); -                        Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(p_Creature, u_check); +                        Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(m_caster, p_Creature, u_check);                          m_caster->VisitNearbyObject(range, searcher);                          if(p_Creature ) @@ -1849,7 +1812,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)                      Player* Target = itr->getSource();                      // IsHostileTo check duel and controlled by enemy -                    if( Target && targetPlayer->IsWithinDistInMap(Target, radius) && +                    if( Target && targetPlayer->IsWithinDistInMap(Target, radius_f) &&                          targetPlayer->getClass() == Target->getClass() &&                          !m_caster->IsHostileTo(Target) )                      { @@ -1880,7 +1843,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)              float x, y, z, angle, dist;              float objSize = m_caster->GetObjectSize(); -            dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); +            dist = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));              if(dist < objSize)                  dist = objSize;              else if(cur == TARGET_DEST_CASTER_RANDOM) @@ -1928,7 +1891,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)              float x, y, z, angle, dist;              float objSize = target->GetObjectSize(); -            dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); +            dist = target->GetSpellRadiusForTarget(target, sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));              if(dist < objSize)                  dist = objSize;              else if(cur == TARGET_DEST_CASTER_RANDOM) @@ -1964,7 +1927,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)              float x, y, z, angle, dist; -            dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); +            dist = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));              if (cur == TARGET_DEST_DEST_RANDOM)                  dist *= rand_norm(); @@ -2016,7 +1979,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)      }  } -void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura) +void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura)  {      if(m_CastItem)          m_castItemGUID = m_CastItem->GetGUID(); @@ -2038,7 +2001,7 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)      m_caster->m_Events.AddEvent(Event, m_caster->m_Events.CalculateTime(1));      //Prevent casting at cast another spell (ServerSide check) -    if(m_caster->IsNonMeleeSpellCasted(false, true) && m_cast_count) +    if(m_caster->IsNonMeleeSpellCasted(false, true, true) && m_cast_count)      {          SendCastResult(SPELL_FAILED_SPELL_IN_PROGRESS);          finish(false); @@ -2131,11 +2094,11 @@ void Spell::cancel()                  {                      Unit* unit = m_caster->GetGUID()==(*ihit).targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);                      if( unit && unit->isAlive() ) -                        unit->RemoveAurasDueToCasterSpell(m_spellInfo->Id, m_caster->GetGUID()); +                        unit->RemoveAurasByCasterSpell(m_spellInfo->Id, m_caster->GetGUID());                  }              } -            m_caster->RemoveAurasDueToCasterSpell(m_spellInfo->Id, m_caster->GetGUID()); +            m_caster->RemoveAurasByCasterSpell(m_spellInfo->Id, m_caster->GetGUID());              SendChannelUpdate(0);              SendInterrupted(0);              SendCastResult(SPELL_FAILED_INTERRUPTED); @@ -2218,16 +2181,43 @@ void Spell::cast(bool skipCheck)      FillTargetMap(); -    if(m_spellState == SPELL_STATE_FINISHED)                // stop cast if spell marked as finish somewhere in Take*/FillTargetMap +    if(m_spellInfo->SpellFamilyName)      { -        SetExecutedCurrently(false); -        return; +        if (m_spellInfo->excludeCasterAuraSpell) +            m_preCastSpell = m_spellInfo->excludeCasterAuraSpell; +        else if (m_spellInfo->excludeTargetAuraSpell) +            m_preCastSpell = m_spellInfo->excludeTargetAuraSpell;      } +    switch (m_spellInfo->SpellFamilyName) +    { +        case SPELLFAMILY_GENERIC: +        { +            if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages +                m_preCastSpell = 11196;                                // Recently Bandaged +            else if(m_spellInfo->SpellIconID == 1662 && m_spellInfo->AttributesEx & 0x20) +                m_preCastSpell = 23230;                                // Blood Fury - Healing Reduction +            break; +        } +        case SPELLFAMILY_PRIEST: +        { +            if (m_spellInfo->Id == 47585)                              // Dispersion (transform) +                m_preCastSpell = 60069;                                // Dispersion (mana regen) +            break; +        } +    }      // traded items have trade slot instead of guid in m_itemTargetGUID      // set to real guid to be sent later to the client      m_targets.updateTradeSlotItem(); +    if (m_caster->GetTypeId() == TYPEID_PLAYER) +    { +        if (m_CastItem) +            ((Player*)m_caster)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM, m_CastItem->GetEntry()); + +        ((Player*)m_caster)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, m_spellInfo->Id); +    } +      if(!m_IsTriggeredSpell)      {          //TakePower(); @@ -2242,21 +2232,20 @@ void Spell::cast(bool skipCheck)      if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE)          CalculateDamageDoneForAllTargets(); -    //handle SPELL_AURA_ADD_TARGET_TRIGGER auras      //are there any spells need to be triggered after hit? +    // handle SPELL_AURA_ADD_TARGET_TRIGGER auras      Unit::AuraList const& targetTriggers = m_caster->GetAurasByType(SPELL_AURA_ADD_TARGET_TRIGGER);      for(Unit::AuraList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i)      { +        if (!(*i)->isAffectedOnSpell(m_spellInfo)) +            continue;          SpellEntry const *auraSpellInfo = (*i)->GetSpellProto();          uint32 auraSpellIdx = (*i)->GetEffIndex(); -        if (IsAffectedBy(auraSpellInfo, auraSpellIdx)) +        if(SpellEntry const *spellInfo = sSpellStore.LookupEntry(auraSpellInfo->EffectTriggerSpell[auraSpellIdx]))          { -            if(SpellEntry const *spellInfo = sSpellStore.LookupEntry(auraSpellInfo->EffectTriggerSpell[auraSpellIdx])) -            { -                // Calculate chance at that moment (can be depend for example from combo points) -                int32 chance = m_caster->CalculateSpellDamage(auraSpellInfo, auraSpellIdx, (*i)->GetBasePoints(), NULL); -                m_ChanceTriggerSpells.push_back(std::make_pair(spellInfo, chance * (*i)->GetStackAmount())); -            } +            // Calculate chance at that moment (can be depend for example from combo points) +            int32 chance = m_caster->CalculateSpellDamage(auraSpellInfo, auraSpellIdx, (*i)->GetBasePoints(), NULL); +            m_ChanceTriggerSpells.push_back(std::make_pair(spellInfo, chance * (*i)->GetStackAmount()));          }      } @@ -2305,9 +2294,18 @@ void Spell::handle_immediate()      // start channeling if applicable      if(IsChanneledSpell(m_spellInfo))      { -        m_spellState = SPELL_STATE_CASTING; -        m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags); -        SendChannelStart(GetSpellDuration(m_spellInfo)); +        int32 duration = GetSpellDuration(m_spellInfo); +        if (duration) +        { +            //apply haste mods +            m_caster->ModSpellCastTime(m_spellInfo, duration); +            // Apply duration mod +            if(Player* modOwner = m_caster->GetSpellModOwner()) +                modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); +            m_spellState = SPELL_STATE_CASTING; +            m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags); +            SendChannelStart(duration); +        }      }      // process immediate effects (items, ground, etc.) also initialize some variables @@ -2488,7 +2486,7 @@ void Spell::SendSpellCooldown()      // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)      // prevent 0 cooldowns set by another way -    if (rec <= 0 && catrec <= 0 && (cat == 76 || cat == 351)) +    if (rec <= 0 && catrec <= 0 && (cat == 76 || IsAutoRepeatRangedSpell(m_spellInfo) && m_spellInfo->Id != SPELL_ID_AUTOSHOT))          rec = _player->GetAttackTime(RANGED_ATTACK);      // Now we have cooldown data (if found any), time to apply mods @@ -2526,7 +2524,7 @@ void Spell::SendSpellCooldown()                  if(*i_scset == m_spellInfo->Id)             // skip main spell, already handled above                      continue; -                _player->AddSpellCooldown(m_spellInfo->Id, m_CastItem ? m_CastItem->GetEntry() : 0, catrecTime); +                _player->AddSpellCooldown(*i_scset, m_CastItem ? m_CastItem->GetEntry() : 0, catrecTime);              }          }      } @@ -2704,9 +2702,9 @@ void Spell::SendCastResult(uint8 result)      if(result != 0)      {          WorldPacket data(SMSG_CAST_FAILED, (4+1+1)); +        data << uint8(m_cast_count);                        // single cast or multi 2.3 (0/1)          data << uint32(m_spellInfo->Id);          data << uint8(result);                              // problem -        data << uint8(m_cast_count);                        // single cast or multi 2.3 (0/1)          switch (result)          {              case SPELL_FAILED_REQUIRES_SPELL_FOCUS: @@ -2727,8 +2725,8 @@ void Spell::SendCastResult(uint8 result)                      case 45373:                             // Bloodberry Elixir                          data << uint32(4075);                          break; -                    default:                                // default case -                        data << uint32(m_spellInfo->AreaId); +                    default:                                // default case (don't must be) +                        data << uint32(0);                          break;                  }                  break; @@ -2747,18 +2745,11 @@ void Spell::SendCastResult(uint8 result)              case SPELL_FAILED_EQUIPPED_ITEM_CLASS:                  data << uint32(m_spellInfo->EquippedItemClass);                  data << uint32(m_spellInfo->EquippedItemSubClassMask); -                data << uint32(m_spellInfo->EquippedItemInventoryTypeMask); +                //data << uint32(m_spellInfo->EquippedItemInventoryTypeMask);                  break;          }          ((Player*)m_caster)->GetSession()->SendPacket(&data);      } -    else -    { -        WorldPacket data(SMSG_CLEAR_EXTRA_AURA_INFO, (8+4)); -        data.append(m_caster->GetPackGUID()); -        data << uint32(m_spellInfo->Id); -        ((Player*)m_caster)->GetSession()->SendPacket(&data); -    }  }  void Spell::SendSpellStart() @@ -2772,6 +2763,9 @@ void Spell::SendSpellStart()      if(IsRangedSpell())          castFlags |= CAST_FLAG_AMMO; +    if(m_spellInfo->runeCostID) +        castFlags |= CAST_FLAG_UNKNOWN10; +      Unit *target = m_targets.getUnitTarget() ? m_targets.getUnitTarget() : m_caster;      WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2)); @@ -2781,14 +2775,32 @@ void Spell::SendSpellStart()          data.append(m_caster->GetPackGUID());      data.append(m_caster->GetPackGUID()); -    data << uint32(m_spellInfo->Id); -    data << uint8(m_cast_count);                            // single cast or multi 2.3 (0/1) -    data << uint16(castFlags); -    data << uint32(m_timer); +    data << uint8(m_cast_count);                            // pending spell cast? +    data << uint32(m_spellInfo->Id);                        // spellId +    data << uint32(castFlags);                              // cast flags +    data << uint32(m_timer);                                // delay?      m_targets.write(&data); -    if( castFlags & CAST_FLAG_AMMO ) +    if ( castFlags & CAST_FLAG_UNKNOWN6 )                   // predicted power? +        data << uint32(0); + +    if ( castFlags & CAST_FLAG_UNKNOWN7 )                   // rune cooldowns list +    { +        uint8 v1 = 0;//m_runesState; +        uint8 v2 = 0;//((Player*)m_caster)->GetRunesState(); +        data << uint8(v1);                                  // runes state before +        data << uint8(v2);                                  // runes state after +        for(uint8 i = 0; i < MAX_RUNES; ++i) +        { +            uint8 m = (1 << i); +            if(m & v1)                                      // usable before... +                if(!(m & v2))                               // ...but on cooldown now... +                    data << uint8(0);                       // some unknown byte (time?) +        } +    } + +    if ( castFlags & CAST_FLAG_AMMO )          WriteAmmoToPacket(&data);      m_caster->SendMessageToSet(&data, true); @@ -2808,24 +2820,68 @@ void Spell::SendSpellGo()      if(IsRangedSpell())          castFlags |= CAST_FLAG_AMMO;                        // arrows/bullets visual +    if((m_caster->GetTypeId() == TYPEID_PLAYER) && (m_caster->getClass() == CLASS_DEATH_KNIGHT) && m_spellInfo->runeCostID) +    { +        castFlags |= CAST_FLAG_UNKNOWN10;                   // same as in SMSG_SPELL_START +        castFlags |= CAST_FLAG_UNKNOWN6;                    // makes cooldowns visible +        castFlags |= CAST_FLAG_UNKNOWN7;                    // rune cooldowns list +    } +      WorldPacket data(SMSG_SPELL_GO, 50);                    // guess size +      if(m_CastItem)          data.append(m_CastItem->GetPackGUID());      else          data.append(m_caster->GetPackGUID());      data.append(m_caster->GetPackGUID()); -    data << uint32(m_spellInfo->Id); -    data << uint16(castFlags); +    data << uint8(m_cast_count);                            // pending spell cast? +    data << uint32(m_spellInfo->Id);                        // spellId +    data << uint32(castFlags);                              // cast flags      data << uint32(getMSTime());                            // timestamp      WriteSpellGoTargets(&data);      m_targets.write(&data); -    if( castFlags & CAST_FLAG_AMMO ) +    if ( castFlags & CAST_FLAG_UNKNOWN6 )                   // unknown wotlk, predicted power? +        data << uint32(0); + +    if ( castFlags & CAST_FLAG_UNKNOWN7 )                   // rune cooldowns list +    { +        uint8 v1 = m_runesState; +        uint8 v2 = ((Player*)m_caster)->GetRunesState(); +        data << uint8(v1);                                  // runes state before +        data << uint8(v2);                                  // runes state after +        for(uint8 i = 0; i < MAX_RUNES; ++i) +        { +            uint8 m = (1 << i); +            if(m & v1)                                      // usable before... +                if(!(m & v2))                               // ...but on cooldown now... +                    data << uint8(0);                       // some unknown byte (time?) +        } +    } + +    if ( castFlags & CAST_FLAG_UNKNOWN4 )                   // unknown wotlk +    { +        data << float(0); +        data << uint32(0); +    } + +    if ( castFlags & CAST_FLAG_AMMO )          WriteAmmoToPacket(&data); +    if ( castFlags & CAST_FLAG_UNKNOWN5 )                   // unknown wotlk +    { +        data << uint32(0); +        data << uint32(0); +    } + +    if ( m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION ) +    { +        data << uint8(0); +    } +      m_caster->SendMessageToSet(&data, true);  } @@ -2870,15 +2926,36 @@ void Spell::WriteAmmoToPacket( WorldPacket * data )  void Spell::WriteSpellGoTargets( WorldPacket * data )  { -    *data << (uint8)m_countOfHit; +    // This function also fill data for channeled spells: +    // m_needAliveTargetMask req for stop channelig if one target die +    uint32 hit  = m_UniqueGOTargetInfo.size(); // Always hits on GO +    uint32 miss = 0; +    for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) +    { +        if ((*ihit).effectMask == 0)                  // No effect apply - all immuned add state +        { +            // possibly SPELL_MISS_IMMUNE2 for this?? +            ihit->missCondition = SPELL_MISS_IMMUNE2; +            miss++; +        } +        else if ((*ihit).missCondition == SPELL_MISS_NONE) +            hit++; +        else +            miss++; +    } + +    *data << (uint8)hit;      for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)          if ((*ihit).missCondition == SPELL_MISS_NONE)       // Add only hits +        {              *data << uint64(ihit->targetGUID); +            m_needAliveTargetMask |=ihit->effectMask; +        }      for(std::list<GOTargetInfo>::iterator ighit= m_UniqueGOTargetInfo.begin();ighit != m_UniqueGOTargetInfo.end();++ighit)          *data << uint64(ighit->targetGUID);                 // Always hits -    *data << (uint8)m_countOfMiss; +    *data << (uint8)miss;      for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)      {          if( ihit->missCondition != SPELL_MISS_NONE )        // Add only miss @@ -2889,6 +2966,9 @@ void Spell::WriteSpellGoTargets( WorldPacket * data )                  *data << uint8(ihit->reflectResult);          }      } +    // Reset m_needAliveTargetMask for non channeled spell +    if(!IsChanneledSpell(m_spellInfo)) +        m_needAliveTargetMask = 0;  }  void Spell::SendLogExecute() @@ -2953,30 +3033,19 @@ void Spell::SendLogExecute()                          data << uint8(0);                      break;                  case SPELL_EFFECT_CREATE_ITEM: +                case SPELL_EFFECT_CREATE_ITEM_2:                      data << uint32(m_spellInfo->EffectItemType[0]);                      break;                  case SPELL_EFFECT_SUMMON: -                case SPELL_EFFECT_SUMMON_WILD: -                case SPELL_EFFECT_SUMMON_GUARDIAN:                  case SPELL_EFFECT_TRANS_DOOR:                  case SPELL_EFFECT_SUMMON_PET: -                case SPELL_EFFECT_SUMMON_POSSESSED: -                case SPELL_EFFECT_SUMMON_TOTEM:                  case SPELL_EFFECT_SUMMON_OBJECT_WILD:                  case SPELL_EFFECT_CREATE_HOUSE:                  case SPELL_EFFECT_DUEL: -                case SPELL_EFFECT_SUMMON_TOTEM_SLOT1: -                case SPELL_EFFECT_SUMMON_TOTEM_SLOT2: -                case SPELL_EFFECT_SUMMON_TOTEM_SLOT3: -                case SPELL_EFFECT_SUMMON_TOTEM_SLOT4: -                case SPELL_EFFECT_SUMMON_PHANTASM: -                case SPELL_EFFECT_SUMMON_CRITTER:                  case SPELL_EFFECT_SUMMON_OBJECT_SLOT1:                  case SPELL_EFFECT_SUMMON_OBJECT_SLOT2:                  case SPELL_EFFECT_SUMMON_OBJECT_SLOT3:                  case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: -                case SPELL_EFFECT_SUMMON_DEMON: -                case SPELL_EFFECT_150:                      if(Unit *unit = m_targets.getUnitTarget())                          data.append(unit->GetPackGUID());                      else if(m_targets.getItemTargetGUID()) @@ -2995,6 +3064,13 @@ void Spell::SendLogExecute()                      else                          data << uint8(0);                      break; +                case SPELL_EFFECT_RESURRECT: +                case SPELL_EFFECT_RESURRECT_NEW: +                    if(Unit *unit = m_targets.getUnitTarget()) +                        data.append(unit->GetPackGUID()); +                    else +                        data << uint8(0); +                    break;                  default:                      return;              } @@ -3008,13 +3084,16 @@ void Spell::SendInterrupted(uint8 result)  {      WorldPacket data(SMSG_SPELL_FAILURE, (8+4+1));      data.append(m_caster->GetPackGUID()); -    data << m_spellInfo->Id; -    data << result; +    data << uint8(m_cast_count); +    data << uint32(m_spellInfo->Id); +    data << uint8(result);      m_caster->SendMessageToSet(&data, true);      data.Initialize(SMSG_SPELL_FAILED_OTHER, (8+4));      data.append(m_caster->GetPackGUID()); -    data << m_spellInfo->Id; +    data << uint8(m_cast_count); +    data << uint32(m_spellInfo->Id); +    data << uint8(result);      m_caster->SendMessageToSet(&data, true);  } @@ -3082,10 +3161,19 @@ void Spell::SendChannelStart(uint32 duration)  void Spell::SendResurrectRequest(Player* target)  { -    WorldPacket data(SMSG_RESURRECT_REQUEST, (8+4+2+4)); -    data << m_caster->GetGUID(); -    data << uint32(1) << uint16(0) << uint32(1); +    // Both players and NPCs can resurrect using spells - have a look at creature 28487 for example +    // However, the packet structure differs slightly + +    const char* sentName = m_caster->GetTypeId()==TYPEID_PLAYER ?"":m_caster->GetNameForLocaleIdx(target->GetSession()->GetSessionDbLocaleIndex()); +    WorldPacket data(SMSG_RESURRECT_REQUEST, (8+4+strlen(sentName)+1+1+1)); +    data << uint64(m_caster->GetGUID()); +    data << uint32(strlen(sentName)+1); + +    data << sentName; +    data << uint8(0); + +    data << uint8(m_caster->GetTypeId()==TYPEID_PLAYER ?0:1);      target->GetSession()->SendPacket(&data);  } @@ -3138,7 +3226,7 @@ void Spell::TakeCastItem()                  if (charges)                  {                      (charges > 0) ? --charges : ++charges;  // abs(charges) less at 1 after use -                    if (proto->Stackable < 2) +                    if (proto->Stackable == 1)                          m_CastItem->SetSpellCharges(i, charges);                      m_CastItem->SetState(ITEM_CHANGED, (Player*)m_caster);                  } @@ -3177,6 +3265,12 @@ void Spell::TakePower()                      {                          if(ihit->missCondition != SPELL_MISS_NONE && ihit->missCondition != SPELL_MISS_MISS/* && ihit->targetGUID!=m_caster->GetGUID()*/)                              hit = false; +                        if (ihit->missCondition != SPELL_MISS_NONE) +                        { +                            //lower spell cost on fail (by talent aura) +                            if(Player *modOwner = ((Player*)m_caster)->GetSpellModOwner()) +                                modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_SPELL_COST_REFUND_ON_FAIL, m_powerCost); +                        }                          break;                      }          if(hit && NeedsComboPoints(m_spellInfo)) @@ -3198,6 +3292,12 @@ void Spell::TakePower()      Powers powerType = Powers(m_spellInfo->powerType); +    if(powerType == POWER_RUNE) +    { +        TakeRunePower(); +        return; +    } +      if(hit)          m_caster->ModifyPower(powerType, -m_powerCost);      else @@ -3208,6 +3308,145 @@ void Spell::TakePower()          m_caster->SetLastManaUse(getMSTime());  } +void Spell::TakeAmmo() +{ +    if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER) +    { +        Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK ); + +        // wands don't have ammo +        if(!pItem  || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND) +            return; + +        if( pItem->GetProto()->InventoryType == INVTYPE_THROWN ) +        { +            if(pItem->GetMaxStackCount()==1) +            { +                // decrease durability for non-stackable throw weapon +                ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED); +            } +            else +            { +                // decrease items amount for stackable throw weapon +                uint32 count = 1; +                ((Player*)m_caster)->DestroyItemCount( pItem, count, true); +            } +        } +        else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID)) +            ((Player*)m_caster)->DestroyItemCount(ammo, 1, true); +    } +} + +uint8 Spell::CheckRuneCost(uint32 runeCostID) +{ +    if(m_caster->GetTypeId() != TYPEID_PLAYER) +        return 0; + +    Player *plr = (Player*)m_caster; + +    if(plr->getClass() != CLASS_DEATH_KNIGHT) +        return 0; + +    SpellRuneCostEntry const *src = sSpellRuneCostStore.LookupEntry(runeCostID); + +    if(!src) +        return 0; + +    if(src->NoRuneCost()) +        return 0; + +    int32 runeCost[NUM_RUNE_TYPES];                         // blood, frost, unholy, death + +    for(uint32 i = 0; i < RUNE_DEATH; ++i) +    { +        runeCost[i] = src->RuneCost[i]; +    } + +    runeCost[RUNE_DEATH] = 0;                               // calculated later + +    for(uint32 i = 0; i < MAX_RUNES; ++i) +    { +        uint8 rune = plr->GetCurrentRune(i); +        if((plr->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0)) +        { +            runeCost[rune]--; +        } +    } + +    for(uint32 i = 0; i < RUNE_DEATH; ++i) +    { +        if(runeCost[i] > 0) +        { +            runeCost[RUNE_DEATH] += runeCost[i]; +        } +    } + +    if(runeCost[RUNE_DEATH] > 0) +        return SPELL_FAILED_NO_POWER;                       // not sure if result code is correct + +    return 0; +} + +void Spell::TakeRunePower() +{ +    if(m_caster->GetTypeId() != TYPEID_PLAYER) +        return; + +    Player *plr = (Player*)m_caster; + +    if(plr->getClass() != CLASS_DEATH_KNIGHT) +        return; + +    SpellRuneCostEntry const *src = sSpellRuneCostStore.LookupEntry(m_spellInfo->runeCostID); + +    if(!src || (src->NoRuneCost() && src->NoRunicPowerGain())) +        return; + +    m_runesState = plr->GetRunesState();                    // store previous state + +    int32 runeCost[NUM_RUNE_TYPES];                         // blood, frost, unholy, death + +    for(uint32 i = 0; i < RUNE_DEATH; ++i) +    { +        runeCost[i] = src->RuneCost[i]; +    } + +    runeCost[RUNE_DEATH] = 0;                               // calculated later + +    for(uint32 i = 0; i < MAX_RUNES; ++i) +    { +        uint8 rune = plr->GetCurrentRune(i); +        if((plr->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0)) +        { +            plr->SetRuneCooldown(i, RUNE_COOLDOWN);         // 5*2=10 sec +            runeCost[rune]--; +        } +    } + +    runeCost[RUNE_DEATH] = runeCost[RUNE_BLOOD] + runeCost[RUNE_UNHOLY] + runeCost[RUNE_FROST]; + +    if(runeCost[RUNE_DEATH] > 0) +    { +        for(uint32 i = 0; i < MAX_RUNES; ++i) +        { +            uint8 rune = plr->GetCurrentRune(i); +            if((plr->GetRuneCooldown(i) == 0) && (rune == RUNE_DEATH)) +            { +                plr->SetRuneCooldown(i, RUNE_COOLDOWN);     // 5*2=10 sec +                runeCost[rune]--; +                plr->ConvertRune(i, plr->GetBaseRune(i)); +                if(runeCost[RUNE_DEATH] == 0) +                    break; +            } +        } +    } + +    // you can gain some runic power when use runes +    float rp = src->runePowerGain;; +    rp *= sWorld.getRate(RATE_POWER_RUNICPOWER_INCOME); +    plr->ModifyPower(POWER_RUNIC_POWER, (int32)rp); +} +  void Spell::TakeReagents()  {      if(m_IsTriggeredSpell)                                  // reagents used in triggered spell removed by original spell or don't must be removed. @@ -3216,11 +3455,9 @@ void Spell::TakeReagents()      if (m_caster->GetTypeId() != TYPEID_PLAYER)          return; -    if (m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP && -        m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION)) -        return; -      Player* p_caster = (Player*)m_caster; +    if (p_caster->CanNoReagentCast(m_spellInfo)) +        return;      for(uint32 x=0;x<8;x++)      { @@ -3283,14 +3520,9 @@ void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTar      gameObjTarget = pGOTarget;      uint8 eff = m_spellInfo->Effect[i]; -    uint32 mechanic = m_spellInfo->EffectMechanic[i];      sLog.outDebug( "Spell: Effect : %u", eff); -    //Simply return. Do not display "immune" in red text on client -    if(unitTarget && unitTarget->IsImmunedToSpellEffect(eff, mechanic)) -        return; -      //we do not need DamageMultiplier here.      damage = CalculateDamage(i, NULL); @@ -3328,6 +3560,9 @@ uint8 Spell::CanCast(bool strict)      // check cooldowns to prevent cheating      if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id))      { +        //can cast triggered (by aura only?) spells while have this flag +        if (!m_IsTriggeredSpell && ((Player*)m_caster)->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY)) +            return SPELL_FAILED_SPELL_IN_PROGRESS;          if(m_triggeredByAuraSpell)              return SPELL_FAILED_DONT_REPORT;          else @@ -3344,19 +3579,55 @@ uint8 Spell::CanCast(bool strict)      // for now, ignore triggered spells      if( strict && !m_IsTriggeredSpell)      { -        // Cannot be used in this stance/form -        if(uint8 shapeError = GetErrorAtShapeshiftedCast(m_spellInfo, m_caster->m_form)) -            return shapeError; +        bool checkForm = true; +        // Ignore form req aura +        Unit::AuraList const& ignore = m_caster->GetAurasByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT); +        for(Unit::AuraList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) +        { +            if (!(*i)->isAffectedOnSpell(m_spellInfo)) +                continue; +            checkForm = false; +            break; +        } +        if (checkForm) +        { +            // Cannot be used in this stance/form +            if(uint8 shapeError = GetErrorAtShapeshiftedCast(m_spellInfo, m_caster->m_form)) +                return shapeError; -        if ((m_spellInfo->Attributes & SPELL_ATTR_ONLY_STEALTHED) && !(m_caster->HasStealthAura())) -            return SPELL_FAILED_ONLY_STEALTHED; +            if ((m_spellInfo->Attributes & SPELL_ATTR_ONLY_STEALTHED) && !(m_caster->HasStealthAura())) +                return SPELL_FAILED_ONLY_STEALTHED; +        } +    } + +    bool reqAuraState=true; +    Unit::AuraList const& stateAuras = m_caster->GetAurasByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE); +    for(Unit::AuraList::const_iterator j = stateAuras.begin();j != stateAuras.end(); ++j) +    { +        if((*j)->isAffectedOnSpell(m_spellInfo)) +        { +            reqAuraState=false; +            break; +        } +    } + +    if (reqAuraState) +    { +        // caster state requirements +        if(m_spellInfo->CasterAuraState && !m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraState))) +            return SPELL_FAILED_CASTER_AURASTATE; +        if(m_spellInfo->CasterAuraStateNot && m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraStateNot))) +            return SPELL_FAILED_CASTER_AURASTATE; + +        if(m_spellInfo->casterAuraSpell && !m_caster->HasAura(m_spellInfo->casterAuraSpell)) +            return SPELL_FAILED_CASTER_AURASTATE; +        if(m_spellInfo->excludeCasterAuraSpell && m_caster->HasAura(m_spellInfo->excludeCasterAuraSpell)) +            return SPELL_FAILED_CASTER_AURASTATE; + +        if(m_caster->isInCombat() && IsNonCombatSpell(m_spellInfo)) +            return SPELL_FAILED_AFFECTING_COMBAT;      } -    // caster state requirements -    if(m_spellInfo->CasterAuraState && !m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraState))) -        return SPELL_FAILED_CASTER_AURASTATE; -    if(m_spellInfo->CasterAuraStateNot && m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraStateNot))) -        return SPELL_FAILED_CASTER_AURASTATE;      // cancel autorepeat spells if cast start when moving      // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code) @@ -3372,14 +3643,23 @@ uint8 Spell::CanCast(bool strict)      if(target)      { -        // target state requirements (not allowed state), apply to self also -        if(m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot))) -            return SPELL_FAILED_TARGET_AURASTATE; +        if (reqAuraState) +        { +            // target state requirements (not allowed state), apply to self also +            if(m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot))) +                return SPELL_FAILED_TARGET_AURASTATE; + +            if(m_spellInfo->targetAuraSpell && !target->HasAura(m_spellInfo->targetAuraSpell)) +                return SPELL_FAILED_TARGET_AURASTATE; + +            if(m_spellInfo->excludeTargetAuraSpell && target->HasAura(m_spellInfo->excludeTargetAuraSpell)) +                return SPELL_FAILED_TARGET_AURASTATE; +        }          if(target != m_caster)          {              // target state requirements (apply to non-self only), to allow cast affects to self like Dirty Deeds -            if(m_spellInfo->TargetAuraState && !target->HasAuraState(AuraState(m_spellInfo->TargetAuraState))) +            if(reqAuraState && m_spellInfo->TargetAuraState && !target->HasAuraState(AuraState(m_spellInfo->TargetAuraState)))                  return SPELL_FAILED_TARGET_AURASTATE;              // Not allow casting on flying player @@ -3401,6 +3681,20 @@ uint8 Spell::CanCast(bool strict)                  }              }          } +        else if (m_caster->GetTypeId()==TYPEID_PLAYER) // Target - is player caster +        { +            // Additional check for some spells +            // If 0 spell effect empty - client not send target data (need use selection) +            // TODO: check it on next client version +            if (m_targets.m_targetMask == TARGET_FLAG_SELF && +                m_spellInfo->EffectImplicitTargetA[1] == TARGET_CHAIN_DAMAGE) +            { +                if (target = m_caster->GetUnit(*m_caster, ((Player *)m_caster)->GetSelection())) +                    m_targets.setUnitTarget(target); +                else +                    return SPELL_FAILED_BAD_TARGETS; +            } +        }          // check pet presents          for(int j=0;j<3;j++) @@ -3452,13 +3746,16 @@ uint8 Spell::CanCast(bool strict)          if(IsPositiveSpell(m_spellInfo->Id))          { -            if(target->IsImmunedToSpell(m_spellInfo,false)) +            if(target->IsImmunedToSpell(m_spellInfo))                  return SPELL_FAILED_TARGET_AURASTATE;          }          //Must be behind the target.          if( m_spellInfo->AttributesEx2 == 0x100000 && (m_spellInfo->AttributesEx & 0x200) == 0x200 && target->HasInArc(M_PI, m_caster) -            && (m_spellInfo->SpellFamilyName != SPELLFAMILY_DRUID || m_spellInfo->SpellFamilyFlags != 0x0000000000020000LL)) +            //Exclusion for Pounce: Facing Limitation was removed in 2.0.1, but it still uses the same, old Ex-Flags +            && (!(m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags.IsEqual(0x20000,0,0))) +            //Mutilate no longer requires you be behind the target as of patch 3.0.3 +            && (!(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && m_spellInfo->SpellFamilyFlags[1] & 0x200000)))          {              SendInterrupted(2);              return SPELL_FAILED_NOT_BEHIND; @@ -3492,8 +3789,9 @@ uint8 Spell::CanCast(bool strict)                  return SPELL_FAILED_NOT_IN_ARENA;      // zone check -    if(!IsSpellAllowedInLocation(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId())) -        return SPELL_FAILED_REQUIRES_AREA; +    if (uint8 res= GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId(), +        m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster)->GetBattleGroundId() : 0)) +        return res;      // not let players cast spells at mount (and let do it to creatures)      if( m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell && @@ -3546,7 +3844,7 @@ uint8 Spell::CanCast(bool strict)                                  cell.data.Part.reserved = ALL_DISTRICT;                                  MaNGOS::NearestGameObjectEntryInObjectRangeCheck go_check(*m_caster,i_spellST->second.targetEntry,range); -                                MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck> checker(p_GameObject,go_check); +                                MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck> checker(m_caster, p_GameObject,go_check);                                  TypeContainerVisitor<MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker);                                  CellLock<GridReadGuard> cell_lock(cell, p); @@ -3584,7 +3882,7 @@ uint8 Spell::CanCast(bool strict)                              cell.SetNoCreate();             // Really don't know what is that???                              MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type!=SPELL_TARGET_TYPE_DEAD,range); -                            MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(p_Creature, u_check); +                            MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(m_caster, p_Creature, u_check);                              TypeContainerVisitor<MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer >  grid_creature_searcher(searcher); @@ -3692,7 +3990,7 @@ uint8 Spell::CanCast(bool strict)              case SPELL_EFFECT_SCHOOL_DAMAGE:              {                  // Hammer of Wrath -                if(m_spellInfo->SpellVisual == 7250) +                if(m_spellInfo->SpellVisual[0] == 7250)                  {                      if (!m_targets.getUnitTarget())                          return SPELL_FAILED_BAD_IMPLICIT_TARGETS; @@ -3717,15 +4015,9 @@ uint8 Spell::CanCast(bool strict)                  if(!learn_spellproto)                      return SPELL_FAILED_NOT_KNOWN; -                if(!pet->CanTakeMoreActiveSpells(learn_spellproto->Id)) -                    return SPELL_FAILED_TOO_MANY_SKILLS; -                  if(m_spellInfo->spellLevel > pet->getLevel())                      return SPELL_FAILED_LOWLEVEL; -                if(!pet->HasTPForSpell(learn_spellproto->Id)) -                    return SPELL_FAILED_TRAINING_POINTS; -                  break;              }              case SPELL_EFFECT_LEARN_PET_SPELL: @@ -3740,20 +4032,18 @@ uint8 Spell::CanCast(bool strict)                  if(!learn_spellproto)                      return SPELL_FAILED_NOT_KNOWN; -                if(!pet->CanTakeMoreActiveSpells(learn_spellproto->Id)) -                    return SPELL_FAILED_TOO_MANY_SKILLS; -                  if(m_spellInfo->spellLevel > pet->getLevel())                      return SPELL_FAILED_LOWLEVEL; -                if(!pet->HasTPForSpell(learn_spellproto->Id)) -                    return SPELL_FAILED_TRAINING_POINTS; -                  break;              }              case SPELL_EFFECT_FEED_PET:              { -                if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_targets.getItemTarget() ) +                if (m_caster->GetTypeId() != TYPEID_PLAYER) +                    return SPELL_FAILED_BAD_TARGETS; + +                Item* foodItem = m_targets.getItemTarget(); +                if(!foodItem)                      return SPELL_FAILED_BAD_TARGETS;                  Pet* pet = m_caster->GetPet(); @@ -3761,10 +4051,10 @@ uint8 Spell::CanCast(bool strict)                  if(!pet)                      return SPELL_FAILED_NO_PET; -                if(!pet->HaveInDiet(m_targets.getItemTarget()->GetProto())) +                if(!pet->HaveInDiet(foodItem->GetProto()))                      return SPELL_FAILED_WRONG_PET_FOOD; -                if(!pet->GetCurrentFoodBenefitLevel(m_targets.getItemTarget()->GetProto()->ItemLevel)) +                if(!pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel))                      return SPELL_FAILED_FOOD_LOWLEVEL;                  if(m_caster->isInCombat() || pet->isInCombat()) @@ -3851,27 +4141,27 @@ uint8 Spell::CanCast(bool strict)                  {                      // check for lock - key pair (checked by client also, just prevent cheating                      bool ok_key = false; -                    for(int it = 0; it < 5; ++it) +                    for(int it = 0; it < 8; ++it)                      { -                        switch(lockInfo->keytype[it]) +                        switch(lockInfo->Type[it])                          {                              case LOCK_KEY_NONE:                                  break;                              case LOCK_KEY_ITEM:                              { -                                if(lockInfo->key[it]) +                                if(lockInfo->Index[it])                                  { -                                    if(m_CastItem && m_CastItem->GetEntry()==lockInfo->key[it]) +                                    if(m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[it])                                          ok_key =true;                                      break;                                  }                              }                              case LOCK_KEY_SKILL:                              { -                                if(uint32(m_spellInfo->EffectMiscValue[i])!=lockInfo->key[it]) +                                if(uint32(m_spellInfo->EffectMiscValue[i])!=lockInfo->Index[it])                                      break; -                                switch(lockInfo->key[it]) +                                switch(lockInfo->Index[it])                                  {                                      case LOCKTYPE_HERBALISM:                                          if(((Player*)m_caster)->HasSkill(SKILL_HERBALISM)) @@ -3929,9 +4219,9 @@ uint8 Spell::CanCast(bool strict)                  {                      // check for lock - key pair                      bool ok = false; -                    for(int it = 0; it < 5; ++it) +                    for(int it = 0; it < 8; ++it)                      { -                        if(lockInfo->keytype[it]==LOCK_KEY_ITEM && lockInfo->key[it] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[it]) +                        if(lockInfo->Type[it]==LOCK_KEY_ITEM && lockInfo->Index[it] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[it])                          {                              // if so, we're good to go                              ok = true; @@ -3942,9 +4232,9 @@ uint8 Spell::CanCast(bool strict)                          break;                      if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK) -                        ReqValue = lockInfo->requiredlockskill; +                        ReqValue = lockInfo->Skill[1];                      else -                        ReqValue = lockInfo->requiredminingskill; +                        ReqValue = lockInfo->Skill[0];                  }                  // skill doesn't meet the required value @@ -3968,9 +4258,7 @@ uint8 Spell::CanCast(bool strict)                  break;              } -            // This is generic summon effect now and don't make this check for summon types similar -            // SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN. -            // These won't show up in m_caster->GetPetGUID() +            // This is generic summon effect              case SPELL_EFFECT_SUMMON:              {                  switch(m_spellInfo->EffectMiscValueB[i]) @@ -3991,11 +4279,8 @@ uint8 Spell::CanCast(bool strict)                  }                  break;              } -            // Don't make this check for SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN. -            // These won't show up in m_caster->GetPetGUID() -            case SPELL_EFFECT_SUMMON_POSSESSED: +            // Not used for summon?              case SPELL_EFFECT_SUMMON_PHANTASM: -            case SPELL_EFFECT_SUMMON_DEMON:              {                  if(m_caster->GetPetGUID())                      return SPELL_FAILED_ALREADY_HAVE_SUMMON; @@ -4053,7 +4338,7 @@ uint8 Spell::CanCast(bool strict)              case SPELL_EFFECT_LEAP:              case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER:              { -                float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); +                float dis = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));                  float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation());                  float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation());                  // teleport a bit above terrain level to avoid falling below it @@ -4140,17 +4425,14 @@ uint8 Spell::CanCast(bool strict)                      return SPELL_FAILED_NO_MOUNTS_ALLOWED;                  // Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells -                if (m_caster->GetTypeId()==TYPEID_PLAYER && !sMapStore.LookupEntry(m_caster->GetMapId())->IsMountAllowed() && !m_IsTriggeredSpell && !m_spellInfo->AreaId) -                    return SPELL_FAILED_NO_MOUNTS_ALLOWED; - -                if (m_caster->GetAreaId()==35) +                if (m_caster->GetTypeId()==TYPEID_PLAYER && !sMapStore.LookupEntry(m_caster->GetMapId())->IsMountAllowed() && !m_IsTriggeredSpell && !m_spellInfo->AreaGroupId)                      return SPELL_FAILED_NO_MOUNTS_ALLOWED;                  ShapeshiftForm form = m_caster->m_form;                  if( form == FORM_CAT          || form == FORM_TREE      || form == FORM_TRAVEL   ||                      form == FORM_AQUA         || form == FORM_BEAR      || form == FORM_DIREBEAR ||                      form == FORM_CREATUREBEAR || form == FORM_GHOSTWOLF || form == FORM_FLIGHT   || -                    form == FORM_FLIGHT_EPIC  || form == FORM_MOONKIN ) +                    form == FORM_FLIGHT_EPIC  || form == FORM_MOONKIN   || form == FORM_METAMORPHOSIS )                      return SPELL_FAILED_NOT_SHAPESHIFT;                  break; @@ -4169,11 +4451,10 @@ uint8 Spell::CanCast(bool strict)              case SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED:              case SPELL_AURA_FLY:              { -        // not allow cast fly spells at old maps by players (all spells is self target) +                // not allow cast fly spells at old maps by players (all spells is self target)                  if(m_caster->GetTypeId()==TYPEID_PLAYER)                  { -                    if( !((Player*)m_caster)->isGameMaster() && -            GetVirtualMapForMapAndZone(m_caster->GetMapId(),m_caster->GetZoneId()) != 530) +                    if( !((Player*)m_caster)->IsAllowUseFlyMountsHere() )                          return SPELL_FAILED_NOT_HERE;                  }                  break; @@ -4288,15 +4569,16 @@ uint8 Spell::CheckCasterAuras() const      //Check whether the cast should be prevented by any state you might have.      uint8 prevented_reason = 0;      // Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out -    if(!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED) && m_caster->HasAuraType(SPELL_AURA_MOD_STUN)) +    uint32 unitflag = m_caster->GetUInt32Value(UNIT_FIELD_FLAGS);     // Get unit state +    if(unitflag & UNIT_FLAG_STUNNED && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED))          prevented_reason = SPELL_FAILED_STUNNED; -    else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED) && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED)) +    else if(unitflag & UNIT_FLAG_CONFUSED && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED))          prevented_reason = SPELL_FAILED_CONFUSED; -    else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING) && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED)) +    else if(unitflag & UNIT_FLAG_FLEEING && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED))          prevented_reason = SPELL_FAILED_FLEEING; -    else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED) && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE) +    else if(unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE)          prevented_reason = SPELL_FAILED_SILENCED; -    else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY) +    else if(unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY)          prevented_reason = SPELL_FAILED_PACIFIED;      // Attr must make flag drop spell totally immune from all effects @@ -4405,15 +4687,15 @@ uint8 Spell::CheckRange(bool strict)          range_mod = 6.25;*/      SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); -    float max_range = GetSpellMaxRange(srange); // + range_mod; -    float min_range = GetSpellMinRange(srange); + +    Unit *target = m_targets.getUnitTarget(); +    float max_range = m_caster->GetSpellMaxRangeForTarget(target, srange); // + range_mod; +    float min_range = m_caster->GetSpellMinRangeForTarget(target, srange);      uint32 range_type = GetSpellRangeType(srange);      if(Player* modOwner = m_caster->GetSpellModOwner())          modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, max_range, this); -    Unit *target = m_targets.getUnitTarget(); -      if(target && target != m_caster)      {          if(range_type == SPELL_RANGE_MELEE) @@ -4487,9 +4769,12 @@ int32 Spell::CalculatePowerCost()              case POWER_FOCUS:              case POWER_ENERGY:              case POWER_HAPPINESS: -                //            case POWER_RUNES:                  powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetMaxPower(Powers(m_spellInfo->powerType)) / 100;                  break; +            case POWER_RUNE: +            case POWER_RUNIC_POWER: +                sLog.outDebug("Spell::CalculateManaCost: Not implemented yet!"); +                break;              default:                  sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id);                  return 0; @@ -4534,6 +4819,11 @@ uint8 Spell::CheckPower()          sLog.outError("Spell::CheckMana: Unknown power type '%d'", m_spellInfo->powerType);          return SPELL_FAILED_UNKNOWN;      } + +    uint8 failReason = CheckRuneCost(m_spellInfo->runeCostID); +    if(failReason) +        return failReason; +      // Check power amount      Powers powerType = Powers(m_spellInfo->powerType);      if(m_caster->GetPower(powerType) < m_powerCost) @@ -4653,8 +4943,8 @@ uint8 Spell::CheckItems()          cell.data.Part.reserved = ALL_DISTRICT;          GameObject* ok = NULL; -        Trinity::GameObjectFocusCheck go_check(m_caster,m_spellInfo->RequiresSpellFocus); -        Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck> checker(ok,go_check); +        MaNGOS::GameObjectFocusCheck go_check(m_caster,m_spellInfo->RequiresSpellFocus); +        MaNGOS::GameObjectSearcher<MaNGOS::GameObjectFocusCheck> checker(m_caster,ok,go_check);          TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck>, GridTypeMapContainer > object_checker(checker);          CellLock<GridReadGuard> cell_lock(cell, p); @@ -4666,8 +4956,7 @@ uint8 Spell::CheckItems()          focusObject = ok;                                   // game object found in range      } -    if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP && -        m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION))) +    if (!p_caster->CanNoReagentCast(m_spellInfo))      {          for(uint32 i=0;i<8;i++)          { @@ -4752,6 +5041,7 @@ uint8 Spell::CheckItems()                  break;              }              case SPELL_EFFECT_ENCHANT_ITEM: +            case SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC:              {                  Item* targetItem = m_targets.getItemTarget();                  if(!targetItem) @@ -4835,13 +5125,36 @@ uint8 Spell::CheckItems()                      return SPELL_FAILED_LOW_CASTLEVEL;                  //make sure the player has the required ores in inventory                  if(m_targets.getItemTarget()->GetCount() < 5) -                    return SPELL_FAILED_PROSPECT_NEED_MORE; +                    return SPELL_FAILED_NEED_MORE_ITEMS;                  if(!LootTemplates_Prospecting.HaveLootFor(m_targets.getItemTargetEntry()))                      return SPELL_FAILED_CANT_BE_PROSPECTED;                  break;              } +            case SPELL_EFFECT_MILLING: +            { +                if(!m_targets.getItemTarget()) +                    return SPELL_FAILED_CANT_BE_MILLED; +                //ensure item is a millable herb +                if(!(m_targets.getItemTarget()->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS) || m_targets.getItemTarget()->GetProto()->Class != ITEM_CLASS_TRADE_GOODS) +                    return SPELL_FAILED_CANT_BE_MILLED; +                //prevent milling in trade slot +                if( m_targets.getItemTarget()->GetOwnerGUID() != m_caster->GetGUID() ) +                    return SPELL_FAILED_CANT_BE_MILLED; +                //Check for enough skill in inscription +                uint32 item_millingskilllevel = m_targets.getItemTarget()->GetProto()->RequiredSkillRank; +                if(item_millingskilllevel >p_caster->GetSkillValue(SKILL_INSCRIPTION)) +                    return SPELL_FAILED_LOW_CASTLEVEL; +                //make sure the player has the required herbs in inventory +                if(m_targets.getItemTarget()->GetCount() < 5) +                    return SPELL_FAILED_NEED_MORE_ITEMS; + +                if(!LootTemplates_Milling.HaveLootFor(m_targets.getItemTargetEntry())) +                    return SPELL_FAILED_CANT_BE_MILLED; + +                break; +            }              case SPELL_EFFECT_WEAPON_DAMAGE:              case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:              { @@ -4921,18 +5234,22 @@ void Spell::Delayed() // only called in DealDamage()      //if (m_spellState == SPELL_STATE_DELAYED)      //    return;                                             // spell is active and can't be time-backed +    if(isDelayableNoMore())                                 // Spells may only be delayed twice +        return; +      // spells not loosing casting time ( slam, dynamites, bombs.. )      //if(!(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_DAMAGE))      //    return; -    //check resist chance -    int32 resistChance = 100;                               //must be initialized to 100 for percent modifiers -    ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance, this); -    resistChance += m_caster->GetTotalAuraModifier(SPELL_AURA_RESIST_PUSHBACK) - 100; -    if (roll_chance_i(resistChance)) +    //check pushback reduce +    int32 delaytime = 500;                                  // spellcasting delay is normally 500ms +    int32 delayReduce = 100;                                // must be initialized to 100 for percent modifiers +    ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this); +    delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100; +    if(delayReduce >= 100)          return; -    int32 delaytime = GetNextDelayAtDamageMsTime(); +    delaytime = delaytime * (100 - delayReduce) / 100;      if(int32(m_timer) + delaytime > m_casttime)      { @@ -4956,14 +5273,18 @@ void Spell::DelayedChannel()      if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER || getState() != SPELL_STATE_CASTING)          return; -    //check resist chance -    int32 resistChance = 100;                               //must be initialized to 100 for percent modifiers -    ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance, this); -    resistChance += m_caster->GetTotalAuraModifier(SPELL_AURA_RESIST_PUSHBACK) - 100; -    if (roll_chance_i(resistChance)) +    if(isDelayableNoMore())                                 // Spells may only be delayed twice +        return; + +    //check pushback reduce +    int32 delaytime = GetSpellDuration(m_spellInfo) * 25 / 100; // channeling delay is normally 25% of its time per hit +    int32 delayReduce = 100;                               // must be initialized to 100 for percent modifiers +    ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,delayReduce, this); +    delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100; +    if(delayReduce >= 100)          return; -    int32 delaytime = GetNextDelayAtDamageMsTime(); +    delaytime = delaytime * (100 - delayReduce) / 100;      if(int32(m_timer) < delaytime)      { @@ -5017,9 +5338,9 @@ void Spell::UpdatePointers()      m_targets.Update(m_caster);  } -bool Spell::IsAffectedBy(SpellEntry const *spellInfo, uint32 effectId) +bool Spell::IsAffectedByAura(Aura *aura)  { -    return spellmgr.IsAffectedBySpell(m_spellInfo,spellInfo->Id,effectId,spellInfo->EffectItemType[effectId]); +    return spellmgr.IsAffectedByMod(m_spellInfo, aura->getAuraSpellMod());  }  bool Spell::CheckTargetCreatureType(Unit* target) const @@ -5027,7 +5348,7 @@ bool Spell::CheckTargetCreatureType(Unit* target) const      uint32 spellCreatureTargetMask = m_spellInfo->TargetCreatureType;      // Curse of Doom : not find another way to fix spell target check :/ -    if(m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags == 0x0200000000LL) +    if(m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags.IsEqual(0,0x02,0))      {          // not allow cast at player          if(target->GetTypeId()==TYPEID_PLAYER) @@ -5070,6 +5391,12 @@ bool Spell::CheckTarget( Unit* target, uint32 eff, bool hitPhase )              return false;      } +    // Check Aura spell req (need for AoE spells) +    if(m_spellInfo->targetAuraSpell && !target->HasAura(m_spellInfo->targetAuraSpell)) +        return false; +    if (m_spellInfo->excludeTargetAuraSpell && target->HasAura(m_spellInfo->excludeTargetAuraSpell)) +        return false; +      // Check targets for not_selectable unit flag and remove      // A player can cast spells on his pet (or other controlled unit) though in any state      if (target != m_caster && target->GetCharmerOrOwnerGUID() != m_caster->GetGUID()) @@ -5130,7 +5457,13 @@ bool Spell::CheckTarget( Unit* target, uint32 eff, bool hitPhase )              // all ok by some way or another, skip normal check              break;          default:                                            // normal case -            if(target!=m_caster && !target->IsWithinLOSInMap(m_caster)) +            // Get GO cast coordinates if original caster -> GO +            WorldObject *caster = NULL; +            if (m_originalCasterGUID) +                caster = ObjectAccessor::GetGameObject(*m_caster, m_originalCasterGUID); +            if (!caster) +                caster = m_caster; +            if(target!=m_caster && !target->IsWithinLOSInMap(caster))                  return false;              break;      } @@ -5149,9 +5482,8 @@ Unit* Spell::SelectMagnetTarget()          {              if(Unit* magnet = (*itr)->GetCaster())              { -                if((*itr)->m_procCharges>0) +                if((*itr)->DropAuraCharge())                  { -                    (*itr)->SetAuraProcCharges((*itr)->m_procCharges-1);                      target = magnet;                      m_targets.setUnitTarget(target);                      AddUnitTarget(target, 0); @@ -5175,7 +5507,7 @@ Unit* Spell::SelectMagnetTarget()  bool Spell::IsNeedSendToClient() const  { -    return m_spellInfo->SpellVisual!=0 || IsChanneledSpell(m_spellInfo) || +    return m_spellInfo->SpellVisual[0] || m_spellInfo->SpellVisual[1] || IsChanneledSpell(m_spellInfo) ||          m_spellInfo->speed > 0.0f || !m_triggeredByAuraSpell && !m_IsTriggeredSpell;  } @@ -5359,6 +5691,14 @@ void Spell::CalculateDamageDoneForAllTargets()          }      } +    bool usesAmmo=true; +    Unit::AuraList const& Auras = m_caster->GetAurasByType(SPELL_AURA_ABILITY_CONSUME_NO_AMMO); +    for(Unit::AuraList::const_iterator j = Auras.begin();j != Auras.end(); ++j) +    { +        if((*j)->isAffectedOnSpell(m_spellInfo)) +            usesAmmo=false; +    } +      for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)      {          TargetInfo &target = *ihit; @@ -5371,6 +5711,28 @@ void Spell::CalculateDamageDoneForAllTargets()          if (!unit)              continue; +        if (usesAmmo) +        { +            bool ammoTaken=false; +            for (uint8 i=0;i<3;i++) +            { +                if (!(mask & 1<<i)) +                    continue; +                switch (m_spellInfo->Effect[i]) +                { +                    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: +                    ammoTaken=true; +                    TakeAmmo(); +                } +                if (ammoTaken) +                    break; +            } +        } +          if (target.missCondition==SPELL_MISS_NONE)                          // In case spell hit target, do all effect on that target              target.damage += CalculateDamageDone(unit, mask, multiplier);          else if (target.missCondition == SPELL_MISS_REFLECT)                // In case spell reflect from target, do all effect on caster (if hit)  | 
