diff options
Diffstat (limited to 'src/server/game/Spells/Spell.cpp')
| -rwxr-xr-x | src/server/game/Spells/Spell.cpp | 480 | 
1 files changed, 202 insertions, 278 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 36d7328f37e..6376ff6e50b 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -53,6 +53,8 @@  #include "SpellScript.h"  #include "InstanceScript.h"  #include "SpellInfo.h" +#include "Battlefield.h" +#include "BattlefieldMgr.h"  extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; @@ -458,23 +460,23 @@ void SpellCastTargets::Update(Unit* caster)  void SpellCastTargets::OutDebug() const  {      if (!m_targetMask) -        sLog->outString("No targets"); +        sLog->outInfo(LOG_FILTER_SPELLS_AURAS, "No targets"); -    sLog->outString("target mask: %u", m_targetMask); +    sLog->outInfo(LOG_FILTER_SPELLS_AURAS, "target mask: %u", m_targetMask);      if (m_targetMask & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK)) -        sLog->outString("Object target: " UI64FMTD, m_objectTargetGUID); +        sLog->outInfo(LOG_FILTER_SPELLS_AURAS, "Object target: " UI64FMTD, m_objectTargetGUID);      if (m_targetMask & TARGET_FLAG_ITEM) -        sLog->outString("Item target: " UI64FMTD, m_itemTargetGUID); +        sLog->outInfo(LOG_FILTER_SPELLS_AURAS, "Item target: " UI64FMTD, m_itemTargetGUID);      if (m_targetMask & TARGET_FLAG_TRADE_ITEM) -        sLog->outString("Trade item target: " UI64FMTD, m_itemTargetGUID); +        sLog->outInfo(LOG_FILTER_SPELLS_AURAS, "Trade item target: " UI64FMTD, m_itemTargetGUID);      if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION) -        sLog->outString("Source location: transport guid:" UI64FMTD " trans offset: %s position: %s", m_src._transportGUID, m_src._transportOffset.ToString().c_str(), m_src._position.ToString().c_str()); +        sLog->outInfo(LOG_FILTER_SPELLS_AURAS, "Source location: transport guid:" UI64FMTD " trans offset: %s position: %s", m_src._transportGUID, m_src._transportOffset.ToString().c_str(), m_src._position.ToString().c_str());      if (m_targetMask & TARGET_FLAG_DEST_LOCATION) -        sLog->outString("Destination location: transport guid:" UI64FMTD " trans offset: %s position: %s", m_dst._transportGUID, m_dst._transportOffset.ToString().c_str(), m_dst._position.ToString().c_str()); +        sLog->outInfo(LOG_FILTER_SPELLS_AURAS, "Destination location: transport guid:" UI64FMTD " trans offset: %s position: %s", m_dst._transportGUID, m_dst._transportOffset.ToString().c_str(), m_dst._position.ToString().c_str());      if (m_targetMask & TARGET_FLAG_STRING) -        sLog->outString("String: %s", m_strTarget.c_str()); -    sLog->outString("speed: %f", m_speed); -    sLog->outString("elevation: %f", m_elevation); +        sLog->outInfo(LOG_FILTER_SPELLS_AURAS, "String: %s", m_strTarget.c_str()); +    sLog->outInfo(LOG_FILTER_SPELLS_AURAS, "speed: %f", m_speed); +    sLog->outInfo(LOG_FILTER_SPELLS_AURAS, "elevation: %f", m_elevation);  }  SpellValue::SpellValue(SpellInfo const* proto) @@ -585,9 +587,7 @@ m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharme      CleanupEffectExecuteData();      for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) -    {          m_destTargets[i] = SpellDestination(*m_caster); -    }  }  Spell::~Spell() @@ -605,7 +605,7 @@ Spell::~Spell()      {          // Clean the reference to avoid later crash.          // If this error is repeating, we may have to add an ASSERT to better track down how we get into this case. -        sLog->outError("SPELL: deleting spell for spell ID %u. However, spell still referenced.", m_spellInfo->Id); +        sLog->outError(LOG_FILTER_SPELLS_AURAS, "SPELL: deleting spell for spell ID %u. However, spell still referenced.", m_spellInfo->Id);          *m_selfContainer = NULL;      } @@ -829,7 +829,7 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar              break;      } -    switch(targetType.GetSelectionCategory()) +    switch (targetType.GetSelectionCategory())      {          case TARGET_SELECT_CATEGORY_CHANNEL:              SelectImplicitChannelTargets(effIndex, targetType); @@ -847,7 +847,7 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar              switch (targetType.GetObjectType())              {                  case TARGET_OBJECT_TYPE_SRC: -                    switch(targetType.GetReferenceType()) +                    switch (targetType.GetReferenceType())                      {                          case TARGET_REFERENCE_TYPE_CASTER:                              m_targets.SetSrc(*m_caster); @@ -858,7 +858,7 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar                      }                      break;                  case TARGET_OBJECT_TYPE_DEST: -                     switch(targetType.GetReferenceType()) +                     switch (targetType.GetReferenceType())                       {                           case TARGET_REFERENCE_TYPE_CASTER:                               SelectImplicitCasterDestTargets(effIndex, targetType); @@ -875,7 +875,7 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar                       }                       break;                  default: -                    switch(targetType.GetReferenceType()) +                    switch (targetType.GetReferenceType())                      {                          case TARGET_REFERENCE_TYPE_CASTER:                              SelectImplicitCasterObjectTargets(effIndex, targetType); @@ -916,17 +916,25 @@ void Spell::SelectImplicitChannelTargets(SpellEffIndex effIndex, SpellImplicitTa      switch (targetType.GetTarget())      {          case TARGET_UNIT_CHANNEL_TARGET: +        { +            WorldObject* target = ObjectAccessor::GetUnit(*m_caster, channeledSpell->m_targets.GetUnitTargetGUID()); +            CallScriptObjectTargetSelectHandlers(target, effIndex);              // unit target may be no longer avalible - teleported out of map for example -            if (Unit* target = Unit::GetUnit(*m_caster, channeledSpell->m_targets.GetUnitTargetGUID())) -                AddUnitTarget(target, 1 << effIndex); +            if (target && target->ToUnit()) +                AddUnitTarget(target->ToUnit(), 1 << effIndex);              else                  sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: cannot find channel spell target for spell ID %u, effect %u", m_spellInfo->Id, effIndex);              break; +        }          case TARGET_DEST_CHANNEL_TARGET:              if (channeledSpell->m_targets.HasDst())                  m_targets.SetDst(channeledSpell->m_targets);              else if (WorldObject* target = ObjectAccessor::GetWorldObject(*m_caster, channeledSpell->m_targets.GetObjectTargetGUID())) -                m_targets.SetDst(*target); +            { +                CallScriptObjectTargetSelectHandlers(target, effIndex); +                if (target) +                    m_targets.SetDst(*target); +            }              else                  sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: cannot find channel spell destination for spell ID %u, effect %u", m_spellInfo->Id, effIndex);              break; @@ -1004,6 +1012,8 @@ void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTar          return;      } +    CallScriptObjectTargetSelectHandlers(target, effIndex); +      switch (targetType.GetObjectType())      {          case TARGET_OBJECT_TYPE_UNIT: @@ -1043,7 +1053,9 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge      {          Trinity::WorldObjectSpellConeTargetCheck check(coneAngle, radius, m_caster, m_spellInfo, selectionType, condList);          Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> searcher(m_caster, targets, check, containerTypeMask); -        SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> > (searcher, containerTypeMask, m_caster, m_caster, radius); +        SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> >(searcher, containerTypeMask, m_caster, m_caster, radius); + +        CallScriptObjectAreaTargetSelectHandlers(targets, effIndex);          if (!targets.empty())          { @@ -1071,8 +1083,6 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge                      gObjTargets.push_back(gObjTarget);              } -            CallScriptAfterUnitTargetSelectHandlers(unitTargets, effIndex); -              for (std::list<Unit*>::iterator itr = unitTargets.begin(); itr != unitTargets.end(); ++itr)                  AddUnitTarget(*itr, effMask, false); @@ -1207,6 +1217,9 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge          default:              break;      } + +    CallScriptObjectAreaTargetSelectHandlers(targets, effIndex); +      std::list<Unit*> unitTargets;      std::list<GameObject*> gObjTargets;      // for compability with older code - add only unit and go targets @@ -1288,18 +1301,6 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge                      maxSize = m_caster->HasAura(62970) ? 6 : 5; // Glyph of Wild Growth                      power = POWER_HEALTH;                  } -                else if (m_spellInfo->SpellFamilyFlags[2] == 0x0100) // Starfall -                { -                    // Remove targets not in LoS or in stealth -                    for (std::list<Unit*>::iterator itr = unitTargets.begin(); itr != unitTargets.end();) -                    { -                        if ((*itr)->HasStealthAura() || (*itr)->HasInvisibilityAura() || !(*itr)->IsWithinLOSInMap(m_caster)) -                            itr = unitTargets.erase(itr); -                        else -                            ++itr; -                    } -                    break; -                }                  else                      break; @@ -1340,6 +1341,11 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge              }          } +        // todo: move to scripts, but we must call it before resize list by MaxAffectedTargets +        // Intimidating Shout +        if (m_spellInfo->Id == 5246 && effIndex != EFFECT_0) +            unitTargets.remove(m_targets.GetUnitTarget()); +          // Other special target selection goes here          if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)          { @@ -1348,13 +1354,9 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge                  if ((*j)->IsAffectedOnSpell(m_spellInfo))                      maxTargets += (*j)->GetAmount(); -            if (m_spellInfo->Id == 5246) //Intimidating Shout -                unitTargets.remove(m_targets.GetUnitTarget());              Trinity::Containers::RandomResizeList(unitTargets, maxTargets);          } -        CallScriptAfterUnitTargetSelectHandlers(unitTargets, effIndex); -          for (std::list<Unit*>::iterator itr = unitTargets.begin(); itr != unitTargets.end(); ++itr)              AddUnitTarget(*itr, effMask, false);      } @@ -1370,6 +1372,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge              Trinity::Containers::RandomResizeList(gObjTargets, maxTargets);          } +          for (std::list<GameObject*>::iterator itr = gObjTargets.begin(); itr != gObjTargets.end(); ++itr)              AddGOTarget(*itr, effMask);      } @@ -1377,7 +1380,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge  void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)  { -    switch(targetType.GetTarget()) +    switch (targetType.GetTarget())      {          case TARGET_DEST_CASTER:              m_targets.SetDst(*m_caster); @@ -1442,7 +1445,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici  void Spell::SelectImplicitTargetDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)  {      WorldObject* target = m_targets.GetObjectTarget(); -    switch(targetType.GetTarget()) +    switch (targetType.GetTarget())      {          case TARGET_DEST_TARGET_ENEMY:          case TARGET_DEST_TARGET_ANY: @@ -1475,7 +1478,7 @@ void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitT      if (!m_targets.HasDst())          m_targets.SetDst(*m_caster); -    switch(targetType.GetTarget()) +    switch (targetType.GetTarget())      {          case TARGET_DEST_DYNOBJ_ENEMY:          case TARGET_DEST_DYNOBJ_ALLY: @@ -1501,27 +1504,27 @@ void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitT  void Spell::SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)  { -    switch(targetType.GetTarget()) +    WorldObject* target = NULL; +    bool checkIfValid = true; + +    switch (targetType.GetTarget())      {          case TARGET_UNIT_CASTER: -            AddUnitTarget(m_caster, 1 << effIndex, false); +            target = m_caster; +            checkIfValid = false;              break;          case TARGET_UNIT_MASTER: -            if (Unit* owner = m_caster->GetCharmerOrOwner()) -                AddUnitTarget(owner, 1 << effIndex); +            target = m_caster->GetCharmerOrOwner();              break;          case TARGET_UNIT_PET: -            if (Guardian* pet = m_caster->GetGuardianPet()) -                AddUnitTarget(pet, 1 << effIndex); +            target = m_caster->GetGuardianPet();              break;          case TARGET_UNIT_SUMMONER:              if (m_caster->isSummon()) -                if (Unit* unit = m_caster->ToTempSummon()->GetSummoner()) -                    AddUnitTarget(unit, 1 << effIndex); +                target = m_caster->ToTempSummon()->GetSummoner();              break;          case TARGET_UNIT_VEHICLE: -            if (Unit *vehicle = m_caster->GetVehicleBase()) -                AddUnitTarget(vehicle, 1 << effIndex); +            target = m_caster->GetVehicleBase();              break;          case TARGET_UNIT_PASSENGER_0:          case TARGET_UNIT_PASSENGER_1: @@ -1532,26 +1535,38 @@ void Spell::SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImpli          case TARGET_UNIT_PASSENGER_6:          case TARGET_UNIT_PASSENGER_7:              if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsVehicle()) -                if (Unit *unit = m_caster->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0)) -                    AddUnitTarget(unit, 1 << effIndex); +                target = m_caster->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0);              break;          default:              break;      } + +    CallScriptObjectTargetSelectHandlers(target, effIndex); + +    if (target && target->ToUnit()) +        AddUnitTarget(target->ToUnit(), 1 << effIndex, checkIfValid);  }  void Spell::SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)  {      ASSERT((m_targets.GetObjectTarget() || m_targets.GetItemTarget()) && "Spell::SelectImplicitTargetObjectTargets - no explicit object or item target available!"); -    if (Unit* unit = m_targets.GetUnitTarget()) -        AddUnitTarget(unit, 1 << effIndex, true, false); -    else if (GameObject* gobj = m_targets.GetGOTarget()) -        AddGOTarget(gobj, 1 << effIndex); -    else -        AddItemTarget(m_targets.GetItemTarget(), 1 << effIndex); -    if (WorldObject* target = m_targets.GetObjectTarget()) +    WorldObject* target = m_targets.GetObjectTarget(); + +    CallScriptObjectTargetSelectHandlers(target, effIndex); + +    if (target) +    { +        if (Unit* unit = target->ToUnit()) +            AddUnitTarget(unit, 1 << effIndex, true, false); +        else if (GameObject* gobj = target->ToGameObject()) +            AddGOTarget(gobj, 1 << effIndex); +          SelectImplicitChainTargets(effIndex, targetType, target, 1 << effIndex); +    } +    // Script hook can remove object target and we would wrongly land here +    else if (Item* item = m_targets.GetItemTarget()) +        AddItemTarget(item, 1 << effIndex);  }  void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask) @@ -1572,14 +1587,15 @@ void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTarg          SearchChainTargets(targets, maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType()              , m_spellInfo->Effects[effIndex].ImplicitTargetConditions, targetType.GetTarget() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY); +        // Chain primary target is added earlier +        CallScriptObjectAreaTargetSelectHandlers(targets, effIndex); +          // for backward compability          std::list<Unit*> unitTargets;          for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)              if (Unit* unitTarget = (*itr)->ToUnit())                  unitTargets.push_back(unitTarget); -        CallScriptAfterUnitTargetSelectHandlers(unitTargets, effIndex); -          for (std::list<Unit*>::iterator itr = unitTargets.begin(); itr != unitTargets.end(); ++itr)              AddUnitTarget(*itr, effMask, false);      } @@ -1623,7 +1639,7 @@ void Spell::SelectImplicitTrajTargets()      float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d);      if (a > -0.0001f)          a = 0; -    DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: a %f b %f", a, b);) +    DEBUG_TRAJ(sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::SelectTrajTargets: a %f b %f", a, b);)      float bestDist = m_spellInfo->GetMaxRange(false); @@ -1639,11 +1655,11 @@ void Spell::SelectImplicitTrajTargets()          const float objDist2d = m_targets.GetSrcPos()->GetExactDist2d(*itr) * cos(m_targets.GetSrcPos()->GetRelativeAngle(*itr));          const float dz = (*itr)->GetPositionZ() - m_targets.GetSrcPos()->m_positionZ; -        DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: check %u, dist between %f %f, height between %f %f.", (*itr)->GetEntry(), objDist2d - size, objDist2d + size, dz - size, dz + size);) +        DEBUG_TRAJ(sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::SelectTrajTargets: check %u, dist between %f %f, height between %f %f.", (*itr)->GetEntry(), objDist2d - size, objDist2d + size, dz - size, dz + size);)          float dist = objDist2d - size;          float height = dist * (a * dist + b); -        DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: dist %f, height %f.", dist, height);) +        DEBUG_TRAJ(sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::SelectTrajTargets: dist %f, height %f.", dist, height);)          if (dist < bestDist && height < dz + size && height > dz - size)          {              bestDist = dist > 0 ? dist : 0; @@ -1651,7 +1667,7 @@ void Spell::SelectImplicitTrajTargets()          }  #define CHECK_DIST {\ -            DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: dist %f, height %f.", dist, height);)\ +            DEBUG_TRAJ(sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::SelectTrajTargets: dist %f, height %f.", dist, height);)\              if (dist > bestDist)\                  continue;\              if (dist < objDist2d + size && dist > objDist2d - size)\ @@ -1713,7 +1729,7 @@ void Spell::SelectImplicitTrajTargets()              float distSq = (*itr)->GetExactDistSq(x, y, z);              float sizeSq = (*itr)->GetObjectSize();              sizeSq *= sizeSq; -            DEBUG_TRAJ(sLog->outError("Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);) +            DEBUG_TRAJ(sLog->outError(LOG_FILTER_SPELLS_AURAS, "Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);)              if (distSq > sizeSq)              {                  float factor = 1 - sqrt(sizeSq / distSq); @@ -1722,7 +1738,7 @@ void Spell::SelectImplicitTrajTargets()                  z += factor * ((*itr)->GetPositionZ() - z);                  distSq = (*itr)->GetExactDistSq(x, y, z); -                DEBUG_TRAJ(sLog->outError("Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);) +                DEBUG_TRAJ(sLog->outError(LOG_FILTER_SPELLS_AURAS, "Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);)              }          } @@ -1742,9 +1758,12 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex)          case SPELL_EFFECT_SUMMON_PLAYER:              if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->GetSelection())              { -                Player* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetSelection()); -                if (target) -                    AddUnitTarget(target, 1 << effIndex, false); +                WorldObject* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetSelection()); + +                CallScriptObjectTargetSelectHandlers(target, SpellEffIndex(effIndex)); + +                if (target && target->ToPlayer()) +                    AddUnitTarget(target->ToUnit(), 1 << effIndex, false);              }              return;          default: @@ -1760,6 +1779,8 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex)      if (!targetMask)          return; +    WorldObject* target = NULL; +      switch (m_spellInfo->Effects[effIndex].GetImplicitTargetType())      {          // add explicit object target or self to the target map @@ -1768,40 +1789,46 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex)              if (targetMask & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK))              {                  if (Unit* unitTarget = m_targets.GetUnitTarget()) -                    AddUnitTarget(unitTarget, 1 << effIndex, false); +                    target = unitTarget;                  else if (targetMask & TARGET_FLAG_CORPSE_MASK)                  {                      if (Corpse* corpseTarget = m_targets.GetCorpseTarget())                      {                          // TODO: this is a workaround - corpses should be added to spell target map too, but we can't do that so we add owner instead                          if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID())) -                            AddUnitTarget(owner, 1 << effIndex, false); +                            target = owner;                      }                  }                  else //if (targetMask & TARGET_FLAG_UNIT_MASK) -                { -                    AddUnitTarget(m_caster, 1 << effIndex, false); -                } +                    target = m_caster;              }              if (targetMask & TARGET_FLAG_ITEM_MASK)              {                  if (Item* itemTarget = m_targets.GetItemTarget())                      AddItemTarget(itemTarget, 1 << effIndex); +                return;              }              if (targetMask & TARGET_FLAG_GAMEOBJECT_MASK) -            { -                if (GameObject* gObjTarget = m_targets.GetGOTarget()) -                    AddGOTarget(gObjTarget, 1 << effIndex); -            } +                target = m_targets.GetGOTarget();              break;          // add self to the target map          case EFFECT_IMPLICIT_TARGET_CASTER:              if (targetMask & TARGET_FLAG_UNIT_MASK) -                AddUnitTarget(m_caster, 1 << effIndex, false); +                target = m_caster;              break;          default:              break;      } + +    CallScriptObjectTargetSelectHandlers(target, SpellEffIndex(effIndex)); + +    if (target) +    { +        if (target->ToUnit()) +            AddUnitTarget(target->ToUnit(), 1 << effIndex, false); +        else if (target->ToGameObject()) +            AddGOTarget(target->ToGameObject(), 1 << effIndex); +    }  }  uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* condList) @@ -2442,13 +2469,13 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)          else              procEx |= PROC_EX_NORMAL_HIT; -        // 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, m_triggeredByAuraSpell); -          int32 gain = caster->HealBySpell(unitTarget, m_spellInfo, addhealth, crit);          unitTarget->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, m_spellInfo);          m_healing = gain; + +        // 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, m_triggeredByAuraSpell);      }      // Do damage and triggers      else if (m_damage > 0) @@ -2475,15 +2502,10 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)                  caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx);          } -        caster->DealSpellDamage(&damageInfo, true); -        // Haunt -        if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags[1] & 0x40000 && m_spellAura && m_spellAura->GetEffect(1)) -        { -            AuraEffect* aurEff = m_spellAura->GetEffect(1); -            aurEff->SetAmount(CalculatePctU(aurEff->GetAmount(), damageInfo.damage)); -        }          m_damage = damageInfo.damage; + +        caster->DealSpellDamage(&damageInfo, true);      }      // Passive spell hits/misses or active spells only misses (only triggers)      else @@ -2504,7 +2526,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)          }      } -    if (missInfo != SPELL_MISS_EVADE && m_caster && !m_caster->IsFriendlyTo(unit) && !m_spellInfo->IsPositive()) +    if (missInfo != SPELL_MISS_EVADE && m_caster && !m_caster->IsFriendlyTo(unit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))      {          m_caster->CombatStart(unit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO)); @@ -2548,12 +2570,34 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA          return SPELL_MISS_EVADE;      // For delayed spells immunity may be applied between missile launch and hit - check immunity for that case +    if (m_spellInfo->Speed && (unit->IsImmunedToDamage(m_spellInfo) || unit->IsImmunedToSpell(m_spellInfo))) +        return SPELL_MISS_IMMUNE; +      // disable effects to which unit is immune +    SpellMissInfo returnVal = SPELL_MISS_IMMUNE;      for (uint32 effectNumber = 0; effectNumber < MAX_SPELL_EFFECTS; ++effectNumber) -        if (effectMask & (1 << effectNumber) && unit->IsImmunedToSpellEffect(m_spellInfo, effectNumber)) -            effectMask &= ~(1 << effectNumber); -    if (!effectMask || (m_spellInfo->Speed && (unit->IsImmunedToDamage(m_spellInfo) || unit->IsImmunedToSpell(m_spellInfo)))) -        return SPELL_MISS_IMMUNE; +    { +        if (effectMask & (1 << effectNumber)) +        { +            if (unit->IsImmunedToSpellEffect(m_spellInfo, effectNumber)) +                effectMask &= ~(1 << effectNumber); +            else if (m_spellInfo->Effects[effectNumber].IsAura() && !m_spellInfo->IsPositiveEffect(effectNumber)) +            { +                int32 debuff_resist_chance = unit->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(m_spellInfo->Dispel)); +                debuff_resist_chance += unit->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(m_spellInfo->Dispel)); + +                if (debuff_resist_chance > 0) +                    if (irand(0,10000) <= (debuff_resist_chance * 100)) +                    { +                        effectMask &= ~(1 << effectNumber); +                        returnVal = SPELL_MISS_RESIST; +                    } +            } +        } +    } + +    if (!effectMask) +        return returnVal;      PrepareScriptHitHandlers();      CallScriptBeforeHitHandlers(); @@ -3107,13 +3151,13 @@ void Spell::cast(bool skipCheck)          // should be done before the spell is actually executed          sScriptMgr->OnPlayerSpellCast(playerCaster, this, skipCheck); -        // Let any pets know we've attacked something. As of 3.0.2 pets begin -        //  attacking their owner's target immediately -        if (Pet* playerPet = playerCaster->GetPet()) -        { -            if (playerPet->isAlive() && playerPet->isControlled() && (m_targets.GetTargetMask() & TARGET_FLAG_UNIT)) -                playerPet->AI()->OwnerAttacked(m_targets.GetObjectTarget()->ToUnit()); -        } +        // As of 3.0.2 pets begin attacking their owner's target immediately +        // Let any pets know we've attacked something. Check DmgClass for harmful spells only +        // This prevents spells such as Hunter's Mark from triggering pet attack +        if (this->GetSpellInfo()->DmgClass != SPELL_DAMAGE_CLASS_NONE) +            if (Pet* playerPet = playerCaster->GetPet()) +                if (playerPet->isAlive() && playerPet->isControlled() && (m_targets.GetTargetMask() & TARGET_FLAG_UNIT)) +                    playerPet->AI()->OwnerAttacked(m_targets.GetObjectTarget()->ToUnit());      }      SetExecutedCurrently(true); @@ -3432,29 +3476,13 @@ void Spell::_handle_immediate_phase()          return;      // Handle procs on cast      // TODO: finish new proc system:P -    if (m_UniqueTargetInfo.empty()) +    if (m_UniqueTargetInfo.empty() && m_targets.HasDst())      {          uint32 procAttacker = m_procAttacker;          if (!procAttacker) -        { -            bool positive = m_spellInfo->IsPositive(); -            switch (m_spellInfo->DmgClass) -            { -                case SPELL_DAMAGE_CLASS_MAGIC: -                    if (positive) -                        procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS; -                    else -                        procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG; -                break; -                case SPELL_DAMAGE_CLASS_NONE: -                    if (positive) -                        procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS; -                    else -                        procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG; -                break; -            } -        } -        // Proc damage for spells which have only dest targets (2484 should proc 51486 for example) +            procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS; + +        // Proc the spells that have DEST target          m_originalCaster->ProcDamageAndSpell(NULL, procAttacker, 0, m_procEx | PROC_EX_NORMAL_HIT, 0, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell);      }  } @@ -4279,7 +4307,7 @@ void Spell::TakeCastItem()      {          // This code is to avoid a crash          // I'm not sure, if this is really an error, but I guess every item needs a prototype -        sLog->outError("Cast item has no item prototype highId=%d, lowId=%d", m_CastItem->GetGUIDHigh(), m_CastItem->GetGUIDLow()); +        sLog->outError(LOG_FILTER_SPELLS_AURAS, "Cast item has no item prototype highId=%d, lowId=%d", m_CastItem->GetGUIDHigh(), m_CastItem->GetGUIDLow());          return;      } @@ -4369,7 +4397,7 @@ void Spell::TakePower()      if (powerType >= MAX_POWERS)      { -        sLog->outError("Spell::TakePower: Unknown power type '%d'", powerType); +        sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::TakePower: Unknown power type '%d'", powerType);          return;      } @@ -4852,22 +4880,13 @@ SpellCastResult Spell::CheckCast(bool strict)              if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER) && !target->HasInArc(static_cast<float>(M_PI), m_caster))                  return SPELL_FAILED_NOT_INFRONT; -            if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target)) -                return SPELL_FAILED_LINE_OF_SIGHT; -        } -        else -        { -            if (m_caster->GetTypeId() == TYPEID_PLAYER) // Target - is player caster -            { -                // Lay on Hands - cannot be self-cast on paladin with Forbearance or after using Avenging Wrath -                if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && m_spellInfo->SpellFamilyFlags[0] & 0x0008000) -                    if (target->HasAura(61988)) // Immunity shield marker -                        return SPELL_FAILED_TARGET_AURASTATE; -            } +            if (m_caster->GetEntry() != WORLD_TRIGGER) // Ignore LOS for gameobjects casts (wrongly casted by a trigger) +                if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target)) +                    return SPELL_FAILED_LINE_OF_SIGHT;          }      } -    //Check for line of sight for spells with dest +    // Check for line of sight for spells with dest      if (m_targets.HasDst())      {          float x, y, z; @@ -4966,7 +4985,8 @@ SpellCastResult Spell::CheckCast(bool strict)      bool hasDispellableAura = false;      bool hasNonDispelEffect = false; -    for (int i = 0; i < MAX_SPELL_EFFECTS; i++) +    uint32 dispelMask = 0; +    for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)          if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_DISPEL)          {              if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->AttributesEx & SPELL_ATTR1_MELEE_COMBAT_START) @@ -4974,17 +4994,8 @@ SpellCastResult Spell::CheckCast(bool strict)                  hasDispellableAura = true;                  break;              } -            if (Unit* target = m_targets.GetUnitTarget()) -            { -                DispelChargesList dispelList; -                uint32 dispelMask = SpellInfo::GetDispelMask(DispelType(m_spellInfo->Effects[i].MiscValue)); -                target->GetDispellableAuraList(m_caster, dispelMask, dispelList); -                if (!dispelList.empty()) -                { -                    hasDispellableAura = true; -                    break; -                } -            } + +            dispelMask |= SpellInfo::GetDispelMask(DispelType(m_spellInfo->Effects[i].MiscValue));          }          else if (m_spellInfo->Effects[i].IsEffect())          { @@ -4992,57 +5003,22 @@ SpellCastResult Spell::CheckCast(bool strict)              break;          } -    if (!hasNonDispelEffect && !hasDispellableAura && m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL) && !IsTriggered()) -        return SPELL_FAILED_NOTHING_TO_DISPEL; +    if (!hasNonDispelEffect && !hasDispellableAura && dispelMask && !IsTriggered()) +    { +        if (Unit* target = m_targets.GetUnitTarget()) +        { +            DispelChargesList dispelList; +            target->GetDispellableAuraList(m_caster, dispelMask, dispelList); +            if (dispelList.empty()) +                return SPELL_FAILED_NOTHING_TO_DISPEL; +        } +    } -    for (int i = 0; i < MAX_SPELL_EFFECTS; i++) +    for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)      {          // for effects of spells that have only one target          switch (m_spellInfo->Effects[i].Effect)          { -            case SPELL_EFFECT_DUMMY: -            { -                if (m_spellInfo->Id == 51582)          // Rocket Boots Engaged -                { -                    if (m_caster->IsInWater()) -                        return SPELL_FAILED_ONLY_ABOVEWATER; -                } -                else if (m_spellInfo->SpellIconID == 156)    // Holy Shock -                { -                    // spell different for friends and enemies -                    // hurt version required facing -                    if (m_targets.GetUnitTarget() && !m_caster->IsFriendlyTo(m_targets.GetUnitTarget()) && !m_caster->HasInArc(static_cast<float>(M_PI), m_targets.GetUnitTarget())) -                        return SPELL_FAILED_UNIT_NOT_INFRONT; -                } -                else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] == 0x2000) // Death Coil (DeathKnight) -                { -                    Unit* target = m_targets.GetUnitTarget(); -                    if (!target || (target->IsFriendlyTo(m_caster) && target->GetCreatureType() != CREATURE_TYPE_UNDEAD)) -                        return SPELL_FAILED_BAD_TARGETS; -                } -                else if (m_spellInfo->Id == 19938)          // Awaken Peon -                { -                    Unit* unit = m_targets.GetUnitTarget(); -                    if (!unit || !unit->HasAura(17743)) -                        return SPELL_FAILED_BAD_TARGETS; -                } -                else if (m_spellInfo->Id == 52264)          // Deliver Stolen Horse -                { -                    if (!m_caster->FindNearestCreature(28653, 5)) -                        return SPELL_FAILED_OUT_OF_RANGE; -                } -                else if (m_spellInfo->Id == 31789)          // Righteous Defense -                { -                    if (m_caster->GetTypeId() != TYPEID_PLAYER) -                        return SPELL_FAILED_DONT_REPORT; - -                    Unit* target = m_targets.GetUnitTarget(); -                    if (!target || !target->IsFriendlyTo(m_caster) || target->getAttackers().empty()) -                        return SPELL_FAILED_BAD_TARGETS; - -                } -                break; -            }              case SPELL_EFFECT_LEARN_SPELL:              {                  if (m_caster->GetTypeId() != TYPEID_PLAYER) @@ -5359,12 +5335,7 @@ SpellCastResult Spell::CheckCast(bool strict)              }              case SPELL_EFFECT_LEAP_BACK:              { -                // Spell 781 (Disengage) requires player to be in combat -                if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->Id == 781 && !m_caster->isInCombat()) -                    return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; - -                Unit* target = m_targets.GetUnitTarget(); -                if (m_caster == target && m_caster->HasUnitState(UNIT_STATE_ROOT)) +                if (m_caster->HasUnitState(UNIT_STATE_ROOT))                  {                      if (m_caster->GetTypeId() == TYPEID_PLAYER)                          return SPELL_FAILED_ROOTED; @@ -5385,66 +5356,10 @@ SpellCastResult Spell::CheckCast(bool strict)          }      } -    for (int i = 0; i < MAX_SPELL_EFFECTS; i++) +    for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)      {          switch (m_spellInfo->Effects[i].ApplyAuraName)          { -            case SPELL_AURA_DUMMY: -            { -                //custom check -                switch (m_spellInfo->Id) -                { -                    // Tag Murloc -                    case 30877: -                    { -                        Unit* target = m_targets.GetUnitTarget(); -                        if (!target || target->GetEntry() != 17326) -                            return SPELL_FAILED_BAD_TARGETS; -                        break; -                    } -                    case 61336: -                        if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_caster->ToPlayer()->IsInFeralForm()) -                            return SPELL_FAILED_ONLY_SHAPESHIFT; -                        break; -                    case 1515: -                    { -                        if (m_caster->GetTypeId() != TYPEID_PLAYER) -                            return SPELL_FAILED_BAD_TARGETS; - -                        if (!m_targets.GetUnitTarget() || m_targets.GetUnitTarget()->GetTypeId() == TYPEID_PLAYER) -                            return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - -                        Creature* target = m_targets.GetUnitTarget()->ToCreature(); - -                        if (target->getLevel() > m_caster->getLevel()) -                            return SPELL_FAILED_HIGHLEVEL; - -                        // use SMSG_PET_TAME_FAILURE? -                        if (!target->GetCreatureTemplate()->isTameable (m_caster->ToPlayer()->CanTameExoticPets())) -                            return SPELL_FAILED_BAD_TARGETS; - -                        if (m_caster->GetPetGUID()) -                            return SPELL_FAILED_ALREADY_HAVE_SUMMON; - -                        if (m_caster->GetCharmGUID()) -                            return SPELL_FAILED_ALREADY_HAVE_CHARM; - -                        break; -                    } -                    case 44795: // Parachute -                    { -                        float x, y, z; -                        m_caster->GetPosition(x, y, z); -                        float ground_Z = m_caster->GetMap()->GetHeight(m_caster->GetPhaseMask(), x, y, z); -                        if (fabs(ground_Z - z) < 0.1f) -                            return SPELL_FAILED_DONT_REPORT; -                        break; -                    } -                    default: -                        break; -                } -                break; -            }              case SPELL_AURA_MOD_POSSESS_PET:              {                  if (m_caster->GetTypeId() != TYPEID_PLAYER) @@ -5529,8 +5444,9 @@ SpellCastResult Spell::CheckCast(bool strict)                  // allow always ghost flight spells                  if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->isAlive())                  { -                    if (AreaTableEntry const* pArea = GetAreaEntryByAreaID(m_originalCaster->GetAreaId())) -                        if (pArea->flags & AREA_FLAG_NO_FLY_ZONE) +                    Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetZoneId()); +                    if (AreaTableEntry const* area = GetAreaEntryByAreaID(m_originalCaster->GetAreaId())) +                        if (area->flags & AREA_FLAG_NO_FLY_ZONE  || (Bf && !Bf->CanFlyIn()))                              return (_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_NOT_HERE;                  }                  break; @@ -5631,7 +5547,7 @@ SpellCastResult Spell::CheckCasterAuras() const      // We use bitmasks so the loop is done only once and not on every aura check below.      if (m_spellInfo->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)      { -        for (int i = 0; i < MAX_SPELL_EFFECTS; ++i) +        for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)          {              if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_SCHOOL_IMMUNITY)                  school_immune |= uint32(m_spellInfo->Effects[i].MiscValue); @@ -5699,7 +5615,7 @@ SpellCastResult Spell::CheckCasterAuras() const                  SpellInfo const* auraInfo = aura->GetSpellInfo();                  if (auraInfo->GetAllEffectsMechanicMask() & mechanic_immune)                      continue; -                if (auraInfo->GetSchoolMask() & school_immune) +                if (auraInfo->GetSchoolMask() & school_immune && !(auraInfo->AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE))                      continue;                  if (auraInfo->GetDispelMask() & dispel_immune)                      continue; @@ -5861,7 +5777,7 @@ SpellCastResult Spell::CheckPower()      // Check valid power type      if (m_spellInfo->PowerType >= MAX_POWERS)      { -        sLog->outError("Spell::CheckPower: Unknown power type '%d'", m_spellInfo->PowerType); +        sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::CheckPower: Unknown power type '%d'", m_spellInfo->PowerType);          return SPELL_FAILED_UNKNOWN;      } @@ -6425,7 +6341,7 @@ void Spell::Delayed() // only called in DealDamage()      else          m_timer += delaytime; -    sLog->outDetail("Spell %u partially interrupted for (%d) ms at damage", m_spellInfo->Id, delaytime); +    sLog->outInfo(LOG_FILTER_SPELLS_AURAS, "Spell %u partially interrupted for (%d) ms at damage", m_spellInfo->Id, delaytime);      WorldPacket data(SMSG_SPELL_DELAYED, 8+4);      data.append(m_caster->GetPackGUID()); @@ -6641,7 +6557,7 @@ SpellEvent::~SpellEvent()      }      else      { -        sLog->outError("~SpellEvent: %s %u tried to delete non-deletable spell %u. Was not deleted, causes memory leak.", +        sLog->outError(LOG_FILTER_SPELLS_AURAS, "~SpellEvent: %s %u tried to delete non-deletable spell %u. Was not deleted, causes memory leak.",              (m_Spell->GetCaster()->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), m_Spell->GetCaster()->GetGUIDLow(), m_Spell->m_spellInfo->Id);          ASSERT(false);      } @@ -7162,15 +7078,29 @@ void Spell::CallScriptAfterHitHandlers()      }  } -void Spell::CallScriptAfterUnitTargetSelectHandlers(std::list<Unit*>& unitTargets, SpellEffIndex effIndex) +void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex)  {      for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)      { -        (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_UNIT_TARGET_SELECT); -        std::list<SpellScript::UnitTargetHandler>::iterator hookItrEnd = (*scritr)->OnUnitTargetSelect.end(), hookItr = (*scritr)->OnUnitTargetSelect.begin(); +        (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT); +        std::list<SpellScript::ObjectAreaTargetSelectHandler>::iterator hookItrEnd = (*scritr)->OnObjectAreaTargetSelect.end(), hookItr = (*scritr)->OnObjectAreaTargetSelect.begin();          for (; hookItr != hookItrEnd; ++hookItr)              if ((*hookItr).IsEffectAffected(m_spellInfo, effIndex)) -                (*hookItr).Call(*scritr, unitTargets); +                (*hookItr).Call(*scritr, targets); + +        (*scritr)->_FinishScriptCall(); +    } +} + +void Spell::CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffIndex effIndex) +{ +    for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) +    { +        (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT); +        std::list<SpellScript::ObjectTargetSelectHandler>::iterator hookItrEnd = (*scritr)->OnObjectTargetSelect.end(), hookItr = (*scritr)->OnObjectTargetSelect.begin(); +        for (; hookItr != hookItrEnd; ++hookItr) +            if ((*hookItr).IsEffectAffected(m_spellInfo, effIndex)) +                (*hookItr).Call(*scritr, target);          (*scritr)->_FinishScriptCall();      } @@ -7204,12 +7134,6 @@ void Spell::PrepareTriggersExecutedOnHit()      // todo: move this to scripts      switch (m_spellInfo->SpellFamilyName)      { -        case SPELLFAMILY_GENERIC: -        { -            if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages -                m_preCastSpell = 11196;  // Recently Bandaged -            break; -        }          case SPELLFAMILY_MAGE:          {               // Permafrost  | 
