diff options
Diffstat (limited to 'src/game/Spell.cpp')
| -rw-r--r-- | src/game/Spell.cpp | 2779 | 
1 files changed, 1644 insertions, 1135 deletions
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 4fdd26c806f..7e94e86ab4d 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 @@ -33,9 +33,9 @@  #include "Player.h"  #include "Pet.h"  #include "Unit.h" +#include "Totem.h"  #include "Spell.h"  #include "DynamicObject.h" -#include "SpellAuras.h"  #include "Group.h"  #include "UpdateData.h"  #include "MapManager.h" @@ -43,14 +43,13 @@  #include "CellImpl.h"  #include "Policies/SingletonImp.h"  #include "SharedDefines.h" -#include "Tools.h"  #include "LootMgr.h"  #include "VMapFactory.h"  #include "BattleGround.h"  #include "Util.h"  #include "TemporarySummon.h" -#define SPELL_CHANNEL_UPDATE_INTERVAL 1000 +#define SPELL_CHANNEL_UPDATE_INTERVAL (1*IN_MILISECONDS)  extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; @@ -63,6 +62,54 @@ bool IsQuestTameSpell(uint32 spellId)          && spellproto->Effect[1] == SPELL_EFFECT_APPLY_AURA && spellproto->EffectApplyAuraName[1] == SPELL_AURA_DUMMY;  } +class PrioritizeManaWraper +{ +    friend struct PrioritizeMana; + +    public: +        explicit PrioritizeManaWraper(Unit * unit) : unit(unit) +        { +            uint32 maxmana = unit->GetMaxPower(POWER_MANA); +            percentMana = maxmana ? unit->GetPower(POWER_MANA) * 100 / maxmana : 101; +        } +        Unit* getUnit() const { return unit; } +    private: +        Unit* unit; +        uint32 percentMana; +}; + +struct PrioritizeMana +{ +    int operator()( PrioritizeManaWraper const& x, PrioritizeManaWraper const& y ) const +    { +        return x.percentMana < y.percentMana; +    } +}; + +class PrioritizeHealthWraper +{ +    friend struct PrioritizeHealth; + +    public: +        explicit PrioritizeHealthWraper(Unit * unit) : unit(unit) +        { +            uint32 maxhp = unit->GetMaxHealth(); +            percentHealth = maxhp ? unit->GetHealth() * 100 / maxhp : 101; +        } +        Unit* getUnit() const { return unit; } +    private: +        Unit* unit; +        uint32 percentHealth; +}; + +struct PrioritizeHealth +{ +    int operator()( PrioritizeHealthWraper const& x, PrioritizeHealthWraper const& y ) const +    { +        return x.percentHealth < y.percentHealth; +    } +}; +  SpellCastTargets::SpellCastTargets()  {      m_unitTarget = NULL; @@ -130,6 +177,14 @@ void SpellCastTargets::setDestination(WorldObject *target)      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; @@ -155,7 +210,7 @@ void SpellCastTargets::setCorpseTarget(Corpse* corpse)  void SpellCastTargets::Update(Unit* caster)  { -    m_GOTarget   = m_GOTargetGUID ? ObjectAccessor::GetGameObject(*caster,m_GOTargetGUID) : NULL; +    m_GOTarget   = m_GOTargetGUID ? caster->GetMap()->GetGameObject(m_GOTargetGUID) : NULL;      m_unitTarget = m_unitTargetGUID ?          ( m_unitTargetGUID==caster->GetGUID() ? caster : ObjectAccessor::GetUnit(*caster, m_unitTargetGUID) ) :      NULL; @@ -182,6 +237,8 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )      if(data->rpos()+4 > data->size())          return false; +    //data->hexlike(); +      *data >> m_targetMask;      sLog.outDebug("Spell read, target mask = %u", m_targetMask); @@ -189,16 +246,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 ) @@ -213,7 +274,10 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )      if( m_targetMask & 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; @@ -229,10 +293,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; @@ -252,7 +312,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()); @@ -277,7 +337,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; @@ -293,10 +360,12 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi      m_triggeringContainer = triggeringContainer;      m_referencedFromCurrentSpell = false;      m_executedCurrently = false; +    m_needComboPoints = NeedsComboPoints(m_spellInfo);      m_delayStart = 0;      m_delayAtDamageCount = 0;      m_applyMultiplierMask = 0; +    m_effectMask = 0;      // Get data for type of attack      switch (m_spellInfo->DmgClass) @@ -308,11 +377,11 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi                  m_attackType = BASE_ATTACK;              break;          case SPELL_DAMAGE_CLASS_RANGED: -            m_attackType = RANGED_ATTACK; +            m_attackType = IsRangedWeaponSpell(m_spellInfo) ? RANGED_ATTACK : BASE_ATTACK;              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; @@ -327,7 +396,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi          if((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId()==TYPEID_PLAYER)          {              if(Item* pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK)) -                m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage->DamageType); +                m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage[0].DamageType);          }      }      // Set health leech amount to zero @@ -362,14 +431,15 @@ 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; +    m_spellAura = 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 @@ -379,7 +449,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++)          { @@ -406,6 +476,35 @@ Spell::~Spell()      delete m_spellValue;  } +template<typename T> +WorldObject* Spell::FindCorpseUsing() +{ +    // non-standard target selection +    float max_range = GetSpellMaxRange(m_spellInfo, false); + +    CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); +    Cell cell(p); +    cell.data.Part.reserved = ALL_DISTRICT; +    cell.SetNoCreate(); + +    WorldObject* result = NULL; + +    T u_check(m_caster, max_range); +    MaNGOS::WorldObjectSearcher<T> searcher(m_caster, result, u_check); + +    TypeContainerVisitor<MaNGOS::WorldObjectSearcher<T>, GridTypeMapContainer > grid_searcher(searcher); +    CellLock<GridReadGuard> cell_lock(cell, p); +    cell_lock->Visit(cell_lock, grid_searcher, *m_caster->GetMap()); + +    if (!result) +    { +        TypeContainerVisitor<MaNGOS::WorldObjectSearcher<T>, WorldTypeMapContainer > world_searcher(searcher); +        cell_lock->Visit(cell_lock, world_searcher, *m_caster->GetMap()); +    } + +    return result; +} +  void Spell::FillTargetMap()  {      for(uint32 i = 0; i < 3; ++i) @@ -441,8 +540,20 @@ void Spell::FillTargetMap()              continue;          } +        if(/*tmpUnitMap.empty() && */m_spellInfo->Targets & TARGET_FLAG_CASTER) +        { +            AddUnitTarget(m_caster, i); +            continue; +        } +          if(!targetA && !targetB)          { +            if(!GetSpellMaxRangeForFriend(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex))) +            { +                AddUnitTarget(m_caster, i); +                continue; +            } +              // add here custom effects that need default target.              // FOR EVERY TARGET TYPE THERE IS A DIFFERENT FILL!!              switch(m_spellInfo->Effect[i]) @@ -453,17 +564,7 @@ void Spell::FillTargetMap()                      {                          case 20577:                         // Cannibalize                          { -                            // non-standard target selection -                            SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); -                            float max_range = GetSpellMaxRange(srange); -                            WorldObject* result = NULL; - -                            Trinity::CannibalizeObjectCheck u_check(m_caster, max_range); -                            Trinity::WorldObjectSearcher<Trinity::CannibalizeObjectCheck > searcher(result, u_check); -                            m_caster->VisitNearbyGridObject(max_range, searcher); -                            if(!result) -                                m_caster->VisitNearbyWorldObject(max_range, searcher); - +                            WorldObject* result = FindCorpseUsing<MaNGOS::CannibalizeObjectCheck> ();                              if(result)                              { @@ -484,15 +585,7 @@ void Spell::FillTargetMap()                              {                                  // clear cooldown at fail                                  if(m_caster->GetTypeId()==TYPEID_PLAYER) -                                { -                                    ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id); - -                                    WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); -                                    data << uint32(m_spellInfo->Id); -                                    data << uint64(m_caster->GetGUID()); -                                    ((Player*)m_caster)->GetSession()->SendPacket(&data); -                                } - +                                    ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id,true);                                  SendCastResult(SPELL_FAILED_NO_EDIBLE_CORPSES);                                  finish(false);                              } @@ -501,6 +594,8 @@ void Spell::FillTargetMap()                          default:                              if(m_targets.getUnitTarget())                                  AddUnitTarget(m_targets.getUnitTarget(), i); +                            else +                                AddUnitTarget(m_caster, i);                              break;                      }                      break; @@ -509,12 +604,16 @@ 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: +                case SPELL_EFFECT_SEND_TAXI:                      if(m_targets.getUnitTarget())                          AddUnitTarget(m_targets.getUnitTarget(), i); -                    else +                    // Triggered spells have additional spell targets - cast them even if no explicit unit target is given (required for spell 50516 for example) +                    else if(m_spellInfo->Effect[i] == SPELL_EFFECT_TRIGGER_SPELL)                          AddUnitTarget(m_caster, i);                      break;                  case SPELL_EFFECT_SUMMON_PLAYER: @@ -541,19 +640,23 @@ 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: +                case SPELL_EFFECT_KILL_CREDIT2: // only one spell: 42793                      AddUnitTarget(m_caster, i);                      break;                  case SPELL_EFFECT_LEARN_PET_SPELL: -                    if(Pet* pet = m_caster->GetPet()) +                    if(Guardian* pet = m_caster->GetGuardianPet())                          AddUnitTarget(pet, i);                      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;*/ @@ -590,6 +693,7 @@ void Spell::FillTargetMap()                      }                      break;                  default: +                    AddUnitTarget(m_caster, i);                      break;              }          } @@ -623,41 +727,10 @@ void Spell::prepareDataForTriggerSystem()  {      //==========================================================================================      // Now fill data for trigger system, need know: -    // Ņan spell trigger another or not ( m_canTrigger ) +    // 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) -        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) -    { -        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; -            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; -            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; -            break; -            case SPELLFAMILY_PALADIN: // For Holy Shock triggers need do it -                if (m_spellInfo->SpellFamilyFlags & 0x0001000000200000LL) m_canTrigger = true; -            break; -            case SPELLFAMILY_ROGUE: // mutilate mainhand + offhand -                if (m_spellInfo->SpellFamilyFlags & 0x600000000LL) 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)      { @@ -666,21 +739,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; @@ -689,7 +771,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;  } @@ -698,8 +780,6 @@ void Spell::CleanupTargetList()      m_UniqueTargetInfo.clear();      m_UniqueGOTargetInfo.clear();      m_UniqueItemInfo.clear(); -    m_countOfHit = 0; -    m_countOfMiss = 0;      m_delayMoment = 0;  } @@ -711,6 +791,9 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)      if(!CheckTarget(pVictim, effIndex))          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 @@ -718,7 +801,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;          }      } @@ -728,7 +812,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; @@ -742,11 +826,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)      { @@ -827,15 +906,13 @@ void Spell::AddGOTarget(GameObject* pVictim, uint32 effIndex)      else          target.timeDelay = 0LL; -    ++m_countOfHit; -      // Add target to list      m_UniqueGOTargetInfo.push_back(target);  }  void Spell::AddGOTarget(uint64 goGUID, uint32 effIndex)  { -    GameObject* go = ObjectAccessor::GetGameObject(*m_caster, goGUID); +    GameObject* go = m_caster->GetMap()->GetGameObject(goGUID);      if (go)          AddGOTarget(go, effIndex);  } @@ -862,83 +939,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)  { @@ -948,15 +948,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) @@ -975,30 +973,40 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)      // Fill base trigger info      uint32 procAttacker = m_procAttacker;      uint32 procVictim   = m_procVictim; -    uint32 procEx       = PROC_EX_NONE; +    uint32 procEx       = m_triggeredByAuraSpell  +        && !(m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_TRIGGERED_CAN_TRIGGER) +        && !(m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_TRIGGERED_CAN_TRIGGER_2) +        ? PROC_EX_INTERNAL_TRIGGERED : PROC_EX_NONE; +    m_spellAura = NULL; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied                              //Spells with this flag cannot trigger if effect is casted on self                              // Slice and Dice, relentless strikes, eviscerate -    bool canEffectTrigger = (m_spellInfo->AttributesEx4 & (SPELL_ATTR_EX4_CANT_PROC_FROM_SELFCAST | SPELL_ATTR_EX4_UNK4) ? m_caster!=unitTarget : true)  -        && m_canTrigger; +    bool canEffectTrigger = (m_spellInfo->AttributesEx4 & (SPELL_ATTR_EX4_CANT_PROC_FROM_SELFCAST | SPELL_ATTR_EX4_UNK4) ? m_caster!=unitTarget : true); +    Unit * spellHitTarget = NULL;      if (missInfo==SPELL_MISS_NONE)                          // In case spell hit target, do all effect on that target -        DoSpellHitOnUnit(unit, mask); +        spellHitTarget = unit;      else if (missInfo == SPELL_MISS_REFLECT)                // In case spell reflect from target, do all effect on caster (if hit)      {          if (target->reflectResult == SPELL_MISS_NONE)       // If reflected spell hit caster -> do all effect on him -            DoSpellHitOnUnit(m_caster, mask); +            spellHitTarget = m_caster;      } -    /*else //TODO: This is a hack. need fix + +    if(spellHitTarget)      { -        uint32 tempMask = 0; -        for(uint32 i = 0; i < 3; ++i) -            if(m_spellInfo->Effect[i] == SPELL_EFFECT_DUMMY -                || m_spellInfo->Effect[i] == SPELL_EFFECT_TRIGGER_SPELL) -                tempMask |= 1<<i; -        if(tempMask &= mask) -            DoSpellHitOnUnit(unit, tempMask); -    }*/ +        SpellMissInfo missInfo = DoSpellHitOnUnit(spellHitTarget, mask); +        if(missInfo != SPELL_MISS_NONE) +        { +            m_caster->SendSpellMiss(unit, m_spellInfo->Id, missInfo); +            m_damage = 0; +            spellHitTarget = NULL; +        } +    } + +    // Do not take combo points on dodge +    if (m_needComboPoints && m_targets.getUnitTargetGUID() == target->targetGUID) +        if( missInfo != SPELL_MISS_NONE && missInfo != SPELL_MISS_MISS) +            m_needComboPoints = false;      // All calculated do it!      // Do healing and triggers @@ -1009,23 +1017,20 @@ 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; -        caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit); -          // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)          if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)              caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo); -        int32 gain = unitTarget->ModifyHealth( int32(addhealth) ); +        if (m_spellAura) +            m_spellAura->SetProcDamage(addhealth); +        int32 gain = caster->DealHeal(unitTarget, addhealth, m_spellInfo, crit);          unitTarget->getHostilRefManager().threatAssist(caster, float(gain) * 0.5f, m_spellInfo); -        if(caster->GetTypeId()==TYPEID_PLAYER) -            if(BattleGround *bg = ((Player*)caster)->GetBattleGround()) -                bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);      }      // Do damage and triggers      else if (m_damage > 0) @@ -1035,127 +1040,120 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)          // Add bonuses and fill damageInfo struct          caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo); +        caster->DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);          // Send log damage message to client          caster->SendSpellNonMeleeDamageLog(&damageInfo); -        procEx = createProcExtendMask(&damageInfo, missInfo); +        procEx |= createProcExtendMask(&damageInfo, missInfo);          procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE;          // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)          if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)              caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo); +        if (m_spellAura) +            m_spellAura->SetProcDamage(damageInfo.damage); +          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      {          // Fill base damage struct (unitTarget - is real spell target)          SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask); -        procEx = createProcExtendMask(&damageInfo, missInfo); +        procEx |= createProcExtendMask(&damageInfo, missInfo);          // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)          if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)              caster->ProcDamageAndSpell(unit, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo);      } -    // Call scripted function for AI if this spell is casted upon a creature (except pets) -    if(IS_CREATURE_GUID(target->targetGUID)) -    { -        // cast at creature (or GO) quest objectives update at successful cast finished (+channel finished) -        // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... ) -        if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() ) -            ((Player*)m_caster)->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id); -    } -      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);          }      } + +    if(spellHitTarget) +    { +        // Call scripted function for AI if this spell is casted upon a creature (except pets) +        if(IS_CREATURE_GUID(target->targetGUID)) +        { +            // cast at creature (or GO) quest objectives update at successful cast finished (+channel finished) +            // ignore pets or autorepeat/melee casts for speed (not exist quest for spells (hm... ) +            if( !((Creature*)unit)->isPet() && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() ) +            { +                if ( Player* p = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself() ) +                    p->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id); +            } +        } + +        //AI functions +        if(spellHitTarget->GetTypeId() == TYPEID_UNIT && ((Creature*)spellHitTarget)->IsAIEnabled) +            ((Creature*)spellHitTarget)->AI()->SpellHit(m_caster, m_spellInfo); + +        if(m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->IsAIEnabled) +            ((Creature*)m_caster)->AI()->SpellHitTarget(spellHitTarget, m_spellInfo); + +        // Needs to be called after dealing damage/healing to not remove breaking on damage auras +        DoTriggersOnSpellHit(spellHitTarget); +    }  } -void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) +SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)  {      if(!unit || !effectMask) -        return; +        return SPELL_MISS_EVADE;      // 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(m_spellInfo) || +        unit->IsImmunedToSpell(m_spellInfo)))      { -        m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_IMMUNE); -        m_damage = 0; -        return; +        return SPELL_MISS_IMMUNE; +    } + +    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_damage = 0; -                return; -            } +            return SPELL_MISS_EVADE;          } +          if( !m_caster->IsFriendlyTo(unit) )          {              // for delayed spells ignore not visible explicit target              if(m_spellInfo->speed > 0.0f && unit==m_targets.getUnitTarget() && !unit->isVisibleForOrDetect(m_caster,false))              { -                m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE); -                m_damage = 0; -                return; +                return SPELL_MISS_EVADE;              }              unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL); @@ -1168,9 +1166,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)              // TODO: this cause soul transfer bugged              if(m_spellInfo->speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !IsPositiveSpell(m_spellInfo->Id))              { -                m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE); -                m_damage = 0; -                return; +                return SPELL_MISS_EVADE;              }              // assisting case, healing and resurrection @@ -1179,7 +1175,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)                  m_caster->SetContestedPvP();                  //m_caster->UpdatePvP(true);              } -            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); @@ -1197,30 +1193,70 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)              unit->IncrDiminishing(m_diminishGroup);      } -    for(uint32 effectNumber=0;effectNumber<3;effectNumber++) +    uint8 aura_effmask = 0; +    for (uint8 i = 0; i < 3; ++i) +        if (effectMask & (1<<i) && (m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA || IsAreaAuraEffect(m_spellInfo->Effect[i]))) +            aura_effmask |= 1<<i; + +    if (aura_effmask)      { -        if (effectMask & (1<<effectNumber)) +        Unit * caster = m_originalCaster ? m_originalCaster : m_caster; +        Aura * Aur = new Aura(m_spellInfo, aura_effmask, m_currentBasePoints, unit, caster, m_CastItem, m_caster); + +        if (!Aur->IsAreaAura())          { -            HandleEffects(unit,NULL,NULL,effectNumber/*,m_damageMultipliers[effectNumber]*/); -            //Only damage and heal spells need this -            /*if ( m_applyMultiplierMask & (1 << effectNumber) ) +            // Now Reduce spell duration using data received at spell hit +            int32 duration = Aur->GetAuraMaxDuration(); +            unit->ApplyDiminishingToDuration(m_diminishGroup,duration,caster,m_diminishLevel); +            Aur->setDiminishGroup(m_diminishGroup); + +            duration = caster->ModSpellDuration(m_spellInfo, unit, duration, Aur->IsPositive()); + +            //mod duration of channeled aura by spell haste +            if (IsChanneledSpell(m_spellInfo)) +                caster->ModSpellCastTime(m_spellInfo, duration, this); + +            if(duration != Aur->GetAuraMaxDuration())              { -                // Get multiplier -                float multiplier = m_spellInfo->DmgMultiplier[effectNumber]; -                // Apply multiplier mods -                if(m_originalCaster) -                    if(Player* modOwner = m_originalCaster->GetSpellModOwner()) -                        modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_EFFECT_PAST_FIRST, multiplier,this); -                m_damageMultipliers[effectNumber] *= multiplier; -            }*/ +                Aur->SetAuraMaxDuration(duration); +                Aur->SetAuraDuration(duration); +            } + +            // Prayer of Mending (jump animation), we need formal caster instead original for correct animation +            if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags[1] & 0x000020)) +                m_caster->CastSpell(unit, 41637, true, NULL, NULL, m_originalCasterGUID);          } +        // Set aura only when successfully applied +        if (unit->AddAura(Aur, false)) +            m_spellAura = Aur;      } -    if(unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->IsAIEnabled) -        ((Creature*)unit)->AI()->SpellHit(m_caster, m_spellInfo); +    for(uint32 effectNumber = 0; effectNumber < 3; ++effectNumber) +    { +        if (effectMask & (1<<effectNumber)) +            HandleEffects(unit,NULL,NULL,effectNumber); +    } + +    return SPELL_MISS_NONE; +} -    if(m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->IsAIEnabled) -        ((Creature*)m_caster)->AI()->SpellHitTarget(unit, m_spellInfo); +void Spell::DoTriggersOnSpellHit(Unit *unit) +{ +    // Apply additional spell effects to target +    if (m_preCastSpell) +    { +        // Special spell id +        // TODO: Handle all of special spells in one place? +        if(m_preCastSpell==61988) +        { +            //Cast Forbearance +            m_caster->CastSpell(unit,25771, true, m_CastItem); +            // Cast Avenging Wrath Marker +            m_caster->CastSpell(unit,61987, true, m_CastItem); +        } +        else +            m_caster->CastSpell(unit,m_preCastSpell, true, m_CastItem); +    }      // spells with this flag can trigger only if not selfcast (eviscerate for example)      if (m_ChanceTriggerSpells.size() && (!(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_CANT_PROC_FROM_SELFCAST | SPELL_ATTR_EX4_UNK4) || unit!=m_caster)) @@ -1228,20 +1264,25 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)          int _duration=0;          for(ChanceTriggerSpells::const_iterator i = m_ChanceTriggerSpells.begin(); i != m_ChanceTriggerSpells.end(); ++i)          { +            // SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration +            // set duration equal to triggering spell              if(roll_chance_i(i->second))              {                  m_caster->CastSpell(unit, i->first, true); -                // SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration -                // set duration equal to triggering spell -                if (GetSpellDuration(i->first)==-1) +                sLog.outDebug("Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->first); +            } +            if (GetSpellDuration(i->first)==-1) +            { +                if (Aura * triggeredAur = unit->GetAura(i->first->Id, m_caster->GetGUID()))                  {                      // get duration from aura-only once                      if (!_duration)                      { -                        Aura * aur = unit->GetAuraByCasterSpell(m_spellInfo->Id, m_caster->GetGUID()); +                        Aura * aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID());                          _duration = aur ? aur->GetAuraDuration() : -1;                      } -                    unit->SetAurasDurationByCasterSpell(i->first->Id, m_caster->GetGUID(), _duration); +                    triggeredAur->SetAuraDuration(_duration); +                    triggeredAur->SetPermanent(false);                  }              }          } @@ -1256,15 +1297,6 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)                  else                      unit->CastSpell(unit, *i, true, 0, 0, m_caster->GetGUID());      } - -    //This is not needed with procflag patch -    /*if(m_originalCaster) -    { -        if(m_customAttr & SPELL_ATTR_CU_EFFECT_HEAL) -            m_originalCaster->ProcDamageAndSpell(unit, PROC_FLAG_HEAL, PROC_FLAG_NONE, 0, GetSpellSchoolMask(m_spellInfo), m_spellInfo); -        if(m_originalCaster != unit && (m_customAttr & SPELL_ATTR_CU_EFFECT_DAMAGE)) -            m_originalCaster->ProcDamageAndSpell(unit, PROC_FLAG_HIT_SPELL, PROC_FLAG_STRUCK_SPELL, 0, GetSpellSchoolMask(m_spellInfo), m_spellInfo); -    }*/  }  void Spell::DoAllEffectOnTarget(GOTargetInfo *target) @@ -1277,7 +1309,7 @@ void Spell::DoAllEffectOnTarget(GOTargetInfo *target)      if(!effectMask)          return; -    GameObject* go = ObjectAccessor::GetGameObject(*m_caster, target->targetGUID); +    GameObject* go = m_caster->GetMap()->GetGameObject(target->targetGUID);      if(!go)          return; @@ -1287,8 +1319,11 @@ void Spell::DoAllEffectOnTarget(GOTargetInfo *target)      // cast at creature (or GO) quest objectives update at successful cast finished (+channel finished)      // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... ) -    if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() ) -        ((Player*)m_caster)->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id); +    if( !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() ) +    { +        if ( Player* p = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself() ) +            p->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id); +    }  }  void Spell::DoAllEffectOnTarget(ItemTargetInfo *target) @@ -1302,13 +1337,19 @@ void Spell::DoAllEffectOnTarget(ItemTargetInfo *target)              HandleEffects(NULL, target->item, NULL, effectNumber);  } -bool Spell::IsAliveUnitPresentInTargetList() +bool Spell::UpdateChanneledTargetList()  {      // Not need check return true      if (m_needAliveTargetMask == 0)          return true;      uint8 needAliveTargetMask = m_needAliveTargetMask; +    uint8 needAuraMask = 0; +    for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i) +        if (m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA) +            needAuraMask |= 1<<i; + +    needAuraMask &= needAliveTargetMask;      for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)      { @@ -1317,7 +1358,27 @@ bool Spell::IsAliveUnitPresentInTargetList()              Unit *unit = m_caster->GetGUID()==ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);              if (unit && unit->isAlive()) +            { +                if (needAuraMask & ihit->effectMask) +                { +                    if(Aura * aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID())) +                    { +                        float range = m_caster->GetSpellMaxRangeForTarget(unit,GetSpellRangeStore()->LookupEntry(m_spellInfo->rangeIndex)); +                        if(Player * modOwner = m_caster->GetSpellModOwner()) +                            modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); +                        if (m_caster != unit && !m_caster->IsWithinDistInMap(unit,range)) +                        { +                            ihit->effectMask &= ~aur->GetEffectMask(); +                            unit->RemoveAura(aur); +                            continue; +                        } +                    } +                    else +                        continue; +                } +                  needAliveTargetMask &= ~ihit->effectMask;   // remove from need alive mask effect that have alive target +            }          }      } @@ -1365,7 +1426,7 @@ struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit,      // functor for operator ">"      bool operator()(const Unit* _Left, const Unit* _Right) const      { -        return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right)); +        return MainTarget->GetDistanceOrder(_Left,_Right);      }  }; @@ -1375,6 +1436,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)->GetAmount(); +    }*/ +      //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; @@ -1420,7 +1491,7 @@ void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uin              if(cur->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS)                  break;              while(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE -                && !m_caster->isInFront(*next, max_range) +                && !m_caster->isInFrontInMap(*next, max_range)                  || !m_caster->canSeeOrDetect(*next, false)                  || !cur->IsWithinLOSInMap(*next))              { @@ -1435,7 +1506,7 @@ void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uin      }  } -void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, const uint32 type, SpellTargets TargetType, uint32 entry) +void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry)  {      float x, y, z;      switch(type) @@ -1478,6 +1549,9 @@ void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, const u          m_caster->GetMap()->VisitWorld(x, y, radius, notifier);      else          m_caster->GetMap()->VisitAll(x, y, radius, notifier); + +    if(m_customAttr & SPELL_ATTR_CU_EXCLUDE_SELF) +        TagUnitMap.remove(m_caster);  }  WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType) @@ -1511,7 +1585,7 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)                          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) @@ -1535,13 +1609,15 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)                          break;                      }                      case SPELL_TARGET_TYPE_CREATURE: +                        if(m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetEntry() == i_spellST->second.targetEntry) +                            return m_targets.getUnitTarget();                      case SPELL_TARGET_TYPE_DEAD:                      default:                      {                          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 ) @@ -1565,7 +1641,7 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)          {              Unit *target = NULL;              Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, range); -            Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(target, u_check); +            Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(m_caster, target, u_check);              m_caster->VisitNearbyObject(range, searcher);              return target;          } @@ -1573,7 +1649,7 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)          {              Unit *target = NULL;              Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, range); -            Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(target, u_check); +            Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(m_caster, target, u_check);              m_caster->VisitNearbyObject(range, searcher);              return target;          } @@ -1599,8 +1675,8 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)                  case TARGET_UNIT_CASTER_FISHING:                  {                      AddUnitTarget(m_caster, i);                    -                    float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); -                    float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); +                    float min_dis = GetSpellMinRange(m_spellInfo, true); +                    float max_dis = GetSpellMaxRange(m_spellInfo, true);                      float dis = rand_norm() * (max_dis - min_dis) + min_dis;                      float x, y, z;                      m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis); @@ -1612,7 +1688,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)                          AddUnitTarget(owner, i);                      break;                  case TARGET_UNIT_PET: -                    if(Pet* pet = m_caster->GetPet()) +                    if(Guardian* pet = m_caster->GetGuardianPet())                          AddUnitTarget(pet, i);                      break;                  case TARGET_UNIT_PARTY_CASTER: @@ -1635,13 +1711,23 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)              switch(cur)              {                  case TARGET_UNIT_TARGET_ENEMY: -                    SelectMagnetTarget(); +                    if(Unit *magnet = m_caster->SelectMagnetTarget(target, m_spellInfo)) +                        if(magnet != target) +                            m_targets.setUnitTarget(magnet); +                    pushType = PUSH_CHAIN; +                    break; +                case TARGET_UNIT_TARGET_ANY: +                    if(!IsPositiveSpell(m_spellInfo->Id)) +                        if(Unit *magnet = m_caster->SelectMagnetTarget(target, m_spellInfo)) +                            if(magnet != target) +                                m_targets.setUnitTarget(magnet); +                    pushType = PUSH_CHAIN; +                    break;                  case TARGET_UNIT_CHAINHEAL:                      pushType = PUSH_CHAIN;                      break;                  case TARGET_UNIT_TARGET_ALLY:                  case TARGET_UNIT_TARGET_RAID: -                case TARGET_UNIT_TARGET_ANY: // SelectMagnetTarget()?                  case TARGET_UNIT_TARGET_PARTY:                  case TARGET_UNIT_MINIPET:                      AddUnitTarget(target, i); @@ -1656,38 +1742,41 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)          case TARGET_TYPE_UNIT_NEARBY:          { -            float range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); -            if(modOwner) -                modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); -              WorldObject *target = NULL; +            float range;              switch(cur)              {                  case TARGET_UNIT_NEARBY_ENEMY: +                    range = GetSpellMaxRange(m_spellInfo, false); +                    if(modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);                      target = SearchNearbyTarget(range, SPELL_TARGETS_ENEMY);                      break;                  case TARGET_UNIT_NEARBY_ALLY:                  case TARGET_UNIT_NEARBY_ALLY_UNK:                  case TARGET_UNIT_NEARBY_RAID: +                    range = GetSpellMaxRange(m_spellInfo, true); +                    if(modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);                      target = SearchNearbyTarget(range, SPELL_TARGETS_ALLY);                      break;                  case TARGET_UNIT_NEARBY_ENTRY: +                    range = GetSpellMaxRange(m_spellInfo, IsPositiveSpell(m_spellInfo->Id)); +                    if(modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);                      target = SearchNearbyTarget(range, SPELL_TARGETS_ENTRY);                      break;              }              if(!target)                  return; -            else if(target->GetTypeId() == TYPEID_UNIT) +            else if(target->GetTypeId() == TYPEID_GAMEOBJECT) +                AddGOTarget((GameObject*)target, i); +            else              {                  pushType = PUSH_CHAIN; -                if(!m_targets.getUnitTarget()) +                if(m_targets.getUnitTarget() != target)                      m_targets.setUnitTarget((Unit*)target);              } -            else if(target->GetTypeId() == TYPEID_GAMEOBJECT) -                AddGOTarget((GameObject*)target, i);              break;          } @@ -1725,7 +1814,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)              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) @@ -1769,7 +1858,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)              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) @@ -1822,7 +1911,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)              }              float dist, x, y, z; -            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(); @@ -1850,7 +1939,13 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)                              m_targets.setDestination(st->target_X, st->target_Y, st->target_Z);                      }                      else -                        sLog.outError( "SPELL: unknown target coordinates for spell ID %u\n", m_spellInfo->Id ); +                    { +                        sLog.outError( "SPELL: unknown target coordinates for spell ID %u", m_spellInfo->Id ); +                        Unit *target = NULL; +                        if(uint64 guid = m_caster->GetUInt64Value(UNIT_FIELD_TARGET)) +                            target = ObjectAccessor::GetUnit(*m_caster, guid); +                        m_targets.setDestination(target ? target : m_caster); +                    }                      break;                  case TARGET_DST_HOME:                      if(m_caster->GetTypeId() == TYPEID_PLAYER) @@ -1858,9 +1953,8 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)                      break;                  case TARGET_DST_NEARBY_ENTRY:                  { -                    float range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); -                    if(modOwner) -                        modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); +                    float range = GetSpellMaxRange(m_spellInfo, IsPositiveSpell(m_spellInfo->Id)); +                    if(modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);                      WorldObject *target = SearchNearbyTarget(range, SPELL_TARGETS_ENTRY);                      if(target) @@ -1940,10 +2034,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)              m_damageMultipliers[i] = 1.0f;              m_applyMultiplierMask |= 1 << i; -            float range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); -            if(modOwner) -                modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); - +            float range;              std::list<Unit*> unitList;              switch(cur) @@ -1951,12 +2042,16 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)                  case TARGET_UNIT_NEARBY_ENEMY:                  case TARGET_UNIT_TARGET_ENEMY:                  case TARGET_UNIT_NEARBY_ENTRY: // fix me +                    range = GetSpellMaxRange(m_spellInfo, false); +                    if(modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);                      SearchChainTarget(unitList, range, maxTargets, SPELL_TARGETS_ENEMY);                      break;                  case TARGET_UNIT_CHAINHEAL:                  case TARGET_UNIT_NEARBY_ALLY:  // fix me                  case TARGET_UNIT_NEARBY_ALLY_UNK:                  case TARGET_UNIT_NEARBY_RAID: +                    range = GetSpellMaxRange(m_spellInfo, true); +                    if(modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);                      SearchChainTarget(unitList, range, maxTargets, SPELL_TARGETS_CHAINHEAL);                      break;              } @@ -1970,114 +2065,178 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)      else if(pushType)      {          // Dummy, just for client -        if(spellmgr.EffectTargetType[m_spellInfo->Effect[i]] == SPELL_REQUIRE_DEST) +        if(spellmgr.EffectTargetType[m_spellInfo->Effect[i]] != SPELL_REQUIRE_UNIT)              return; -        float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); -        if(modOwner) -            modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius, this); - -        std::list<Unit*> unitList; - +        float radius; +        SpellTargets targetType;          switch(cur)          {              case TARGET_UNIT_AREA_ENEMY_SRC:              case TARGET_UNIT_AREA_ENEMY_DST:              case TARGET_UNIT_CONE_ENEMY:              case TARGET_UNIT_CONE_ENEMY_UNKNOWN: -                SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENEMY); +                radius = GetSpellRadius(m_spellInfo, i, false); +                targetType = SPELL_TARGETS_ENEMY;                  break;              case TARGET_UNIT_AREA_ALLY_SRC:              case TARGET_UNIT_AREA_ALLY_DST:              case TARGET_UNIT_CONE_ALLY: -                SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ALLY); -                break; -            case TARGET_UNIT_AREA_PARTY_SRC: -            case TARGET_UNIT_AREA_PARTY_DST: -                m_caster->GetPartyMember(unitList, radius); //fix me -                break; -            case TARGET_OBJECT_AREA_SRC: // fix me -            case TARGET_OBJECT_AREA_DST: +                radius = GetSpellRadius(m_spellInfo, i, true); +                targetType = SPELL_TARGETS_ALLY;                  break;              case TARGET_UNIT_AREA_ENTRY_SRC:              case TARGET_UNIT_AREA_ENTRY_DST:              case TARGET_UNIT_CONE_ENTRY: // fix me +                radius = GetSpellRadius(m_spellInfo, i, IsPositiveSpell(m_spellInfo->Id)); +                targetType = SPELL_TARGETS_ENTRY; +                break; +            default: +                radius = GetSpellRadius(m_spellInfo, i, true); +                targetType = SPELL_TARGETS_NONE; +                break; +        } + +        if(modOwner) +            modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius, this); +        radius *= m_spellValue->RadiusMod; + +        std::list<Unit*> unitList; +        if(targetType == SPELL_TARGETS_ENTRY) +        { +            SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id); +            SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id); +            if(lower == upper)              { -                SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id); -                SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id); -                if(lower == upper) -                { -                    sLog.outErrorDb("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry()); +                sLog.outErrorDb("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry()); -                    if(IsPositiveEffect(m_spellInfo->Id, i)) -                        SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ALLY); -                    else -                        SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENEMY); -                } -                // let it be done in one check? +                if(IsPositiveEffect(m_spellInfo->Id, i)) +                    SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ALLY);                  else +                    SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENEMY); +            } +            // let it be done in one check? +            else +            { +                for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST)                  { -                    for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST) -                    { -                        if(i_spellST->second.type == SPELL_TARGET_TYPE_CREATURE) -                            SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, i_spellST->second.targetEntry); -                    } +                    if(i_spellST->second.type == SPELL_TARGET_TYPE_CREATURE) +                        SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, i_spellST->second.targetEntry);                  } -                break;              } -            case TARGET_UNIT_PARTY_TARGET: -                m_targets.getUnitTarget()->GetPartyMember(unitList, radius); -                break; -            case TARGET_UNIT_PARTY_CASTER: -                m_caster->GetPartyMember(unitList, radius); -                break; -            case TARGET_UNIT_RAID_CASTER: -                m_caster->GetRaidMember(unitList, radius); -                break; -            case TARGET_UNIT_CLASS_TARGET: +        } +        else if(targetType) +            SearchAreaTarget(unitList, radius, pushType, targetType); +        else +        { +            switch(cur)              { -                Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER -                    ? (Player*)m_targets.getUnitTarget() : NULL; - -                Group* pGroup = targetPlayer ? targetPlayer->GetGroup() : NULL; -                if(pGroup) +                case TARGET_UNIT_AREA_PARTY_SRC: +                case TARGET_UNIT_AREA_PARTY_DST: +                    m_caster->GetPartyMember(unitList, radius); //fix me +                    break; +                case TARGET_OBJECT_AREA_SRC: // fix me +                case TARGET_OBJECT_AREA_DST: +                    break; +                case TARGET_UNIT_PARTY_TARGET: +                    m_targets.getUnitTarget()->GetPartyMember(unitList, radius); +                    break; +                case TARGET_UNIT_PARTY_CASTER: +                    m_caster->GetPartyMember(unitList, radius); +                    break; +                case TARGET_UNIT_RAID_CASTER: +                    m_caster->GetRaidMember(unitList, radius); +                    break; +                case TARGET_UNIT_CLASS_TARGET:                  { -                    for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) -                    { -                        Player* Target = itr->getSource(); +                    Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER +                        ? (Player*)m_targets.getUnitTarget() : NULL; -                        // IsHostileTo check duel and controlled by enemy -                        if( Target && targetPlayer->IsWithinDistInMap(Target, radius) && -                            targetPlayer->getClass() == Target->getClass() && -                            !m_caster->IsHostileTo(Target) ) +                    Group* pGroup = targetPlayer ? targetPlayer->GetGroup() : NULL; +                    if(pGroup) +                    { +                        for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())                          { -                            AddUnitTarget(Target, i); +                            Player* Target = itr->getSource(); + +                            // IsHostileTo check duel and controlled by enemy +                            if( Target && targetPlayer->IsWithinDistInMap(Target, radius) && +                                targetPlayer->getClass() == Target->getClass() && +                                !m_caster->IsHostileTo(Target) ) +                            { +                                AddUnitTarget(Target, i); +                            }                          }                      } +                    else if(m_targets.getUnitTarget()) +                        AddUnitTarget(m_targets.getUnitTarget(), i); +                    break;                  } -                else if(m_targets.getUnitTarget()) -                    AddUnitTarget(m_targets.getUnitTarget(), i); -                break;              }          }          if(!unitList.empty())          { -            if(m_spellValue->MaxAffectedTargets) +            if(uint32 maxTargets = m_spellValue->MaxAffectedTargets)              { +                Unit::AuraEffectList const& Auras = m_caster->GetAurasByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS); +                for(Unit::AuraEffectList::const_iterator j = Auras.begin();j != Auras.end(); ++j) +                    if((*j)->isAffectedOnSpell(m_spellInfo)) +                        maxTargets += (*j)->GetAmount(); +                  if(m_spellInfo->Id == 5246) //Intimidating Shout                      unitList.remove(m_targets.getUnitTarget()); +                else if (m_spellInfo->Id==57699) //Replenishment (special target selection) 10 targets with lowest mana +                { +                    typedef std::priority_queue<PrioritizeManaWraper, std::vector<PrioritizeManaWraper>, PrioritizeMana> TopMana; +                    TopMana manaUsers; +                    for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end() && manaUsers.size() <=m_spellValue->MaxAffectedTargets;++itr) +                    { +                        if ((*itr)->getPowerType() == POWER_MANA) +                        { +                            PrioritizeManaWraper  WTarget(*itr); +                            manaUsers.push(WTarget); +                        } +                    } +                    unitList.clear(); +                    while(!manaUsers.empty()) +                    { +                        unitList.push_back(manaUsers.top().getUnit()); +                        manaUsers.pop(); +                    } +                } +                else if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_DEST_TARGET_ANY +                    && m_spellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_AREA_ALLY_DST)// Wild Growth, Circle of Healing target special selection +                { +                    typedef std::priority_queue<PrioritizeHealthWraper, std::vector<PrioritizeHealthWraper>, PrioritizeHealth> TopHealth; +                    TopHealth healedMembers; +                    for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end() && healedMembers.size() <=m_spellValue->MaxAffectedTargets;++itr) +                    { +                        if ((*itr)->IsInRaidWith(m_targets.getUnitTarget())) +                        { +                            PrioritizeHealthWraper  WTarget(*itr); +                            healedMembers.push(WTarget); +                        } +                    } + +                    unitList.clear(); +                    while(!healedMembers.empty()) +                    { +                        unitList.push_back(healedMembers.top().getUnit()); +                        healedMembers.pop(); +                    } +                }                  Trinity::RandomResizeList(unitList, m_spellValue->MaxAffectedTargets);              }              for(std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr)                  AddUnitTarget(*itr, i);          } -    } // Chain or Area +    }  } -void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura) +void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura)  {      if(m_CastItem)          m_castItemGUID = m_CastItem->GetGUID(); @@ -2086,6 +2245,24 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)      m_targets = *targets; +    if(!m_targets.getUnitTargetGUID() && m_spellInfo->Targets & TARGET_FLAG_UNIT) +    { +        Unit *target = NULL; +        if(m_caster->GetTypeId() == TYPEID_UNIT) +            target = m_caster->getVictim(); +        else +            target = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection()); + +        if(target && IsValidSingleTargetSpell(target)) +            m_targets.setUnitTarget(target); +        else +        { +            SendCastResult(SPELL_FAILED_BAD_TARGETS); +            finish(false); +            return; +        } +    } +      m_spellState = SPELL_STATE_PREPARING;      m_caster->GetPosition(m_castPositionX, m_castPositionY, m_castPositionZ); @@ -2099,7 +2276,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); @@ -2136,13 +2313,13 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)      // Fill cost data      m_powerCost = CalculatePowerCost(); -    uint8 result = CanCast(true); -    if(result != 0 && !IsAutoRepeat())                      //always cast autorepeat dummy for triggering +    SpellCastResult result = CheckCast(true); +    if(result != SPELL_CAST_OK && !IsAutoRepeat())          //always cast autorepeat dummy for triggering      {          if(triggeredByAura)          {              SendChannelUpdate(0); -            triggeredByAura->SetAuraDuration(0); +            triggeredByAura->GetParentAura()->SetAuraDuration(0);          }          SendCastResult(result);          finish(false); @@ -2152,13 +2329,20 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)      // Prepare data for triggers      prepareDataForTriggerSystem(); -    // calculate cast time (calculated after first CanCast check to prevent charge counting for first CanCast fail) +    // Set combo point requirement +    if (m_IsTriggeredSpell || m_CastItem || m_caster->GetTypeId()!=TYPEID_PLAYER) +        m_needComboPoints = false; + +    // calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail)      m_casttime = GetSpellCastTime(m_spellInfo, this); +    //m_caster->ModSpellCastTime(m_spellInfo, m_casttime, this);      // set timer base at cast time      ReSetTimer(); - -    if(m_IsTriggeredSpell) +                             //Containers for channeled spells have to be set +                             //TODO:Apply this to all casted spells if needed +    // Why check duration? 29350: channelled triggers channelled +    if(m_IsTriggeredSpell && (!IsChanneledSpell(m_spellInfo) || !GetSpellMaxDuration(m_spellInfo)))          cast(true);      else      { @@ -2208,11 +2392,10 @@ void Spell::cancel()                  {                      Unit* unit = m_caster->GetGUID()==(*ihit).targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);                      if( unit && unit->isAlive() ) -                        unit->RemoveAurasByCasterSpell(m_spellInfo->Id, m_caster->GetGUID()); +                        unit->RemoveAurasDueToSpell(m_spellInfo->Id, m_caster->GetGUID(), AURA_REMOVE_BY_CANCEL);                  }              } - -            m_caster->RemoveAurasByCasterSpell(m_spellInfo->Id, m_caster->GetGUID()); +            m_caster->RemoveAurasDueToSpell(m_spellInfo->Id, m_caster->GetGUID(), AURA_REMOVE_BY_CANCEL);              SendChannelUpdate(0);              SendInterrupted(0);              SendCastResult(SPELL_FAILED_INTERRUPTED); @@ -2236,8 +2419,6 @@ void Spell::cast(bool skipCheck)  {      SetExecutedCurrently(true); -    uint8 castResult = 0; -      // update pointers base at GUIDs to prevent access to non-existed already object      UpdatePointers(); @@ -2252,23 +2433,12 @@ void Spell::cast(bool skipCheck)      if(m_caster->GetTypeId() != TYPEID_PLAYER && m_targets.getUnitTarget() && m_targets.getUnitTarget() != m_caster)          m_caster->SetInFront(m_targets.getUnitTarget()); -    if(!m_IsTriggeredSpell) -    { -        castResult = CheckPower(); -        if(castResult != 0) -        { -            SendCastResult(castResult); -            finish(false); -            SetExecutedCurrently(false); -            return; -        } -    }      // triggered cast called from Spell::prepare where it was already checked -    if(!skipCheck) +    if(!m_IsTriggeredSpell || !skipCheck)      { -        castResult = CanCast(false); -        if(castResult != 0) +        SpellCastResult castResult = CheckCast(false); +        if(castResult != SPELL_CAST_OK)          {              SendCastResult(castResult);              finish(false); @@ -2279,19 +2449,62 @@ 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 && !IsPositiveSpell(m_spellInfo->excludeCasterAuraSpell)) +            m_preCastSpell = m_spellInfo->excludeCasterAuraSpell; +        else if (m_spellInfo->excludeTargetAuraSpell && !IsPositiveSpell(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; +        }      } -      // 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_IsTriggeredSpell && 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); +    } + +    // this is related to combo points so must be done before takepower +    // are there any spells need to be triggered after hit? +    // handle SPELL_AURA_ADD_TARGET_TRIGGER auras +    Unit::AuraEffectList const& targetTriggers = m_caster->GetAurasByType(SPELL_AURA_ADD_TARGET_TRIGGER); +    for(Unit::AuraEffectList::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(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)->GetParentAura()->GetStackAmount())); +        } +    } + +    // this is related to combo points so must be done before takepower +    if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE) +        CalculateDamageDoneForAllTargets(); +      if(!m_IsTriggeredSpell)      { -        //TakePower(); +        // Powers have to be taken before SendSpellGo +        TakePower();          TakeReagents();                                         // we must remove reagents before HandleEffects to allow place crafted item in same slot      } @@ -2300,30 +2513,23 @@ void Spell::cast(bool skipCheck)      //SendCastResult(castResult);      SendSpellGo();                                          // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()... -    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? -    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(m_customAttr & SPELL_ATTR_CU_CHARGE)      { -        SpellEntry const *auraSpellInfo = (*i)->GetSpellProto(); -        uint32 auraSpellIdx = (*i)->GetEffIndex(); -        if (IsAffectedBy(auraSpellInfo, auraSpellIdx)) +        for(uint32 i = 0; i < 3; ++i)          { -            if(SpellEntry const *spellInfo = sSpellStore.LookupEntry(auraSpellInfo->EffectTriggerSpell[auraSpellIdx])) +            switch(m_spellInfo->Effect[i])              { -                // 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())); +                case SPELL_EFFECT_CHARGE: +                case SPELL_EFFECT_JUMP: +                case SPELL_EFFECT_JUMP2: +                case SPELL_EFFECT_138: +                    HandleEffects(NULL,NULL,NULL,i); +                    m_effectMask |= (1<<i); +                    break;              }          }      } -    if(m_customAttr & SPELL_ATTR_CU_CHARGE) -        EffectCharge(0); -      // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells      if (m_spellInfo->speed > 0.0f && !IsChanneledSpell(m_spellInfo))      { @@ -2342,12 +2548,6 @@ void Spell::cast(bool skipCheck)          handle_immediate();      } -    // combo points should not be taken before SPELL_AURA_ADD_TARGET_TRIGGER auras are handled -    if(!m_IsTriggeredSpell) -    { -        TakePower(); -    } -      if(m_customAttr & SPELL_ATTR_CU_LINK_CAST)      {          if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(m_spellInfo->Id)) @@ -2366,9 +2566,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, this); +            // 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 @@ -2485,14 +2694,22 @@ void Spell::_handle_immediate_phase()              if(!m_targets.HasDst()) // FIXME: this will ignore dest set in effect                  m_targets.setDestination(m_caster);              HandleEffects(m_originalCaster, NULL, NULL, j); +            m_effectMask |= (1<<j);          }          else if(spellmgr.EffectTargetType[m_spellInfo->Effect[j]] == SPELL_REQUIRE_NONE) +        {              HandleEffects(m_originalCaster, NULL, NULL, j); +            m_effectMask |= (1<<j); +        }      }  }  void Spell::_handle_finish_phase()  { +    // Take for real after all targets are processed +    if (m_needComboPoints) +        ((Player*)m_caster)->ClearComboPoints(); +      // spell log      if(m_needSpellLog)          SendLogExecute(); @@ -2504,93 +2721,20 @@ void Spell::SendSpellCooldown()          return;      Player* _player = (Player*)m_caster; -    // Add cooldown for max (disable spell) -    // Cooldown started on SendCooldownEvent call -    if (m_spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) -    { -        _player->AddSpellCooldown(m_spellInfo->Id, 0, time(NULL) - 1); -        return; -    } - -    // init cooldown values -    uint32 cat   = 0; -    int32 rec    = -1; -    int32 catrec = -1; - -    // some special item spells without correct cooldown in SpellInfo -    // cooldown information stored in item prototype -    // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client. - -    if(m_CastItem) -    { -        ItemPrototype const* proto = m_CastItem->GetProto(); -        if(proto) -        { -            for(int idx = 0; idx < 5; ++idx) -            { -                if(proto->Spells[idx].SpellId == m_spellInfo->Id) -                { -                    cat    = proto->Spells[idx].SpellCategory; -                    rec    = proto->Spells[idx].SpellCooldown; -                    catrec = proto->Spells[idx].SpellCategoryCooldown; -                    break; -                } -            } -        } -    } -    // if no cooldown found above then base at DBC data -    if(rec < 0 && catrec < 0) +    // mana/health/etc potions, disabled by client (until combat out as declarate) +    if (m_CastItem && m_CastItem->IsPotion())      { -        cat = m_spellInfo->Category; -        rec = m_spellInfo->RecoveryTime; -        catrec = m_spellInfo->CategoryRecoveryTime; +        // need in some way provided data for Spell::finish SendCooldownEvent +        _player->SetLastPotionId(m_CastItem->GetEntry()); +        return;      } -    // 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)) -        rec = _player->GetAttackTime(RANGED_ATTACK); - -    // Now we have cooldown data (if found any), time to apply mods -    if(rec > 0) -        _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, rec, this); - -    if(catrec > 0) -        _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, catrec, this); - -    // replace negative cooldowns by 0 -    if (rec < 0) rec = 0; -    if (catrec < 0) catrec = 0; - -    // no cooldown after applying spell mods -    if( rec == 0 && catrec == 0) +    // have infinity cooldown but set at aura apply                  // do not set cooldown for triggered spells (needed by reincarnation) +    if(m_spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE || m_IsTriggeredSpell)          return; -    time_t curTime = time(NULL); - -    time_t catrecTime = catrec ? curTime+catrec/1000 : 0;   // in secs -    time_t recTime    = rec ? curTime+rec/1000 : catrecTime;// in secs - -    // self spell cooldown -    if(recTime > 0) -        _player->AddSpellCooldown(m_spellInfo->Id, m_CastItem ? m_CastItem->GetEntry() : 0, recTime); - -    // category spells -    if (catrec > 0) -    { -        SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat); -        if(i_scstore != sSpellCategoryStore.end()) -        { -            for(SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset) -            { -                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->AddSpellAndCategoryCooldowns(m_spellInfo,m_CastItem ? m_CastItem->GetEntry() : 0, this);  }  void Spell::update(uint32 difftime) @@ -2649,8 +2793,9 @@ void Spell::update(uint32 difftime)                  }                  // check if there are alive targets left -                if (!IsAliveUnitPresentInTargetList()) +                if (!UpdateChanneledTargetList())                  { +                    sLog.outDebug("Channeled spell %d is removed due to lack of targets", m_spellInfo->Id);                      SendChannelUpdate(0);                      finish();                  } @@ -2668,30 +2813,33 @@ void Spell::update(uint32 difftime)                  // channeled spell processed independently for quest targeting                  // cast at creature (or GO) quest objectives update at successful cast channel finished                  // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... ) -                if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() ) +                if( !IsAutoRepeat() && !IsNextMeleeSwingSpell() )                  { -                    for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) +                    if ( Player* p = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself() )                      { -                        TargetInfo* target = &*ihit; -                        if(!IS_CREATURE_GUID(target->targetGUID)) -                            continue; +                        for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) +                        { +                            TargetInfo* target = &*ihit; +                            if(!IS_CREATURE_GUID(target->targetGUID)) +                                continue; -                        Unit* unit = m_caster->GetGUID()==target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster,target->targetGUID); -                        if (unit==NULL) -                            continue; +                            Unit* unit = m_caster->GetGUID()==target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster,target->targetGUID); +                            if (unit==NULL) +                                continue; -                        ((Player*)m_caster)->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id); -                    } +                            p->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id); +                        } -                    for(std::list<GOTargetInfo>::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit) -                    { -                        GOTargetInfo* target = &*ihit; +                        for(std::list<GOTargetInfo>::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit) +                        { +                            GOTargetInfo* target = &*ihit; -                        GameObject* go = ObjectAccessor::GetGameObject(*m_caster, target->targetGUID); -                        if(!go) -                            continue; +                            GameObject* go = m_caster->GetMap()->GetGameObject(target->targetGUID); +                            if(!go) +                                continue; -                        ((Player*)m_caster)->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id); +                            p->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id); +                        }                      }                  } @@ -2711,7 +2859,6 @@ void Spell::finish(bool ok)      if(m_spellState == SPELL_STATE_FINISHED)          return; -      m_spellState = SPELL_STATE_FINISHED;      if(IsChanneledSpell(m_spellInfo)) @@ -2720,20 +2867,50 @@ void Spell::finish(bool ok)      if(!m_caster->IsNonMeleeSpellCasted(false, false, true))          m_caster->clearUnitState(UNIT_STAT_CASTING); +    // Unsummon summon as possessed creatures on spell cancel +    if(IsChanneledSpell(m_spellInfo) && m_caster->GetTypeId() == TYPEID_PLAYER) +    { +        if (Unit * charm = m_caster->GetCharm()) +        for(int i = 0; i < 3; ++i) +        { +            if(m_spellInfo->Effect[i] == SPELL_EFFECT_SUMMON) +                if(SummonPropertiesEntry const *SummonProperties = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i])) +                    if(SummonProperties->Category == SUMMON_CATEGORY_POSSESSED) +                    { +                        if(charm->GetTypeId() == TYPEID_UNIT) +                        { +                            if(((Creature*)charm)->isPet() && ((Pet*)charm)->getPetType() == POSSESSED_PET) +                                ((Pet*)charm)->Remove(PET_SAVE_AS_DELETED); +                                    break; +                        } +                    } +        } +    } +      // other code related only to successfully finished spells      if(!ok)          return; +    if (m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isSummon()) +    { +        // Unsummon statue +        uint32 spell = m_caster->GetUInt32Value(UNIT_CREATED_BY_SPELL); +        SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell ); +        if (spellInfo && spellInfo->SpellIconID==2056) +        { +            sLog.outDebug("Statue %d is unsummoned in spell %d finish", m_caster->GetGUIDLow(), m_spellInfo->Id); +            m_caster->setDeathState(JUST_DIED); +            return; +        } +    } +      //remove spell mods      if (m_caster->GetTypeId() == TYPEID_PLAYER)          ((Player*)m_caster)->RemoveSpellMods(this);      // Heal caster for all health leech from all targets      if (m_healthLeech) -    { -        m_caster->ModifyHealth(m_healthLeech); -        m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(m_healthLeech)); -    } +        m_caster->DealHeal(m_caster, uint32(m_healthLeech), m_spellInfo);      if (IsMeleeAttackResetSpell())      { @@ -2744,6 +2921,10 @@ void Spell::finish(bool ok)              m_caster->resetAttackTimer(RANGED_ATTACK);      } +    // potions disabled by client, send event "not in combat" if need +    if (!m_triggeredByAuraSpell && m_caster->GetTypeId() == TYPEID_PLAYER) +        ((Player*)m_caster)->UpdatePotionCooldown(this); +      // call triggered spell only at successful cast (after clear combo points -> for add some if need)      // I assume what he means is that some triggered spells may add combo points      if(!m_TriggerSpells.empty()) @@ -2754,72 +2935,67 @@ void Spell::finish(bool ok)          m_caster->AttackStop();  } -void Spell::SendCastResult(uint8 result) +void Spell::SendCastResult(SpellCastResult result)  { +    if(result == SPELL_CAST_OK) +        return; +      if (m_caster->GetTypeId() != TYPEID_PLAYER)          return;      if(((Player*)m_caster)->GetSession()->PlayerLoading())  // don't send cast results at loading time          return; -    if(result != 0) -    { -        WorldPacket data(SMSG_CAST_FAILED, (4+1+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: -                data << uint32(m_spellInfo->RequiresSpellFocus); -                break; -            case SPELL_FAILED_REQUIRES_AREA: -                // hardcode areas limitation case -                switch(m_spellInfo->Id) -                { -                    case 41617:                             // Cenarion Mana Salve -                    case 41619:                             // Cenarion Healing Salve -                        data << uint32(3905); -                        break; -                    case 41618:                             // Bottled Nethergon Energy -                    case 41620:                             // Bottled Nethergon Vapor -                        data << uint32(3842); -                        break; -                    case 45373:                             // Bloodberry Elixir -                        data << uint32(4075); -                        break; -                    default:                                // default case -                        data << uint32(m_spellInfo->AreaId); -                        break; -                } -                break; -            case SPELL_FAILED_TOTEMS: -                if(m_spellInfo->Totem[0]) -                    data << uint32(m_spellInfo->Totem[0]); -                if(m_spellInfo->Totem[1]) -                    data << uint32(m_spellInfo->Totem[1]); -                break; -            case SPELL_FAILED_TOTEM_CATEGORY: -                if(m_spellInfo->TotemCategory[0]) -                    data << uint32(m_spellInfo->TotemCategory[0]); -                if(m_spellInfo->TotemCategory[1]) -                    data << uint32(m_spellInfo->TotemCategory[1]); -                break; -            case SPELL_FAILED_EQUIPPED_ITEM_CLASS: -                data << uint32(m_spellInfo->EquippedItemClass); -                data << uint32(m_spellInfo->EquippedItemSubClassMask); -                data << uint32(m_spellInfo->EquippedItemInventoryTypeMask); -                break; -        } -        ((Player*)m_caster)->GetSession()->SendPacket(&data); -    } -    else +    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 +    switch (result)      { -        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); +        case SPELL_FAILED_REQUIRES_SPELL_FOCUS: +            data << uint32(m_spellInfo->RequiresSpellFocus); +            break; +        case SPELL_FAILED_REQUIRES_AREA: +            // hardcode areas limitation case +            switch(m_spellInfo->Id) +            { +                case 41617:                                 // Cenarion Mana Salve +                case 41619:                                 // Cenarion Healing Salve +                    data << uint32(3905); +                    break; +                case 41618:                                 // Bottled Nethergon Energy +                case 41620:                                 // Bottled Nethergon Vapor +                    data << uint32(3842); +                    break; +                case 45373:                                 // Bloodberry Elixir +                    data << uint32(4075); +                    break; +                default:                                    // default case (don't must be) +                    data << uint32(0); +                    break; +            } +            break; +        case SPELL_FAILED_TOTEMS: +            if(m_spellInfo->Totem[0]) +                data << uint32(m_spellInfo->Totem[0]); +            if(m_spellInfo->Totem[1]) +                data << uint32(m_spellInfo->Totem[1]); +            break; +        case SPELL_FAILED_TOTEM_CATEGORY: +            if(m_spellInfo->TotemCategory[0]) +                data << uint32(m_spellInfo->TotemCategory[0]); +            if(m_spellInfo->TotemCategory[1]) +                data << uint32(m_spellInfo->TotemCategory[1]); +            break; +        case SPELL_FAILED_EQUIPPED_ITEM_CLASS: +            data << uint32(m_spellInfo->EquippedItemClass); +            data << uint32(m_spellInfo->EquippedItemSubClassMask); +            //data << uint32(m_spellInfo->EquippedItemInventoryTypeMask); +            break; +        default: +            break;      } +    ((Player*)m_caster)->GetSession()->SendPacket(&data);  }  void Spell::SendSpellStart() @@ -2830,10 +3006,15 @@ void Spell::SendSpellStart()      sLog.outDebug("Sending SMSG_SPELL_START id=%u", m_spellInfo->Id);      uint32 castFlags = CAST_FLAG_UNKNOWN1; -    if(IsRangedSpell()) +    if(m_spellInfo->Attributes & SPELL_ATTR_REQ_AMMO)          castFlags |= CAST_FLAG_AMMO; +    if ((m_caster->GetTypeId() == TYPEID_PLAYER || +        (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->isPet())) +         && m_spellInfo->powerType != POWER_HEALTH ) +        castFlags |= CAST_FLAG_POWER_LEFT_SELF; -    Unit *target = m_targets.getUnitTarget() ? m_targets.getUnitTarget() : m_caster; +    if(m_spellInfo->runeCostID) +        castFlags |= CAST_FLAG_UNKNOWN10;      WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2));      if(m_CastItem) @@ -2842,14 +3023,17 @@ 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_POWER_LEFT_SELF) +        data << uint32(m_caster->GetPower((Powers)m_spellInfo->powerType)); + +    if ( castFlags & CAST_FLAG_AMMO )          WriteAmmoToPacket(&data);      m_caster->SendMessageToSet(&data, true); @@ -2863,30 +3047,75 @@ void Spell::SendSpellGo()      sLog.outDebug("Sending SMSG_SPELL_GO id=%u", m_spellInfo->Id); -    Unit *target = m_targets.getUnitTarget() ? m_targets.getUnitTarget() : m_caster; -      uint32 castFlags = CAST_FLAG_UNKNOWN3; -    if(IsRangedSpell()) +    if(m_spellInfo->Attributes & SPELL_ATTR_REQ_AMMO)          castFlags |= CAST_FLAG_AMMO;                        // arrows/bullets visual +    if ((m_caster->GetTypeId() == TYPEID_PLAYER || +        (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->isPet())) +        && m_spellInfo->powerType != POWER_HEALTH ) +        castFlags |= CAST_FLAG_POWER_LEFT_SELF; // should only be sent to self, but the current messaging doesn't make that possible + +    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_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_POWER_LEFT_SELF) +        data << uint32(m_caster->GetPower((Powers)m_spellInfo->powerType)); + +    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);  } @@ -2931,15 +3160,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 @@ -2950,6 +3200,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() @@ -3014,30 +3267,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()) @@ -3056,6 +3298,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;              } @@ -3069,13 +3318,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);  } @@ -3119,7 +3371,7 @@ void Spell::SendChannelStart(uint32 duration)          {              if(itr->effectMask & (1<<0) )              { -                target = ObjectAccessor::GetGameObject(*m_caster, itr->targetGUID); +                target = m_caster->GetMap()->GetGameObject(itr->targetGUID);                  break;              }          } @@ -3143,10 +3395,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);  } @@ -3183,7 +3444,7 @@ void Spell::TakeCastItem()      bool expendable = false;      bool withoutCharges = false; -    for (int i = 0; i<5; i++) +    for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)      {          if (proto->Spells[i].SpellId)          { @@ -3199,7 +3460,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);                  } @@ -3225,7 +3486,7 @@ void Spell::TakeCastItem()  void Spell::TakePower()  { -    if(m_CastItem || m_triggeredByAuraSpell || !m_powerCost) +    if(m_CastItem || m_triggeredByAuraSpell)          return;      bool hit = true; @@ -3238,12 +3499,27 @@ 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)) -            ((Player*)m_caster)->ClearComboPoints();      } +    Powers powerType = Powers(m_spellInfo->powerType); + +    if(powerType == POWER_RUNE) +    { +        TakeRunePower(); +        return; +    } + +    if (!m_powerCost) +        return; +      // health as power used      if(m_spellInfo->powerType == POWER_HEALTH)      { @@ -3257,8 +3533,6 @@ void Spell::TakePower()          return;      } -    Powers powerType = Powers(m_spellInfo->powerType); -      if(hit)          m_caster->ModifyPower(powerType, -m_powerCost);      else @@ -3269,6 +3543,136 @@ 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); +    } +} + +SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) +{ +    if(m_caster->GetTypeId() != TYPEID_PLAYER) +        return SPELL_CAST_OK; + +    Player *plr = (Player*)m_caster; + +    if(plr->getClass() != CLASS_DEATH_KNIGHT) +        return SPELL_CAST_OK; + +    SpellRuneCostEntry const *src = sSpellRuneCostStore.LookupEntry(runeCostID); + +    if(!src) +        return SPELL_CAST_OK; + +    if(src->NoRuneCost()) +        return SPELL_CAST_OK; + +    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] = MAX_RUNES;                       // 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] > MAX_RUNES) +        return SPELL_FAILED_NO_POWER;                       // not sure if result code is correct + +    return SPELL_CAST_OK; +} + +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. @@ -3277,11 +3681,13 @@ 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)) +    // do not take reagents for these item casts +    if (m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_TRIGGERED_CAST)          return;      Player* p_caster = (Player*)m_caster; +    if (p_caster->CanNoReagentCast(m_spellInfo)) +        return;      for(uint32 x=0;x<8;x++)      { @@ -3297,7 +3703,7 @@ void Spell::TakeReagents()              ItemPrototype const *proto = m_CastItem->GetProto();              if( proto && proto->ItemId == itemid )              { -                for(int s=0;s<5;s++) +                for(int s=0;s < MAX_ITEM_PROTO_SPELLS; ++s)                  {                      // CastItem will be used up and does not count as reagent                      int32 charges = m_CastItem->GetSpellCharges(s); @@ -3337,20 +3743,19 @@ void Spell::HandleThreatSpells(uint32 spellId)      DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threatSpell->threat);  } -void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i, float /*DamageMultiplier*/) +void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i)  { +    //effect has been handled, skip it +    if(m_effectMask & (1<<i)) +        return; +      unitTarget = pUnitTarget;      itemTarget = pItemTarget;      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; +    sLog.outDebug( "Spell: %u Effect : %u", m_spellInfo->Id, eff);      //we do not need DamageMultiplier here.      damage = CalculateDamage(i, NULL); @@ -3358,21 +3763,8 @@ void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTar      if(eff<TOTAL_SPELL_EFFECTS)      {          //sLog.outDebug( "WORLD: Spell FX %d < TOTAL_SPELL_EFFECTS ", eff); -        (*this.*SpellEffects[eff])(i); +        (this->*SpellEffects[eff])(i);      } -    /* -    else -    { -        sLog.outDebug( "WORLD: Spell FX %d > TOTAL_SPELL_EFFECTS ", eff); -        if (m_CastItem) -            EffectEnchantItemTmp(i); -        else -        { -            sLog.outError("SPELL: unknown effect %u spell id %u\n", -                eff, m_spellInfo->Id); -        } -    } -    */  }  void Spell::TriggerSpell() @@ -3384,11 +3776,14 @@ void Spell::TriggerSpell()      }  } -uint8 Spell::CanCast(bool strict) +SpellCastResult Spell::CheckCast(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 @@ -3405,19 +3800,59 @@ 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::AuraEffectList const& ignore = m_caster->GetAurasByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT); +        for(Unit::AuraEffectList::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 +            SpellCastResult shapeError = GetErrorAtShapeshiftedCast(m_spellInfo, m_caster->m_form); +            if(shapeError != SPELL_CAST_OK) +                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; +        }      } -    // 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; +    bool reqCombat=true; +    Unit::AuraEffectList const& stateAuras = m_caster->GetAurasByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE); +    for(Unit::AuraEffectList::const_iterator j = stateAuras.begin();j != stateAuras.end(); ++j) +    { +        if((*j)->isAffectedOnSpell(m_spellInfo)) +        { +            if ((*j)->GetMiscValue()==1) +            { +                reqCombat=false; +                break; +            } +        } +    } + +    // caster state requirements  +    // not for triggered spells (needed by execute) +    if (!m_IsTriggeredSpell) +    { +        if(m_spellInfo->CasterAuraState && !m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraState), m_spellInfo, m_caster)) +            return SPELL_FAILED_CASTER_AURASTATE; +        if(m_spellInfo->CasterAuraStateNot && m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraStateNot), m_spellInfo, m_caster)) +            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(reqCombat && m_caster->isInCombat() && IsNonCombatSpell(m_spellInfo)) +            return SPELL_FAILED_AFFECTING_COMBAT; +    }      // cancel autorepeat spells if cast start when moving      // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code) @@ -3429,22 +3864,26 @@ uint8 Spell::CanCast(bool strict)              return SPELL_FAILED_MOVING;      } -    Unit *target = m_targets.getUnitTarget(); - -    if(target) +    if(Unit *target = m_targets.getUnitTarget())      {          // target state requirements (not allowed state), apply to self also -        if(m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot))) +        if(!m_IsTriggeredSpell && m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot), m_spellInfo, m_caster)) +            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(!m_IsTriggeredSpell && m_spellInfo->TargetAuraState && !target->HasAuraState(AuraState(m_spellInfo->TargetAuraState), m_spellInfo, m_caster))                  return SPELL_FAILED_TARGET_AURASTATE;              // Not allow casting on flying player -            if (target->isInFlight()) +            if (target->hasUnitState(UNIT_STAT_UNATTACKABLE))                  return SPELL_FAILED_BAD_TARGETS;              if(!m_IsTriggeredSpell && VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target)) @@ -3453,13 +3892,23 @@ uint8 Spell::CanCast(bool strict)              // auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode              // this case can be triggered if rank not found (too low-level target for first rank)              if(m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem) -            {                  for(int i=0;i<3;i++) -                {                      if(IsPositiveEffect(m_spellInfo->Id, i) && m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA)                          if(target->getLevel() + 10 < m_spellInfo->spellLevel)                              return SPELL_FAILED_LOWLEVEL; -                } +        } +        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_UNIT_TARGET_ENEMY) +            { +                if (target = m_caster->GetUnit(*m_caster, ((Player *)m_caster)->GetSelection())) +                    m_targets.setUnitTarget(target); +                else +                    return SPELL_FAILED_BAD_TARGETS;              }          } @@ -3468,7 +3917,7 @@ uint8 Spell::CanCast(bool strict)          {              if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_PET)              { -                target = m_caster->GetPet(); +                target = m_caster->GetGuardianPet();                  if(!target)                  {                      if(m_triggeredByAuraSpell)              // not report pet not existence for triggered spells @@ -3512,14 +3961,15 @@ 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; @@ -3534,10 +3984,9 @@ uint8 Spell::CanCast(bool strict)          // check if target is in combat          if (target != m_caster && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat()) -        {              return SPELL_FAILED_TARGET_AFFECTING_COMBAT; -        }      } +      // Spell casted only on battleground      if((m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_BATTLEGROUND) &&  m_caster->GetTypeId()==TYPEID_PLAYER)          if(!((Player*)m_caster)->InBattleGround()) @@ -3547,14 +3996,22 @@ uint8 Spell::CanCast(bool strict)      // - with greater than 15 min CD without SPELL_ATTR_EX4_USABLE_IN_ARENA flag      // - with SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA flag      if( (m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA) || -        GetSpellRecoveryTime(m_spellInfo) > 15 * MINUTE * 1000 && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA) ) +        GetSpellRecoveryTime(m_spellInfo) > 15 * MINUTE * IN_MILISECONDS && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA) )          if(MapEntry const* mapEntry = sMapStore.LookupEntry(m_caster->GetMapId()))              if(mapEntry->IsBattleArena())                  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(m_caster->GetTypeId() == TYPEID_UNIT || !((Player*)m_caster)->isGameMaster()) +    { +        uint32 zone, area; +        m_caster->GetZoneAndAreaId(zone,area); + +        SpellCastResult locRes= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),zone,area, +            m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL); +        if(locRes != SPELL_CAST_OK) +            return locRes; +    }      // not let players cast spells at mount (and let do it to creatures)      if( m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell && @@ -3568,11 +4025,14 @@ uint8 Spell::CanCast(bool strict)      // always (except passive spells) check items (focus object can be required for any type casts)      if(!IsPassiveSpell(m_spellInfo->Id)) -        if(uint8 castResult = CheckItems()) +    { +        SpellCastResult castResult = CheckItems(); +        if(castResult != SPELL_CAST_OK)              return castResult; +    }      /*//ImpliciteTargetA-B = 38, If fact there is 0 Spell with  ImpliciteTargetB=38 -    if(m_UniqueTargetInfo.empty())                          // skip second canCast apply (for delayed spells for example) +    if(m_UniqueTargetInfo.empty())                          // skip second CheckCast apply (for delayed spells for example)      {          for(uint8 j = 0; j < 3; j++)          { @@ -3607,7 +4067,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); @@ -3645,7 +4105,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); @@ -3708,13 +4168,16 @@ uint8 Spell::CanCast(bool strict)      if(!m_IsTriggeredSpell)      { -        if(uint8 castResult = CheckRange(strict)) +        SpellCastResult castResult = CheckRange(strict); +        if(castResult != SPELL_CAST_OK)              return castResult; -        if(uint8 castResult = CheckPower()) +        castResult = CheckPower(); +        if(castResult != SPELL_CAST_OK)              return castResult; -        if(uint8 castResult = CheckCasterAuras()) +        castResult = CheckCasterAuras(); +        if(castResult != SPELL_CAST_OK)              return castResult;      } @@ -3725,12 +4188,7 @@ uint8 Spell::CanCast(bool strict)          {              case SPELL_EFFECT_DUMMY:              { -                if(m_spellInfo->SpellIconID == 1648)        // Execute -                { -                    if(!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2) -                        return SPELL_FAILED_BAD_TARGETS; -                } -                else if (m_spellInfo->Id == 51582)          // Rocket Boots Engaged +                if (m_spellInfo->Id == 51582)          // Rocket Boots Engaged                  {                      if(m_caster->IsInWater())                          return SPELL_FAILED_ONLY_ABOVEWATER; @@ -3739,7 +4197,7 @@ uint8 Spell::CanCast(bool strict)                  {                      // spell different for friends and enemies                      // hart version required facing -                    if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, target )) +                    if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, m_targets.getUnitTarget() ))                          return SPELL_FAILED_UNIT_NOT_INFRONT;                  }                  else if (m_spellInfo->Id == 19938)          // Awaken Peon @@ -3750,25 +4208,15 @@ uint8 Spell::CanCast(bool strict)                  }                  break;              } -            case SPELL_EFFECT_SCHOOL_DAMAGE: -            { -                // Hammer of Wrath -                if(m_spellInfo->SpellVisual == 7250) -                { -                    if (!m_targets.getUnitTarget()) -                        return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - -                    if(m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2) -                        return SPELL_FAILED_BAD_TARGETS; -                } -                break; -            }              case SPELL_EFFECT_LEARN_SPELL:              { +                if (m_caster->GetTypeId() != TYPEID_PLAYER) +                    return SPELL_FAILED_BAD_TARGETS; +                  if(m_spellInfo->EffectImplicitTargetA[i] != TARGET_UNIT_PET)                      break; -                Pet* pet = m_caster->GetPet(); +                Pet* pet = ((Player*)m_caster)->GetPet();                  if(!pet)                      return SPELL_FAILED_NO_PET; @@ -3778,21 +4226,17 @@ 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:              { -                Pet* pet = m_caster->GetPet(); +                if (m_caster->GetTypeId() != TYPEID_PLAYER) +                    return SPELL_FAILED_BAD_TARGETS; +                Pet* pet = ((Player*)m_caster)->GetPet();                  if(!pet)                      return SPELL_FAILED_NO_PET; @@ -3801,31 +4245,29 @@ 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; -                Pet* pet = m_caster->GetPet(); +                Item* foodItem = m_targets.getItemTarget(); +                if(!foodItem) +                    return SPELL_FAILED_BAD_TARGETS; + +                Pet* pet = ((Player*)m_caster)->GetPet();                  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()) @@ -3897,130 +4339,40 @@ uint8 Spell::CanCast(bool strict)                  // In BattleGround players can use only flags and banners                  if( ((Player*)m_caster)->InBattleGround() && -                    !((Player*)m_caster)->isAllowUseBattleGroundObject() ) +                    !((Player*)m_caster)->CanUseBattleGroundObject() )                      return SPELL_FAILED_TRY_AGAIN;                  // get the lock entry -                LockEntry const *lockInfo = NULL; +                uint32 lockId = 0;                  if (GameObject* go=m_targets.getGOTarget()) -                    lockInfo = sLockStore.LookupEntry(go->GetLockId()); +                    lockId = go->GetLockId();                  else if(Item* itm=m_targets.getItemTarget()) -                    lockInfo = sLockStore.LookupEntry(itm->GetProto()->LockID); - -                // check lock compatibility -                if (lockInfo) -                { -                    // check for lock - key pair (checked by client also, just prevent cheating -                    bool ok_key = false; -                    for(int it = 0; it < 5; ++it) -                    { -                        switch(lockInfo->keytype[it]) -                        { -                            case LOCK_KEY_NONE: -                                break; -                            case LOCK_KEY_ITEM: -                            { -                                if(lockInfo->key[it]) -                                { -                                    if(m_CastItem && m_CastItem->GetEntry()==lockInfo->key[it]) -                                        ok_key =true; -                                    break; -                                } -                            } -                            case LOCK_KEY_SKILL: -                            { -                                if(uint32(m_spellInfo->EffectMiscValue[i])!=lockInfo->key[it]) -                                    break; +                    lockId = itm->GetProto()->LockID; -                                switch(lockInfo->key[it]) -                                { -                                    case LOCKTYPE_HERBALISM: -                                        if(((Player*)m_caster)->HasSkill(SKILL_HERBALISM)) -                                            ok_key =true; -                                        break; -                                    case LOCKTYPE_MINING: -                                        if(((Player*)m_caster)->HasSkill(SKILL_MINING)) -                                            ok_key =true; -                                        break; -                                    default: -                                        ok_key =true; -                                        break; -                                } -                            } -                        } -                        if(ok_key) -                            break; -                    } +                SkillType skillId =SKILL_NONE; +                int32 reqSkillValue = 0; +                int32 skillValue = 0; -                    if(!ok_key) -                        return SPELL_FAILED_BAD_TARGETS; -                } +                // check lock compatibility +                SpellCastResult res = CanOpenLock(i,lockId,skillId,reqSkillValue,skillValue); +                if(res != SPELL_CAST_OK) +                    return res;                  // chance for fail at orange mining/herb/LockPicking gathering attempt -                if (!m_selfContainer || ((*m_selfContainer) != this)) -                    break; - -                // get the skill value of the player -                int32 SkillValue = 0; -                bool canFailAtMax = true; -                if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_HERBALISM) +                // second check prevent fail at rechecks +                if(skillId != SKILL_NONE && (!m_selfContainer || ((*m_selfContainer) != this)))                  { -                    SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_HERBALISM); -                    canFailAtMax = false; -                } -                else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_MINING) -                { -                    SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_MINING); -                    canFailAtMax = false; -                } -                else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK) -                    SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_LOCKPICKING); - -                // castitem check: rogue using skeleton keys. the skill values should not be added in this case. -                if(m_CastItem) -                    SkillValue = 0; +                    bool canFailAtMax = skillId != SKILL_HERBALISM && skillId != SKILL_MINING; -                // add the damage modifier from the spell casted (cheat lock / skeleton key etc.) (use m_currentBasePoints, CalculateDamage returns wrong value) -                // TODO: is this a hack? -                SkillValue += m_currentBasePoints[i]+1; - -                // get the required lock value -                int32 ReqValue=0; -                if (lockInfo) -                { -                    // check for lock - key pair -                    bool ok = false; -                    for(int it = 0; it < 5; ++it) -                    { -                        if(lockInfo->keytype[it]==LOCK_KEY_ITEM && lockInfo->key[it] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[it]) -                        { -                            // if so, we're good to go -                            ok = true; -                            break; -                        } -                    } -                    if(ok) -                        break; - -                    if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK) -                        ReqValue = lockInfo->requiredlockskill; -                    else -                        ReqValue = lockInfo->requiredminingskill; +                    // chance for failure in orange gather / lockpick (gathering skill can't fail at maxskill) +                    if((canFailAtMax || skillValue < sWorld.GetConfigMaxSkillValue()) && reqSkillValue > irand(skillValue-25, skillValue+37)) +                        return SPELL_FAILED_TRY_AGAIN;                  } - -                // skill doesn't meet the required value -                if (ReqValue > SkillValue) -                    return SPELL_FAILED_LOW_CASTLEVEL; - -                // chance for failure in orange gather / lockpick (gathering skill can't fail at maxskill) -                if((canFailAtMax || SkillValue < sWorld.GetConfigMaxSkillValue()) && ReqValue > irand(SkillValue-25, SkillValue+37)) -                    return SPELL_FAILED_TRY_AGAIN; -                  break;              }              case SPELL_EFFECT_SUMMON_DEAD_PET:              { -                Creature *pet = m_caster->GetPet(); +                Creature *pet = m_caster->GetGuardianPet();                  if(!pet)                      return SPELL_FAILED_NO_PET; @@ -4029,18 +4381,16 @@ 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]) +                SummonPropertiesEntry const *SummonProperties = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]); +                if(!SummonProperties) +                    break; +                switch(SummonProperties->Category)                  { -                    case SUMMON_TYPE_POSESSED: -                    case SUMMON_TYPE_POSESSED2: -                    case SUMMON_TYPE_POSESSED3: -                    case SUMMON_TYPE_DEMON: -                    case SUMMON_TYPE_SUMMON: +                    case SUMMON_CATEGORY_PET: +                    case SUMMON_CATEGORY_POSSESSED:                      {                          if(m_caster->GetPetGUID())                              return SPELL_FAILED_ALREADY_HAVE_SUMMON; @@ -4052,11 +4402,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; @@ -4070,13 +4417,11 @@ uint8 Spell::CanCast(bool strict)              {                  if(m_caster->GetPetGUID())                  //let warlock do a replacement summon                  { - -                    Pet* pet = ((Player*)m_caster)->GetPet(); -                      if (m_caster->GetTypeId()==TYPEID_PLAYER && m_caster->getClass()==CLASS_WARLOCK)                      {                          if (strict)                         //starting cast, trigger pet stun (cast by pet so it doesn't attack player) -                            pet->CastSpell(pet, 32752, true, NULL, NULL, pet->GetGUID()); +                            if(Pet* pet = ((Player*)m_caster)->GetPet()) +                                pet->CastSpell(pet, 32752, true, NULL, NULL, pet->GetGUID());                      }                      else                          return SPELL_FAILED_ALREADY_HAVE_SUMMON; @@ -4112,7 +4457,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 @@ -4148,25 +4493,38 @@ uint8 Spell::CanCast(bool strict)          {              case SPELL_AURA_DUMMY:              { -                if(m_spellInfo->Id == 1515) +                //custom check +                switch(m_spellInfo->Id)                  { -                    if (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER) -                        return SPELL_FAILED_BAD_IMPLICIT_TARGETS; +                    case 61336: +                        if(m_caster->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_caster)->IsInFeralForm()) +                            return SPELL_FAILED_ONLY_SHAPESHIFT; +                        break; +                    case 1515: +                    { +                        if (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER) +                            return SPELL_FAILED_BAD_IMPLICIT_TARGETS; -                    if (m_targets.getUnitTarget()->getLevel() > m_caster->getLevel()) -                        return SPELL_FAILED_HIGHLEVEL; +                        if (m_targets.getUnitTarget()->getLevel() > m_caster->getLevel()) +                            return SPELL_FAILED_HIGHLEVEL; -                    // use SMSG_PET_TAME_FAILURE? -                    if (!((Creature*)m_targets.getUnitTarget())->GetCreatureInfo()->isTameable ()) -                        return SPELL_FAILED_BAD_TARGETS; +                        // use SMSG_PET_TAME_FAILURE? +                        if (!((Creature*)m_targets.getUnitTarget())->GetCreatureInfo()->isTameable ()) +                            return SPELL_FAILED_BAD_TARGETS; -                    if(m_caster->GetPetGUID()) -                        return SPELL_FAILED_ALREADY_HAVE_SUMMON; +                        if(m_caster->GetPetGUID()) +                            return SPELL_FAILED_ALREADY_HAVE_SUMMON; -                    if(m_caster->GetCharmGUID()) -                        return SPELL_FAILED_ALREADY_HAVE_CHARM; +                        if(m_caster->GetCharmGUID()) +                            return SPELL_FAILED_ALREADY_HAVE_CHARM; + +                        break; +                    } +                    default: +                        break;                  } -            }break; +                break; +            }              case SPELL_AURA_MOD_POSSESS:              case SPELL_AURA_MOD_CHARM:              { @@ -4199,17 +4557,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; @@ -4225,14 +4580,13 @@ uint8 Spell::CanCast(bool strict)                  break;              } -            case SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED: +            case SPELL_AURA_MOD_INCREASE_MOUNTED_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; @@ -4256,10 +4610,10 @@ uint8 Spell::CanCast(bool strict)      }      // all ok -    return 0; +    return SPELL_CAST_OK;  } -int16 Spell::PetCanCast(Unit* target) +SpellCastResult Spell::CheckPetCast(Unit* target)  {      if(!m_caster->isAlive())          return SPELL_FAILED_CASTER_DEAD; @@ -4307,20 +4661,16 @@ int16 Spell::PetCanCast(Unit* target)              return SPELL_FAILED_NOT_READY;      } -    uint16 result = CanCast(true); -    if(result != 0) -        return result; -    else -        return -1;                                          //this allows to check spell fail 0, in combat +    return CheckCast(true);  } -uint8 Spell::CheckCasterAuras() const +SpellCastResult Spell::CheckCasterAuras() const  {      // Flag drop spells totally immuned to caster auras      // FIXME: find more nice check for all totally immuned spells      // AttributesEx3 & 0x10000000?      if(m_spellInfo->Id==23336 || m_spellInfo->Id==23334 || m_spellInfo->Id==34991) -        return 0; +        return SPELL_CAST_OK;      uint8 school_immune = 0;      uint32 mechanic_immune = 0; @@ -4340,26 +4690,27 @@ uint8 Spell::CheckCasterAuras() const                  dispel_immune |= GetDispellMask(DispelType(m_spellInfo->EffectMiscValue[i]));          }          //immune movement impairment and loss of control -        if(m_spellInfo->Id==(uint32)42292) +        if(m_spellInfo->Id==42292 || m_spellInfo->Id==59752)              mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;      }      //Check whether the cast should be prevented by any state you might have. -    uint8 prevented_reason = 0; +    SpellCastResult prevented_reason = SPELL_CAST_OK;      // 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 -    if(prevented_reason) +    if(prevented_reason != SPELL_CAST_OK)      {          if(school_immune || mechanic_immune || dispel_immune)          { @@ -4369,7 +4720,7 @@ uint8 Spell::CheckCasterAuras() const              {                  if(itr->second)                  { -                    if( GetSpellMechanicMask(itr->second->GetSpellProto(), itr->second->GetEffIndex()) & mechanic_immune ) +                    if( GetAllSpellMechanicMask(itr->second->GetSpellProto()) & mechanic_immune )                          continue;                      if( GetSpellSchoolMask(itr->second->GetSpellProto()) & school_immune )                          continue; @@ -4378,28 +4729,34 @@ uint8 Spell::CheckCasterAuras() const                      //Make a second check for spell failed so the right SPELL_FAILED message is returned.                      //That is needed when your casting is prevented by multiple states and you are only immune to some of them. -                    switch(itr->second->GetModifier()->m_auraname) +                    for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i)                      { -                        case SPELL_AURA_MOD_STUN: -                            if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED)) -                                return SPELL_FAILED_STUNNED; -                            break; -                        case SPELL_AURA_MOD_CONFUSE: -                            if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED)) -                                return SPELL_FAILED_CONFUSED; -                            break; -                        case SPELL_AURA_MOD_FEAR: -                            if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED)) -                                return SPELL_FAILED_FLEEING; -                            break; -                        case SPELL_AURA_MOD_SILENCE: -                        case SPELL_AURA_MOD_PACIFY: -                        case SPELL_AURA_MOD_PACIFY_SILENCE: -                            if( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY) -                                return SPELL_FAILED_PACIFIED; -                            else if ( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE) -                                return SPELL_FAILED_SILENCED; -                            break; +                        if (AuraEffect * part = itr->second->GetPartAura(i)) +                        { +                            switch(part->GetAuraName()) +                            { +                                case SPELL_AURA_MOD_STUN: +                                    if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED)) +                                        return SPELL_FAILED_STUNNED; +                                    break; +                                case SPELL_AURA_MOD_CONFUSE: +                                    if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED)) +                                        return SPELL_FAILED_CONFUSED; +                                    break; +                                case SPELL_AURA_MOD_FEAR: +                                    if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED)) +                                        return SPELL_FAILED_FLEEING; +                                    break; +                                case SPELL_AURA_MOD_SILENCE: +                                case SPELL_AURA_MOD_PACIFY: +                                case SPELL_AURA_MOD_PACIFY_SILENCE: +                                    if( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY) +                                        return SPELL_FAILED_PACIFIED; +                                    else if ( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE) +                                        return SPELL_FAILED_SILENCED; +                                    break; +                            } +                        }                      }                  }              } @@ -4408,7 +4765,7 @@ uint8 Spell::CheckCasterAuras() const          else              return prevented_reason;      } -    return 0;                                               // all ok +    return SPELL_CAST_OK;  }  bool Spell::CanAutoCast(Unit* target) @@ -4421,25 +4778,26 @@ bool Spell::CanAutoCast(Unit* target)          {              if( m_spellInfo->StackAmount <= 1)              { -                if( target->HasAura(m_spellInfo->Id, j) ) +                if( target->HasAuraEffect(m_spellInfo->Id, j) )                      return false;              }              else              { -                if( target->GetAuras().count(Unit::spellEffectPair(m_spellInfo->Id, j)) >= m_spellInfo->StackAmount) -                    return false; +                if( AuraEffect * aureff = target->GetAuraEffect(m_spellInfo->Id, j)) +                    if (aureff->GetParentAura()->GetStackAmount() >= m_spellInfo->StackAmount) +                        return false;              }          }          else if ( IsAreaAuraEffect( m_spellInfo->Effect[j] ))          { -                if( target->HasAura(m_spellInfo->Id, j) ) +                if( target->HasAuraEffect(m_spellInfo->Id, j) )                      return false;          }      } -    int16 result = PetCanCast(target); +    SpellCastResult result = CheckPetCast(target); -    if(result == -1 || result == SPELL_FAILED_UNIT_NOT_INFRONT) +    if(result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT)      {          FillTargetMap();          //check if among target units, our WANTED target is as well (->only self cast spells return false) @@ -4450,12 +4808,13 @@ bool Spell::CanAutoCast(Unit* target)      return false;                                           //target invalid  } -uint8 Spell::CheckRange(bool strict) +SpellCastResult Spell::CheckRange(bool strict)  {      //float range_mod;      // self cast doesn't need range checking -- also for Starshards fix -    if (m_spellInfo->rangeIndex == 1) return 0; +    if (m_spellInfo->rangeIndex == 1) +        return SPELL_CAST_OK;      // i do not know why we need this      /*if (strict)                                             //add radius of caster @@ -4464,15 +4823,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) @@ -4499,14 +4858,13 @@ uint8 Spell::CheckRange(bool strict)      if(m_targets.m_targetMask == TARGET_FLAG_DEST_LOCATION && m_targets.m_destX != 0 && m_targets.m_destY != 0 && m_targets.m_destZ != 0)      { -        float dist = m_caster->GetDistance(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ); -        if(dist > max_range) +        if(!m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ,max_range))              return SPELL_FAILED_OUT_OF_RANGE; -        if(dist < min_range) +        if(m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ,min_range))              return SPELL_FAILED_TOO_CLOSE;      } -    return 0;                                               // ok +    return SPELL_CAST_OK;  }  int32 Spell::CalculatePowerCost() @@ -4546,9 +4904,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; @@ -4574,39 +4935,43 @@ int32 Spell::CalculatePowerCost()      return powerCost;  } -uint8 Spell::CheckPower() +SpellCastResult Spell::CheckPower()  {      // item cast not used power      if(m_CastItem) -        return 0; +        return SPELL_CAST_OK;      // health as power used - need check health amount      if(m_spellInfo->powerType == POWER_HEALTH)      {          if(m_caster->GetHealth() <= m_powerCost)              return SPELL_FAILED_CASTER_AURASTATE; -        return 0; +        return SPELL_CAST_OK;      }      // Check valid power type      if( m_spellInfo->powerType >= MAX_POWERS )      { -        sLog.outError("Spell::CheckMana: Unknown power type '%d'", m_spellInfo->powerType); +        sLog.outError("Spell::CheckPower: Unknown power type '%d'", m_spellInfo->powerType);          return SPELL_FAILED_UNKNOWN;      } + +    SpellCastResult failReason = CheckRuneCost(m_spellInfo->runeCostID); +    if(failReason != SPELL_CAST_OK) +        return failReason; +      // Check power amount      Powers powerType = Powers(m_spellInfo->powerType);      if(m_caster->GetPower(powerType) < m_powerCost)          return SPELL_FAILED_NO_POWER;      else -        return 0; +        return SPELL_CAST_OK;  } -uint8 Spell::CheckItems() +SpellCastResult Spell::CheckItems()  {      if (m_caster->GetTypeId() != TYPEID_PLAYER) -        return 0; +        return SPELL_CAST_OK; -    uint32 itemid, itemcount;      Player* p_caster = (Player*)m_caster;      if(!m_CastItem) @@ -4616,77 +4981,72 @@ uint8 Spell::CheckItems()      }      else      { -        itemid = m_CastItem->GetEntry(); +        uint32 itemid = m_CastItem->GetEntry();          if( !p_caster->HasItemCount(itemid,1) )              return SPELL_FAILED_ITEM_NOT_READY; -        else -        { -            ItemPrototype const *proto = m_CastItem->GetProto(); -            if(!proto) -                return SPELL_FAILED_ITEM_NOT_READY; -            for (int i = 0; i<5; i++) -            { -                if (proto->Spells[i].SpellCharges) -                { -                    if(m_CastItem->GetSpellCharges(i)==0) -                        return SPELL_FAILED_NO_CHARGES_REMAIN; -                } -            } +        ItemPrototype const *proto = m_CastItem->GetProto(); +        if(!proto) +            return SPELL_FAILED_ITEM_NOT_READY; + +        for (int i = 0; i<5; i++) +            if (proto->Spells[i].SpellCharges) +                if(m_CastItem->GetSpellCharges(i)==0) +                    return SPELL_FAILED_NO_CHARGES_REMAIN; -            uint32 ItemClass = proto->Class; -            if (ItemClass == ITEM_CLASS_CONSUMABLE && m_targets.getUnitTarget()) +        // consumable cast item checks +        if (proto->Class == ITEM_CLASS_CONSUMABLE && m_targets.getUnitTarget()) +        { +            // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example +            SpellCastResult failReason = SPELL_CAST_OK; +            for (int i = 0; i < 3; i++)              { -                // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example -                uint8 failReason = 0; -                for (int i = 0; i < 3; i++) -                {                      // skip check, pet not required like checks, and for TARGET_UNIT_PET m_targets.getUnitTarget() is not the real target but the caster                      if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_PET) -                        continue; +                    continue; -                    if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL) +                if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL) +                { +                    if (m_targets.getUnitTarget()->GetHealth() == m_targets.getUnitTarget()->GetMaxHealth())                      { -                        if (m_targets.getUnitTarget()->GetHealth() == m_targets.getUnitTarget()->GetMaxHealth()) -                        { -                            failReason = (uint8)SPELL_FAILED_ALREADY_AT_FULL_HEALTH; -                            continue; -                        } -                        else -                        { -                            failReason = 0; -                            break; -                        } +                        failReason = SPELL_FAILED_ALREADY_AT_FULL_HEALTH; +                        continue;                      } +                    else +                    { +                        failReason = SPELL_CAST_OK; +                        break; +                    } +                } -                    // Mana Potion, Rage Potion, Thistle Tea(Rogue), ... -                    if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE) +                // Mana Potion, Rage Potion, Thistle Tea(Rogue), ... +                if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE) +                { +                    if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)                      { -                        if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) -                        { -                            failReason = (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER; -                            continue; -                        } +                        failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER; +                        continue; +                    } -                        Powers power = Powers(m_spellInfo->EffectMiscValue[i]); -                        if (m_targets.getUnitTarget()->GetPower(power) == m_targets.getUnitTarget()->GetMaxPower(power)) -                        { -                            failReason = (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER; -                            continue; -                        } -                        else -                        { -                            failReason = 0; -                            break; -                        } +                    Powers power = Powers(m_spellInfo->EffectMiscValue[i]); +                    if (m_targets.getUnitTarget()->GetPower(power) == m_targets.getUnitTarget()->GetMaxPower(power)) +                    { +                        failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER; +                        continue; +                    } +                    else +                    { +                        failReason = SPELL_CAST_OK; +                        break;                      }                  } -                if (failReason) -                    return failReason;              } +            if (failReason != SPELL_CAST_OK) +                return failReason;          }      } +    // check target item      if(m_targets.getItemTargetGUID())      {          if(m_caster->GetTypeId() != TYPEID_PLAYER) @@ -4705,6 +5065,7 @@ uint8 Spell::CheckItems()              return SPELL_FAILED_EQUIPPED_ITEM_CLASS;      } +    // check spell focus object      if(m_spellInfo->RequiresSpellFocus)      {          CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); @@ -4712,86 +5073,92 @@ 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);          cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));          if(!ok) -            return (uint8)SPELL_FAILED_REQUIRES_SPELL_FOCUS; +            return SPELL_FAILED_REQUIRES_SPELL_FOCUS;          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))) +    // do not take reagents for these item casts +    if (!(m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_TRIGGERED_CAST))      { -        for(uint32 i=0;i<8;i++) +        // check reagents (ignore triggered spells with reagents processed by original spell) and special reagent ignore case. +        if (!m_IsTriggeredSpell && !p_caster->CanNoReagentCast(m_spellInfo))          { -            if(m_spellInfo->Reagent[i] <= 0) -                continue; +            for(uint32 i=0;i<8;i++) +            { +                if(m_spellInfo->Reagent[i] <= 0) +                    continue; -            itemid    = m_spellInfo->Reagent[i]; -            itemcount = m_spellInfo->ReagentCount[i]; +                uint32 itemid    = m_spellInfo->Reagent[i]; +                uint32 itemcount = m_spellInfo->ReagentCount[i]; -            // if CastItem is also spell reagent -            if( m_CastItem && m_CastItem->GetEntry() == itemid ) -            { -                ItemPrototype const *proto = m_CastItem->GetProto(); -                if(!proto) -                    return SPELL_FAILED_ITEM_NOT_READY; -                for(int s=0;s<5;s++) +                // if CastItem is also spell reagent +                if( m_CastItem && m_CastItem->GetEntry() == itemid )                  { -                    // CastItem will be used up and does not count as reagent -                    int32 charges = m_CastItem->GetSpellCharges(s); -                    if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2) +                    ItemPrototype const *proto = m_CastItem->GetProto(); +                    if(!proto) +                        return SPELL_FAILED_ITEM_NOT_READY; +                    for(int s=0; s < MAX_ITEM_PROTO_SPELLS; ++s)                      { -                        ++itemcount; -                        break; +                        // CastItem will be used up and does not count as reagent +                        int32 charges = m_CastItem->GetSpellCharges(s); +                        if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2) +                        { +                            ++itemcount; +                            break; +                        }                      }                  } +                if( !p_caster->HasItemCount(itemid,itemcount) ) +                    return SPELL_FAILED_ITEM_NOT_READY;         //0x54              } -            if( !p_caster->HasItemCount(itemid,itemcount) ) -                return (uint8)SPELL_FAILED_ITEM_NOT_READY;      //0x54          } -    } -    uint32 totems = 2; -    for(int i=0;i<2;++i) -    { -        if(m_spellInfo->Totem[i] != 0) +        // check totem-item requirements (items presence in inventory) +        uint32 totems = 2; +        for(int i=0;i<2;++i)          { -            if( p_caster->HasItemCount(m_spellInfo->Totem[i],1) ) +            if(m_spellInfo->Totem[i] != 0)              { -                totems -= 1; -                continue; -            } -        }else -        totems -= 1; -    } -    if(totems != 0) -        return (uint8)SPELL_FAILED_TOTEMS;                  //0x7C +                if( p_caster->HasItemCount(m_spellInfo->Totem[i],1) ) +                { +                    totems -= 1; +                    continue; +                } +            }else +            totems -= 1; +        } +        if(totems != 0) +            return SPELL_FAILED_TOTEMS;                         //0x7C -    //Check items for TotemCategory -    uint32 TotemCategory = 2; -    for(int i=0;i<2;++i) -    { -        if(m_spellInfo->TotemCategory[i] != 0) +        // Check items for TotemCategory  (items presence in inventory) +        uint32 TotemCategory = 2; +        for(int i=0;i<2;++i)          { -            if( p_caster->HasItemTotemCategory(m_spellInfo->TotemCategory[i]) ) +            if(m_spellInfo->TotemCategory[i] != 0)              { -                TotemCategory -= 1; -                continue; +                if( p_caster->HasItemTotemCategory(m_spellInfo->TotemCategory[i]) ) +                { +                    TotemCategory -= 1; +                    continue; +                }              } +            else +                TotemCategory -= 1;          } -        else -            TotemCategory -= 1; +        if(TotemCategory != 0) +            return SPELL_FAILED_TOTEM_CATEGORY;                 //0x7B      } -    if(TotemCategory != 0) -        return (uint8)SPELL_FAILED_TOTEM_CATEGORY;          //0x7B +    // special checks for spell effects      for(int i = 0; i < 3; i++)      {          switch (m_spellInfo->Effect[i]) @@ -4811,6 +5178,24 @@ uint8 Spell::CheckItems()                  break;              }              case SPELL_EFFECT_ENCHANT_ITEM: +                if(m_spellInfo->EffectItemType[i] && m_targets.getItemTarget()  +                    && (m_targets.getItemTarget()->IsWeaponVellum() || m_targets.getItemTarget()->IsArmorVellum())) +                { +                    // cannot enchant vellum for other player +                    if (m_targets.getItemTarget()->GetOwner()!=m_caster) +                        return SPELL_FAILED_NOT_TRADEABLE; +                    // do not allow to enchant vellum from scroll made by vellum-prevent exploit +                    if (m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_TRIGGERED_CAST) +                        return SPELL_FAILED_TOTEM_CATEGORY; +                    ItemPosCountVec dest; +                    uint8 msg = p_caster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->EffectItemType[i], 1 ); +                    if (msg != EQUIP_ERR_OK ) +                    { +                        p_caster->SendEquipError( msg, NULL, NULL ); +                        return SPELL_FAILED_DONT_REPORT; +                    } +                } +            case SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC:              {                  Item* targetItem = m_targets.getItemTarget();                  if(!targetItem) @@ -4894,13 +5279,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:              { @@ -4969,7 +5377,39 @@ uint8 Spell::CheckItems()          }      } -    return uint8(0); +    // check weapon presence in slots for main/offhand weapons +    if(m_spellInfo->EquippedItemClass >=0) +    { +        // main hand weapon required +        if(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND) +        { +            Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK); + +            // skip spell if no weapon in slot or broken +            if(!item || item->IsBroken() ) +                return m_IsTriggeredSpell? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_EQUIPPED_ITEM_CLASS; + +            // skip spell if weapon not fit to triggered spell +            if(!item->IsFitToSpellRequirements(m_spellInfo)) +                return m_IsTriggeredSpell? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_EQUIPPED_ITEM_CLASS; +        } + +        // offhand hand weapon required +        if(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND) +        { +            Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK); + +            // skip spell if no weapon in slot or broken +            if(!item || item->IsBroken() ) +                return m_IsTriggeredSpell? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_EQUIPPED_ITEM_CLASS; + +            // skip spell if weapon not fit to triggered spell +            if(!item->IsFitToSpellRequirements(m_spellInfo)) +                return m_IsTriggeredSpell? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_EQUIPPED_ITEM_CLASS; +        } +    } + +    return SPELL_CAST_OK;  }  void Spell::Delayed() // only called in DealDamage() @@ -4980,18 +5420,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)      { @@ -5015,14 +5459,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)      { @@ -5041,11 +5489,8 @@ void Spell::DelayedChannel()              Unit* unit = m_caster->GetGUID()==ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);              if (unit)              { -                for (int j=0;j<3;j++) -                    if( ihit->effectMask & (1<<j) ) -                        unit->DelayAura(m_spellInfo->Id, j, delaytime); +                unit->DelayAura(m_spellInfo->Id, m_caster->GetGUID(), delaytime);              } -          }      } @@ -5076,17 +5521,12 @@ void Spell::UpdatePointers()      m_targets.Update(m_caster);  } -bool Spell::IsAffectedBy(SpellEntry const *spellInfo, uint32 effectId) -{ -    return spellmgr.IsAffectedBySpell(m_spellInfo,spellInfo->Id,effectId,spellInfo->EffectItemType[effectId]); -} -  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) @@ -5129,6 +5569,12 @@ bool Spell::CheckTarget(Unit* target, uint32 eff)              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()) @@ -5189,7 +5635,13 @@ bool Spell::CheckTarget(Unit* target, uint32 eff)              // 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 (IS_GAMEOBJECT_GUID(m_originalCasterGUID)) +                caster = m_caster->GetMap()->GetGameObject(m_originalCasterGUID); +            if (!caster) +                caster = m_caster; +            if(target!=m_caster && !target->IsWithinLOSInMap(caster))                  return false;              break;      } @@ -5197,44 +5649,9 @@ bool Spell::CheckTarget(Unit* target, uint32 eff)      return true;  } -Unit* Spell::SelectMagnetTarget() -{ -    Unit* target = m_targets.getUnitTarget(); - -    if(target && m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && target->HasAuraType(SPELL_AURA_SPELL_MAGNET)) //Attributes & 0x10 what is this? -    { -        Unit::AuraList const& magnetAuras = target->GetAurasByType(SPELL_AURA_SPELL_MAGNET); -        for(Unit::AuraList::const_iterator itr = magnetAuras.begin(); itr != magnetAuras.end(); ++itr) -        { -            if(Unit* magnet = (*itr)->GetCaster()) -            { -                if((*itr)->m_procCharges>0) -                { -                    (*itr)->SetAuraProcCharges((*itr)->m_procCharges-1); -                    target = magnet; -                    m_targets.setUnitTarget(target); -                    AddUnitTarget(target, 0); -                    uint64 targetGUID = target->GetGUID(); -                    for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) -                    { -                        if (targetGUID == ihit->targetGUID)                 // Found in list -                        { -                            (*ihit).damage = target->GetHealth(); -                            break; -                        } -                    } -                    break; -                } -            } -        } -    } - -    return target; -} -  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;  } @@ -5313,9 +5730,6 @@ bool SpellEvent::Execute(uint64 e_time, uint32 p_time)                          // another non-melee non-delayed spell is casted now, abort                          m_Spell->cancel();                      } -                    // Check if target of channeled spell still in range -                    else if (m_Spell->CheckRange(false)) -                        m_Spell->cancel();                      else                      {                          // do the action (pass spell to channeling state) @@ -5418,6 +5832,14 @@ void Spell::CalculateDamageDoneForAllTargets()          }      } +    bool usesAmmo=true; +    Unit::AuraEffectList const& Auras = m_caster->GetAurasByType(SPELL_AURA_ABILITY_CONSUME_NO_AMMO); +    for(Unit::AuraEffectList::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; @@ -5430,6 +5852,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) @@ -5488,6 +5932,68 @@ int32 Spell::CalculateDamageDone(Unit *unit, const uint32 effectMask, float *mul      return damageDone;  } +SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue) +{ +    if(!lockId)                                             // possible case for GO and maybe for items. +        return SPELL_CAST_OK; + +    // Get LockInfo +    LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); + +    if (!lockInfo) +        return SPELL_FAILED_BAD_TARGETS; + +    bool reqKey = false;                                    // some locks not have reqs + +    for(int j = 0; j < 8; ++j) +    { +        switch(lockInfo->Type[j]) +        { +            // check key item (many fit cases can be) +            case LOCK_KEY_ITEM: +                if(lockInfo->Index[j] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[j]) +                    return SPELL_CAST_OK; +                reqKey = true; +                break; +                // check key skill (only single first fit case can be) +            case LOCK_KEY_SKILL: +            { +                reqKey = true; + +                // wrong locktype, skip +                if(uint32(m_spellInfo->EffectMiscValue[effIndex]) != lockInfo->Index[j]) +                    continue; + +                skillId = SkillByLockType(LockType(lockInfo->Index[j])); + +                if ( skillId != SKILL_NONE ) +                { +                    // skill bonus provided by casting spell (mostly item spells) +                    // add the damage modifier from the spell casted (cheat lock / skeleton key etc.) (use m_currentBasePoints, CalculateDamage returns wrong value) +                    uint32 spellSkillBonus = uint32(m_currentBasePoints[effIndex]+1); +                    reqSkillValue = lockInfo->Skill[j]; + +                    // castitem check: rogue using skeleton keys. the skill values should not be added in this case. +                    skillValue = m_CastItem || m_caster->GetTypeId()!= TYPEID_PLAYER ? +                        0 : ((Player*)m_caster)->GetSkillValue(skillId); + +                    skillValue += spellSkillBonus; + +                    if (skillValue < reqSkillValue) +                        return SPELL_FAILED_LOW_CASTLEVEL; +                } + +                return SPELL_CAST_OK; +            } +        } +    } + +    if(reqKey) +        return SPELL_FAILED_BAD_TARGETS; + +    return SPELL_CAST_OK; +} +  void Spell::SetSpellValue(SpellValueMod mod, int32 value)  {      switch(mod) @@ -5504,6 +6010,9 @@ void Spell::SetSpellValue(SpellValueMod mod, int32 value)              m_spellValue->EffectBasePoints[2] = value - int32(m_spellInfo->EffectBaseDice[2]);              m_currentBasePoints[2] = m_spellValue->EffectBasePoints[2];              break; +        case SPELLVALUE_RADIUS_MOD: +            m_spellValue->RadiusMod = (float)value / 10000; +            break;          case SPELLVALUE_MAX_TARGETS:              m_spellValue->MaxAffectedTargets = (uint32)value;              break;  | 
