root/trunk/src/game/Spell.cpp @ 9

Revision 6, 201.9 kB (checked in by yumileroy, 17 years ago)

[svn] * Added ACE for Linux and Windows (Thanks Derex for Linux part and partial Windows part)
* Updated to 6721 and 676
* Fixed TrinityScript? logo
* Version updated to 0.2.6721.676

Original author: Neo2003
Date: 2008-10-04 06:17:19-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18
19#include "Common.h"
20#include "Database/DatabaseEnv.h"
21#include "WorldPacket.h"
22#include "WorldSession.h"
23#include "GridNotifiers.h"
24#include "GridNotifiersImpl.h"
25#include "Opcodes.h"
26#include "Log.h"
27#include "UpdateMask.h"
28#include "World.h"
29#include "ObjectMgr.h"
30#include "SpellMgr.h"
31#include "Player.h"
32#include "Pet.h"
33#include "Unit.h"
34#include "Spell.h"
35#include "DynamicObject.h"
36#include "SpellAuras.h"
37#include "Group.h"
38#include "UpdateData.h"
39#include "MapManager.h"
40#include "ObjectAccessor.h"
41#include "CellImpl.h"
42#include "Policies/SingletonImp.h"
43#include "SharedDefines.h"
44#include "Tools.h"
45#include "LootMgr.h"
46#include "VMapFactory.h"
47#include "BattleGround.h"
48#include "Util.h"
49
50#define SPELL_CHANNEL_UPDATE_INTERVAL 1000
51
52extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
53
54bool IsQuestTameSpell(uint32 spellId)
55{
56    SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
57    if (!spellproto) return false;
58
59    return spellproto->Effect[0] == SPELL_EFFECT_THREAT
60        && spellproto->Effect[1] == SPELL_EFFECT_APPLY_AURA && spellproto->EffectApplyAuraName[1] == SPELL_AURA_DUMMY;
61}
62
63SpellCastTargets::SpellCastTargets()
64{
65    m_unitTarget = NULL;
66    m_itemTarget = NULL;
67    m_GOTarget   = NULL;
68
69    m_unitTargetGUID   = 0;
70    m_GOTargetGUID     = 0;
71    m_CorpseTargetGUID = 0;
72    m_itemTargetGUID   = 0;
73    m_itemTargetEntry  = 0;
74
75    m_srcX = m_srcY = m_srcZ = m_destX = m_destY = m_destZ = 0;
76    m_strTarget = "";
77    m_targetMask = 0;
78}
79
80SpellCastTargets::~SpellCastTargets()
81{
82}
83
84void SpellCastTargets::setUnitTarget(Unit *target)
85{
86    if (!target)
87        return;
88
89    m_destX = target->GetPositionX();
90    m_destY = target->GetPositionY();
91    m_destZ = target->GetPositionZ();
92    m_unitTarget = target;
93    m_unitTargetGUID = target->GetGUID();
94    m_targetMask |= TARGET_FLAG_UNIT;
95}
96
97void SpellCastTargets::setDestination(float x, float y, float z)
98{
99    m_destX = x;
100    m_destY = y;
101    m_destZ = z;
102    m_targetMask |= TARGET_FLAG_DEST_LOCATION;
103}
104
105void SpellCastTargets::setGOTarget(GameObject *target)
106{
107    m_GOTarget = target;
108    m_GOTargetGUID = target->GetGUID();
109    //    m_targetMask |= TARGET_FLAG_OBJECT;
110}
111
112void SpellCastTargets::setItemTarget(Item* item)
113{
114    if(!item)
115        return;
116
117    m_itemTarget = item;
118    m_itemTargetGUID = item->GetGUID();
119    m_itemTargetEntry = item->GetEntry();
120    m_targetMask |= TARGET_FLAG_ITEM;
121}
122
123void SpellCastTargets::setCorpseTarget(Corpse* corpse)
124{
125    m_CorpseTargetGUID = corpse->GetGUID();
126}
127
128void SpellCastTargets::Update(Unit* caster)
129{
130    m_GOTarget   = m_GOTargetGUID ? ObjectAccessor::GetGameObject(*caster,m_GOTargetGUID) : NULL;
131    m_unitTarget = m_unitTargetGUID ?
132        ( m_unitTargetGUID==caster->GetGUID() ? caster : ObjectAccessor::GetUnit(*caster, m_unitTargetGUID) ) :
133    NULL;
134
135    m_itemTarget = NULL;
136    if(caster->GetTypeId()==TYPEID_PLAYER)
137    {
138        if(m_targetMask & TARGET_FLAG_ITEM)
139            m_itemTarget = ((Player*)caster)->GetItemByGuid(m_itemTargetGUID);
140        else
141        {
142            Player* pTrader = ((Player*)caster)->GetTrader();
143            if(pTrader && m_itemTargetGUID < TRADE_SLOT_COUNT)
144                m_itemTarget = pTrader->GetItemByPos(pTrader->GetItemPosByTradeSlot(m_itemTargetGUID));
145        }
146        if(m_itemTarget)
147            m_itemTargetEntry = m_itemTarget->GetEntry();
148    }
149}
150
151bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )
152{
153    if(data->rpos()+4 > data->size())
154        return false;
155
156    *data >> m_targetMask;
157
158    if(m_targetMask == TARGET_FLAG_SELF)
159    {
160        m_destX = caster->GetPositionX();
161        m_destY = caster->GetPositionY();
162        m_destZ = caster->GetPositionZ();
163        m_unitTarget = caster;
164        m_unitTargetGUID = caster->GetGUID();
165        return true;
166    }
167    // TARGET_FLAG_UNK2 is used for non-combat pets, maybe other?
168    if( m_targetMask & (TARGET_FLAG_UNIT|TARGET_FLAG_UNK2) )
169        if(!readGUID(*data, m_unitTargetGUID))
170            return false;
171
172    if( m_targetMask & ( TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK ))
173        if(!readGUID(*data, m_GOTargetGUID))
174            return false;
175
176    if(( m_targetMask & ( TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM )) && caster->GetTypeId() == TYPEID_PLAYER)
177        if(!readGUID(*data, m_itemTargetGUID))
178            return false;
179
180    if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION )
181    {
182        if(data->rpos()+4+4+4 > data->size())
183            return false;
184
185        *data >> m_srcX >> m_srcY >> m_srcZ;
186        if(!MaNGOS::IsValidMapCoord(m_srcX, m_srcY, m_srcZ))
187            return false;
188    }
189
190    if( m_targetMask & TARGET_FLAG_DEST_LOCATION )
191    {
192        if(data->rpos()+4+4+4 > data->size())
193            return false;
194
195        *data >> m_destX >> m_destY >> m_destZ;
196        if(!MaNGOS::IsValidMapCoord(m_destX, m_destY, m_destZ))
197            return false;
198    }
199
200    if( m_targetMask & TARGET_FLAG_STRING )
201    {
202        if(data->rpos()+1 > data->size())
203            return false;
204
205        *data >> m_strTarget;
206    }
207
208    if( m_targetMask & (TARGET_FLAG_CORPSE | TARGET_FLAG_PVP_CORPSE ) )
209        if(!readGUID(*data, m_CorpseTargetGUID))
210            return false;
211
212    // find real units/GOs
213    Update(caster);
214    return true;
215}
216
217void SpellCastTargets::write ( WorldPacket * data )
218{
219    *data << uint32(m_targetMask);
220
221    if( m_targetMask & ( TARGET_FLAG_UNIT | TARGET_FLAG_PVP_CORPSE | TARGET_FLAG_OBJECT | TARGET_FLAG_CORPSE | TARGET_FLAG_UNK2 ) )
222    {
223        if(m_targetMask & TARGET_FLAG_UNIT)
224        {
225            if(m_unitTarget)
226                data->append(m_unitTarget->GetPackGUID());
227            else
228                *data << uint8(0);
229        }
230        else if( m_targetMask & ( TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK ) )
231        {
232            if(m_GOTarget)
233                data->append(m_GOTarget->GetPackGUID());
234            else
235                *data << uint8(0);
236        }
237        else if( m_targetMask & ( TARGET_FLAG_CORPSE | TARGET_FLAG_PVP_CORPSE ) )
238            data->appendPackGUID(m_CorpseTargetGUID);
239        else
240            *data << uint8(0);
241    }
242
243    if( m_targetMask & ( TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM ) )
244    {
245        if(m_itemTarget)
246            data->append(m_itemTarget->GetPackGUID());
247        else
248            *data << uint8(0);
249    }
250
251    if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION )
252        *data << m_srcX << m_srcY << m_srcZ;
253
254    if( m_targetMask & TARGET_FLAG_DEST_LOCATION )
255        *data << m_destX << m_destY << m_destZ;
256
257    if( m_targetMask & TARGET_FLAG_STRING )
258        *data << m_strTarget;
259}
260
261Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 originalCasterGUID, Spell** triggeringContainer )
262{
263    ASSERT( Caster != NULL && info != NULL );
264    ASSERT( info == sSpellStore.LookupEntry( info->Id ) && "`info` must be pointer to sSpellStore element");
265
266    m_spellInfo = info;
267    m_caster = Caster;
268    m_selfContainer = NULL;
269    m_triggeringContainer = triggeringContainer;
270    m_deletable = true;
271    m_delayAtDamageCount = 0;
272
273    m_applyMultiplierMask = 0;
274
275    // Get data for type of attack
276    switch (m_spellInfo->DmgClass)
277    {
278        case SPELL_DAMAGE_CLASS_MELEE:
279            if (m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
280                m_attackType = OFF_ATTACK;
281            else
282                m_attackType = BASE_ATTACK;
283            break;
284        case SPELL_DAMAGE_CLASS_RANGED:
285            m_attackType = RANGED_ATTACK;
286            break;
287        default:
288                                                            // Wands
289            if (m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_WAND)
290                m_attackType = RANGED_ATTACK;
291            else
292                m_attackType = BASE_ATTACK;
293            break;
294    }
295
296    m_spellSchoolMask = GetSpellSchoolMask(info);           // Can be override for some spell (wand shoot for example)
297
298    if(m_attackType == RANGED_ATTACK)
299    {
300        // wand case
301        if((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId()==TYPEID_PLAYER)
302        {
303            if(Item* pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK))
304                m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage->DamageType);
305        }
306    }
307
308    if(originalCasterGUID)
309        m_originalCasterGUID = originalCasterGUID;
310    else
311        m_originalCasterGUID = m_caster->GetGUID();
312
313    if(m_originalCasterGUID==m_caster->GetGUID())
314        m_originalCaster = m_caster;
315    else
316    {
317        m_originalCaster = ObjectAccessor::GetUnit(*m_caster,m_originalCasterGUID);
318        if(m_originalCaster && !m_originalCaster->IsInWorld()) m_originalCaster = NULL;
319    }
320
321    for(int i=0; i <3; ++i)
322        m_currentBasePoints[i] = m_spellInfo->EffectBasePoints[i];
323
324    m_spellState = SPELL_STATE_NULL;
325
326    m_castPositionX = m_castPositionY = m_castPositionZ = 0;
327    m_TriggerSpells.clear();
328    m_IsTriggeredSpell = triggered;
329    //m_AreaAura = false;
330    m_CastItem = NULL;
331
332    unitTarget = NULL;
333    itemTarget = NULL;
334    gameObjTarget = NULL;
335    focusObject = NULL;
336    m_cast_count = 0;
337    m_triggeredByAuraSpell  = NULL;
338
339    //Auto Shot & Shoot
340    if( m_spellInfo->AttributesEx2 == 0x000020 && !triggered )
341        m_autoRepeat = true;
342    else
343        m_autoRepeat = false;
344
345    m_powerCost = 0;                                        // setup to correct value in Spell::prepare, don't must be used before.
346    m_casttime = 0;                                         // setup to correct value in Spell::prepare, don't must be used before.
347    m_timer = 0;                                            // will set to castime in preper
348
349    m_needAliveTargetMask = 0;
350
351    // determine reflection
352    m_canReflect = false;
353
354    if(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && (m_spellInfo->AttributesEx2 & 0x4)==0)
355    {
356        for(int j=0;j<3;j++)
357        {
358            if (m_spellInfo->Effect[j]==0)
359                continue;
360
361            if(!IsPositiveTarget(m_spellInfo->EffectImplicitTargetA[j],m_spellInfo->EffectImplicitTargetB[j]))
362                m_canReflect = true;
363            else
364                m_canReflect = (m_spellInfo->AttributesEx & (1<<7)) ? true : false;
365
366            if(m_canReflect)
367                continue;
368            else
369                break;
370        }
371    }
372
373    CleanupTargetList();
374}
375
376Spell::~Spell()
377{
378}
379
380void Spell::FillTargetMap()
381{
382    // TODO: ADD the correct target FILLS!!!!!!
383
384    for(uint32 i=0;i<3;i++)
385    {
386        // not call for empty effect.
387        // Also some spells use not used effect targets for store targets for dummy effect in triggered spells
388        if(m_spellInfo->Effect[i]==0)
389            continue;
390
391        // targets for TARGET_SCRIPT_COORDINATES (A) and TARGET_SCRIPT  filled in Spell::canCast call
392        if( m_spellInfo->EffectImplicitTargetA[i] == TARGET_SCRIPT_COORDINATES ||
393            m_spellInfo->EffectImplicitTargetA[i] == TARGET_SCRIPT ||
394            m_spellInfo->EffectImplicitTargetB[i] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[i] != TARGET_SELF )
395            continue;
396
397        // TODO: find a way so this is not needed?
398        // for area auras always add caster as target (needed for totems for example)
399        if(IsAreaAuraEffect(m_spellInfo->Effect[i]))
400            AddUnitTarget(m_caster, i);
401
402        std::list<Unit*> tmpUnitMap;
403
404        // TargetA/TargetB dependent from each other, we not switch to full support this dependences
405        // but need it support in some know cases
406        switch(m_spellInfo->EffectImplicitTargetA[i])
407        {
408            case TARGET_ALL_AROUND_CASTER:
409                if( m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_PARTY ||
410                    m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER ||
411                    m_spellInfo->EffectImplicitTargetB[i]==TARGET_RANDOM_RAID_MEMBER )
412                {
413                    SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap);
414                }
415                // Note: this hack with search required until GO casting not implemented
416                // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
417                // currently each enemy selected explicitly and self cast damage
418                else if(m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_ENEMY_IN_AREA && m_spellInfo->Effect[i]==SPELL_EFFECT_ENVIRONMENTAL_DAMAGE)
419                {
420                    if(m_targets.getUnitTarget())
421                        tmpUnitMap.push_back(m_targets.getUnitTarget());
422                }
423                else
424                {
425                    SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap);
426                    SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap);
427                }
428                break;
429            case TARGET_TABLE_X_Y_Z_COORDINATES:
430                // Only if target A, for target B (used in teleports) dest select in effect
431                SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap);
432                break;
433            default:
434                switch(m_spellInfo->EffectImplicitTargetB[i])
435                {
436                    case TARGET_SCRIPT_COORDINATES:         // B case filled in canCast but we need fill unit list base at A case
437                        SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap);
438                        break;
439                    default:
440                        SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap);
441                        SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap);
442                        break;
443                }
444                break;
445        }
446
447        if( (m_spellInfo->EffectImplicitTargetA[i]==0 || m_spellInfo->EffectImplicitTargetA[i]==TARGET_EFFECT_SELECT) &&
448            (m_spellInfo->EffectImplicitTargetB[i]==0 || m_spellInfo->EffectImplicitTargetB[i]==TARGET_EFFECT_SELECT) )
449        {
450            // add here custom effects that need default target.
451            // FOR EVERY TARGET TYPE THERE IS A DIFFERENT FILL!!
452            switch(m_spellInfo->Effect[i])
453            {
454                case SPELL_EFFECT_DUMMY:
455                {
456                    switch(m_spellInfo->Id)
457                    {
458                        case 20577:                         // Cannibalize
459                        {
460                            // non-standard target selection
461                            SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
462                            float max_range = GetSpellMaxRange(srange);
463
464                            CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
465                            Cell cell(p);
466                            cell.data.Part.reserved = ALL_DISTRICT;
467                            cell.SetNoCreate();
468
469                            WorldObject* result = NULL;
470
471                            MaNGOS::CannibalizeObjectCheck u_check(m_caster, max_range);
472                            MaNGOS::WorldObjectSearcher<MaNGOS::CannibalizeObjectCheck > searcher(result, u_check);
473
474                            TypeContainerVisitor<MaNGOS::WorldObjectSearcher<MaNGOS::CannibalizeObjectCheck >, GridTypeMapContainer > grid_searcher(searcher);
475                            CellLock<GridReadGuard> cell_lock(cell, p);
476                            cell_lock->Visit(cell_lock, grid_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
477
478                            if(!result)
479                            {
480                                TypeContainerVisitor<MaNGOS::WorldObjectSearcher<MaNGOS::CannibalizeObjectCheck >, WorldTypeMapContainer > world_searcher(searcher);
481                                cell_lock->Visit(cell_lock, world_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
482                            }
483
484                            if(result)
485                            {
486                                switch(result->GetTypeId())
487                                {
488                                    case TYPEID_UNIT:
489                                    case TYPEID_PLAYER:
490                                        tmpUnitMap.push_back((Unit*)result);
491                                        break;
492                                    case TYPEID_CORPSE:
493                                        m_targets.setCorpseTarget((Corpse*)result);
494                                        if(Player* owner = ObjectAccessor::FindPlayer(((Corpse*)result)->GetOwnerGUID()))
495                                            tmpUnitMap.push_back(owner);
496                                        break;
497                                }
498                            }
499                            else
500                            {
501                                // clear cooldown at fail
502                                if(m_caster->GetTypeId()==TYPEID_PLAYER)
503                                {
504                                    ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
505
506                                    WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
507                                    data << uint32(m_spellInfo->Id);
508                                    data << uint64(m_caster->GetGUID());
509                                    ((Player*)m_caster)->GetSession()->SendPacket(&data);
510                                }
511
512                                SendCastResult(SPELL_FAILED_NO_EDIBLE_CORPSES);
513                                finish(false);
514                            }
515                            break;
516                        }
517                        default:
518                            if(m_targets.getUnitTarget())
519                                tmpUnitMap.push_back(m_targets.getUnitTarget());
520                            break;
521                    }
522                    break;
523                }
524                case SPELL_EFFECT_RESURRECT:
525                case SPELL_EFFECT_PARRY:
526                case SPELL_EFFECT_BLOCK:
527                case SPELL_EFFECT_CREATE_ITEM:
528                case SPELL_EFFECT_TRIGGER_SPELL:
529                case SPELL_EFFECT_TRIGGER_MISSILE:
530                case SPELL_EFFECT_LEARN_SPELL:
531                case SPELL_EFFECT_SKILL_STEP:
532                case SPELL_EFFECT_PROFICIENCY:
533                case SPELL_EFFECT_SUMMON_POSSESSED:
534                case SPELL_EFFECT_SUMMON_OBJECT_WILD:
535                case SPELL_EFFECT_SELF_RESURRECT:
536                case SPELL_EFFECT_REPUTATION:
537                    if(m_targets.getUnitTarget())
538                        tmpUnitMap.push_back(m_targets.getUnitTarget());
539                    break;
540                case SPELL_EFFECT_SUMMON_PLAYER:
541                    if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->GetSelection())
542                    {
543                        Player* target = objmgr.GetPlayer(((Player*)m_caster)->GetSelection());
544                        if(target)
545                            tmpUnitMap.push_back(target);
546                    }
547                    break;
548                case SPELL_EFFECT_RESURRECT_NEW:
549                    if(m_targets.getUnitTarget())
550                        tmpUnitMap.push_back(m_targets.getUnitTarget());
551                    if(m_targets.getCorpseTargetGUID())
552                    {
553                        Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster,m_targets.getCorpseTargetGUID());
554                        if(corpse)
555                        {
556                            Player* owner = ObjectAccessor::FindPlayer(corpse->GetOwnerGUID());
557                            if(owner)
558                                tmpUnitMap.push_back(owner);
559                        }
560                    }
561                    break;
562                case SPELL_EFFECT_SUMMON:
563                    if(m_spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED || m_spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED2)
564                    {
565                        if(m_targets.getUnitTarget())
566                            tmpUnitMap.push_back(m_targets.getUnitTarget());
567                    }
568                    else
569                        tmpUnitMap.push_back(m_caster);
570                    break;
571                case SPELL_EFFECT_SUMMON_CHANGE_ITEM:
572                case SPELL_EFFECT_SUMMON_WILD:
573                case SPELL_EFFECT_SUMMON_GUARDIAN:
574                case SPELL_EFFECT_TRANS_DOOR:
575                case SPELL_EFFECT_ADD_FARSIGHT:
576                case SPELL_EFFECT_STUCK:
577                case SPELL_EFFECT_DESTROY_ALL_TOTEMS:
578                case SPELL_EFFECT_SUMMON_DEMON:
579                case SPELL_EFFECT_SKILL:
580                    tmpUnitMap.push_back(m_caster);
581                    break;
582                case SPELL_EFFECT_LEARN_PET_SPELL:
583                    if(Pet* pet = m_caster->GetPet())
584                        tmpUnitMap.push_back(pet);
585                    break;
586                case SPELL_EFFECT_ENCHANT_ITEM:
587                case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY:
588                case SPELL_EFFECT_DISENCHANT:
589                case SPELL_EFFECT_FEED_PET:
590                case SPELL_EFFECT_PROSPECTING:
591                    if(m_targets.getItemTarget())
592                        AddItemTarget(m_targets.getItemTarget(), i);
593                    break;
594                case SPELL_EFFECT_APPLY_AURA:
595                    switch(m_spellInfo->EffectApplyAuraName[i])
596                    {
597                        case SPELL_AURA_ADD_FLAT_MODIFIER:  // some spell mods auras have 0 target modes instead expected TARGET_SELF(1) (and present for other ranks for same spell for example)
598                        case SPELL_AURA_ADD_PCT_MODIFIER:
599                            tmpUnitMap.push_back(m_caster);
600                            break;
601                        default:                            // apply to target in other case
602                            if(m_targets.getUnitTarget())
603                                tmpUnitMap.push_back(m_targets.getUnitTarget());
604                            break;
605                    }
606                    break;
607                case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
608                                                            // AreaAura
609                    if(m_spellInfo->Attributes == 0x9050000 || m_spellInfo->Attributes == 0x10000)
610                        SetTargetMap(i,TARGET_AREAEFFECT_PARTY,tmpUnitMap);
611                    break;
612                case SPELL_EFFECT_SKIN_PLAYER_CORPSE:
613                    if(m_targets.getUnitTarget())
614                    {
615                        tmpUnitMap.push_back(m_targets.getUnitTarget());
616                    }
617                    else if (m_targets.getCorpseTargetGUID())
618                    {
619                        Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster,m_targets.getCorpseTargetGUID());
620                        if(corpse)
621                        {
622                            Player* owner = ObjectAccessor::FindPlayer(corpse->GetOwnerGUID());
623                            if(owner)
624                                tmpUnitMap.push_back(owner);
625                        }
626                    }
627                    break;
628                default:
629                    break;
630            }
631        }
632        if(IsChanneledSpell(m_spellInfo) && !tmpUnitMap.empty())
633            m_needAliveTargetMask  |= (1<<i);
634
635        if(m_caster->GetTypeId() == TYPEID_PLAYER)
636        {
637            Player *me = (Player*)m_caster;
638            for (std::list<Unit*>::const_iterator itr = tmpUnitMap.begin(); itr != tmpUnitMap.end(); itr++)
639            {
640                Unit *owner = (*itr)->GetOwner();
641                Unit *u = owner ? owner : (*itr);
642                if(u!=m_caster && u->IsPvP() && (!me->duel || me->duel->opponent != u))
643                {
644                    me->UpdatePvP(true);
645                    me->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
646                    break;
647                }
648            }
649        }
650
651        for (std::list<Unit*>::iterator itr = tmpUnitMap.begin() ; itr != tmpUnitMap.end();)
652        {
653            if(!CheckTarget(*itr, i, false ))
654            {
655                itr = tmpUnitMap.erase(itr);
656                continue;
657            }
658            else
659                ++itr;
660        }
661
662        for(std::list<Unit*>::iterator iunit= tmpUnitMap.begin();iunit != tmpUnitMap.end();++iunit)
663            AddUnitTarget((*iunit), i);
664    }
665}
666
667void Spell::CleanupTargetList()
668{
669    m_UniqueTargetInfo.clear();
670    m_UniqueGOTargetInfo.clear();
671    m_UniqueItemInfo.clear();
672    m_countOfHit = 0;
673    m_countOfMiss = 0;
674    m_delayMoment = 0;
675}
676
677void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)
678{
679    if( m_spellInfo->Effect[effIndex]==0 )
680        return;
681
682    uint64 targetGUID = pVictim->GetGUID();
683
684    // Lookup target in already in list
685    for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
686    {
687        if (targetGUID == ihit->targetGUID)                 // Found in list
688        {
689            ihit->effectMask |= 1<<effIndex;                // Add only effect mask
690            return;
691        }
692    }
693
694    // This is new target calculate data for him
695
696    // Get spell hit result on target
697    TargetInfo target;
698    target.targetGUID = targetGUID;                         // Store target GUID
699    target.effectMask = 1<<effIndex;                        // Store index of effect
700    target.processed  = false;                              // Effects not apply on target
701
702    // Calculate hit result
703    target.missCondition = m_caster->SpellHitResult(pVictim, m_spellInfo, m_canReflect);
704    if (target.missCondition == SPELL_MISS_NONE)
705        ++m_countOfHit;
706    else
707        ++m_countOfMiss;
708
709    // Spell have speed - need calculate incoming time
710    if (m_spellInfo->speed > 0.0f)
711    {
712        // calculate spell incoming interval
713        float dist = m_caster->GetDistance(pVictim->GetPositionX(), pVictim->GetPositionY(), pVictim->GetPositionZ());
714        if (dist < 5.0f) dist = 5.0f;
715        target.timeDelay = (uint64) floor(dist / m_spellInfo->speed * 1000.0f);
716
717        // Calculate minimum incoming time
718        if (m_delayMoment==0 || m_delayMoment>target.timeDelay)
719            m_delayMoment = target.timeDelay;
720    }
721    else
722        target.timeDelay = 0LL;
723
724    // If target reflect spell back to caster
725    if (target.missCondition==SPELL_MISS_REFLECT)
726    {
727        // Calculate reflected spell result on caster
728        target.reflectResult =  m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect);
729
730        if (target.reflectResult == SPELL_MISS_REFLECT)     // Impossible reflect again, so simply deflect spell
731            target.reflectResult = SPELL_MISS_PARRY;
732
733        // Increase time interval for reflected spells by 1.5
734        target.timeDelay+=target.timeDelay>>1;
735    }
736    else
737        target.reflectResult = SPELL_MISS_NONE;
738
739    // Add target to list
740    m_UniqueTargetInfo.push_back(target);
741}
742
743void Spell::AddUnitTarget(uint64 unitGUID, uint32 effIndex)
744{
745    Unit* unit = m_caster->GetGUID()==unitGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, unitGUID);
746    if (unit)
747        AddUnitTarget(unit, effIndex);
748}
749
750void Spell::AddGOTarget(GameObject* pVictim, uint32 effIndex)
751{
752    if( m_spellInfo->Effect[effIndex]==0 )
753        return;
754
755    uint64 targetGUID = pVictim->GetGUID();
756
757    // Lookup target in already in list
758    for(std::list<GOTargetInfo>::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit)
759    {
760        if (targetGUID == ihit->targetGUID)                 // Found in list
761        {
762            ihit->effectMask |= 1<<effIndex;                // Add only effect mask
763            return;
764        }
765    }
766
767    // This is new target calculate data for him
768
769    GOTargetInfo target;
770    target.targetGUID = targetGUID;
771    target.effectMask = 1<<effIndex;
772    target.processed  = false;                              // Effects not apply on target
773
774    // Spell have speed - need calculate incoming time
775    if (m_spellInfo->speed > 0.0f)
776    {
777        // calculate spell incoming interval
778        float dist = m_caster->GetDistance(pVictim->GetPositionX(), pVictim->GetPositionY(), pVictim->GetPositionZ());
779        if (dist < 5.0f) dist = 5.0f;
780        target.timeDelay = (uint64) floor(dist / m_spellInfo->speed * 1000.0f);
781        if (m_delayMoment==0 || m_delayMoment>target.timeDelay)
782            m_delayMoment = target.timeDelay;
783    }
784    else
785        target.timeDelay = 0LL;
786
787    ++m_countOfHit;
788
789    // Add target to list
790    m_UniqueGOTargetInfo.push_back(target);
791}
792
793void Spell::AddGOTarget(uint64 goGUID, uint32 effIndex)
794{
795    GameObject* go = ObjectAccessor::GetGameObject(*m_caster, goGUID);
796    if (go)
797        AddGOTarget(go, effIndex);
798}
799
800void Spell::AddItemTarget(Item* pitem, uint32 effIndex)
801{
802    if( m_spellInfo->Effect[effIndex]==0 )
803        return;
804
805    // Lookup target in already in list
806    for(std::list<ItemTargetInfo>::iterator ihit= m_UniqueItemInfo.begin();ihit != m_UniqueItemInfo.end();++ihit)
807    {
808        if (pitem == ihit->item)                            // Found in list
809        {
810            ihit->effectMask |= 1<<effIndex;                // Add only effect mask
811            return;
812        }
813    }
814
815    // This is new target add data
816
817    ItemTargetInfo target;
818    target.item       = pitem;
819    target.effectMask = 1<<effIndex;
820    m_UniqueItemInfo.push_back(target);
821}
822
823void Spell::doTriggers(SpellMissInfo missInfo, uint32 damage, SpellSchoolMask damageSchoolMask, uint32 block, uint32 absorb, bool crit)
824{
825    // Do triggers depends from hit result (triggers on hit do in effects)
826    // Set aura states depends from hit result
827    if (missInfo!=SPELL_MISS_NONE)
828    {
829        // Miss/dodge/parry/block only for melee based spells
830        // Resist only for magic based spells
831        switch (missInfo)
832        {
833            case SPELL_MISS_MISS:
834                if(m_caster->GetTypeId()== TYPEID_PLAYER)
835                    ((Player*)m_caster)->UpdateWeaponSkill(BASE_ATTACK);
836
837                m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_MISS, m_spellInfo, m_IsTriggeredSpell);
838                break;
839            case SPELL_MISS_RESIST:
840                m_caster->ProcDamageAndSpell(unitTarget, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, damageSchoolMask, m_spellInfo, m_IsTriggeredSpell);
841                break;
842            case SPELL_MISS_DODGE:
843                if(unitTarget->GetTypeId() == TYPEID_PLAYER)
844                    ((Player*)unitTarget)->UpdateDefense();
845
846                // Overpower
847                if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->getClass() == CLASS_WARRIOR)
848                {
849                    ((Player*) m_caster)->AddComboPoints(unitTarget, 1);
850                    m_caster->StartReactiveTimer( REACTIVE_OVERPOWER );
851                }
852
853                // Riposte
854                if (unitTarget->getClass() != CLASS_ROGUE)
855                {
856                    unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true);
857                    unitTarget->StartReactiveTimer( REACTIVE_DEFENSE );
858                }
859
860                m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_DODGE, m_spellInfo, m_IsTriggeredSpell);
861                break;
862            case SPELL_MISS_PARRY:
863                // Update victim defense ?
864                if(unitTarget->GetTypeId() == TYPEID_PLAYER)
865                    ((Player*)unitTarget)->UpdateDefense();
866                // Mongoose bite - set only Counterattack here
867                if (unitTarget->getClass() == CLASS_HUNTER)
868                {
869                    unitTarget->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true);
870                    unitTarget->StartReactiveTimer( REACTIVE_HUNTER_PARRY );
871                }
872                else
873                {
874                    unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true);
875                    unitTarget->StartReactiveTimer( REACTIVE_DEFENSE );
876                }
877                m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_PARRY, m_spellInfo, m_IsTriggeredSpell);
878                break;
879            case SPELL_MISS_BLOCK:
880                unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true);
881                unitTarget->StartReactiveTimer( REACTIVE_DEFENSE );
882
883                m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_BLOCK, m_spellInfo, m_IsTriggeredSpell);
884                break;
885                // Trigger from this events not supported
886            case SPELL_MISS_EVADE:
887            case SPELL_MISS_IMMUNE:
888            case SPELL_MISS_IMMUNE2:
889            case SPELL_MISS_DEFLECT:
890            case SPELL_MISS_ABSORB:
891                // Trigger from reflects need do after get reflect result
892            case SPELL_MISS_REFLECT:
893                break;
894            default:
895                break;
896        }
897    }
898}
899
900void Spell::DoAllEffectOnTarget(TargetInfo *target)
901{
902    if (target->processed)                                  // Check target
903        return;
904    target->processed = true;                               // Target checked in apply effects procedure
905
906    // Get mask of effects for target
907    uint32 mask = target->effectMask;
908    if (mask == 0)                                          // No effects
909        return;
910
911    Unit* unit = m_caster->GetGUID()==target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster,target->targetGUID);
912    if (!unit)
913        return;
914
915    SpellMissInfo missInfo = target->missCondition;
916    // Need init unitTarget by default unit (can changed in code on reflect)
917    // Or on missInfo!=SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem)
918    unitTarget = unit;
919
920    if (missInfo==SPELL_MISS_NONE)                          // In case spell hit target, do all effect on that target
921        DoSpellHitOnUnit(unit, mask);
922    else if (missInfo == SPELL_MISS_REFLECT)                // In case spell reflect from target, do all effect on caster (if hit)
923    {
924        if (target->reflectResult == SPELL_MISS_NONE)       // If reflected spell hit caster -> do all effect on him
925            DoSpellHitOnUnit(m_caster, mask);
926    }
927
928    // Do triggers only on miss/resist/parry/dodge
929    if (missInfo!=SPELL_MISS_NONE)
930        doTriggers(missInfo);
931
932    // Call scripted function for AI if this spell is casted upon a creature (except pets)
933    if(IS_CREATURE_GUID(target->targetGUID))
934    {
935        // cast at creature (or GO) quest objectives update at successful cast finished (+channel finished)
936        // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... )
937        if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() )
938            ((Player*)m_caster)->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id);
939
940        if(((Creature*)unit)->AI())
941            ((Creature*)unit)->AI()->SpellHit(m_caster ,m_spellInfo);
942    }
943}
944
945void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
946{
947    if(!unit || !effectMask)
948        return;
949
950    // Recheck immune (only for delayed spells)
951    if( m_spellInfo->speed && (
952        unit->IsImmunedToDamage(GetSpellSchoolMask(m_spellInfo),true) ||
953        unit->IsImmunedToSpell(m_spellInfo,true) ))
954    {
955        m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_IMMUNE);
956        return;
957    }
958
959    if( m_caster != unit )
960    {
961        if( !m_caster->IsFriendlyTo(unit) )
962        {
963            // for delayed spells ignore not visible explicit target
964            if(m_spellInfo->speed > 0.0f && unit==m_targets.getUnitTarget() && !unit->isVisibleForOrDetect(m_caster,false))
965            {
966                m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE);
967                return;
968            }
969
970            // exclude Arcane Missiles Dummy Aura aura for now (attack on hit)
971            // TODO: find way to not need this?
972            if(!(m_spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
973                m_spellInfo->SpellFamilyFlags & 0x800LL))
974            {
975                unit->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
976
977                if( !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) )
978                {
979                    if(!unit->IsStandState() && !unit->hasUnitState(UNIT_STAT_STUNDED))
980                        unit->SetStandState(PLAYER_STATE_NONE);
981
982                    if(!unit->isInCombat() && unit->GetTypeId() != TYPEID_PLAYER && ((Creature*)unit)->AI())
983                        ((Creature*)unit)->AI()->AttackStart(m_caster);
984
985                    unit->SetInCombatWith(m_caster);
986                    m_caster->SetInCombatWith(unit);
987
988                    if(Player *attackedPlayer = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
989                    {
990                        m_caster->SetContestedPvP(attackedPlayer);
991                    }
992                    unit->AddThreat(m_caster, 0.0f);
993                }
994            }
995        }
996        else
997        {
998            // for delayed spells ignore negative spells (after duel end) for friendly targets
999            if(m_spellInfo->speed > 0.0f && !IsPositiveSpell(m_spellInfo->Id))
1000            {
1001                m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE);
1002                return;
1003            }
1004
1005            // assisting case, healing and resurrection
1006            if(unit->hasUnitState(UNIT_STAT_ATTACK_PLAYER))
1007                m_caster->SetContestedPvP();
1008            if( unit->isInCombat() && !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) )
1009            {
1010                m_caster->SetInCombatState(unit->GetCombatTimer() > 0);
1011                unit->getHostilRefManager().threatAssist(m_caster, 0.0f);
1012            }
1013        }
1014    }
1015
1016    // Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add
1017    m_diminishGroup = GetDiminishingReturnsGroupForSpell(m_spellInfo,m_triggeredByAuraSpell);
1018    m_diminishLevel = unit->GetDiminishing(m_diminishGroup);
1019    // Increase Diminishing on unit, current informations for actually casts will use values above
1020    if((GetDiminishingReturnsGroupType(m_diminishGroup) == DRTYPE_PLAYER && unit->GetTypeId() == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(m_diminishGroup) == DRTYPE_ALL)
1021        unit->IncrDiminishing(m_diminishGroup);
1022
1023    for(uint32 effectNumber=0;effectNumber<3;effectNumber++)
1024    {
1025        if (effectMask & (1<<effectNumber))
1026        {
1027            HandleEffects(unit,NULL,NULL,effectNumber,m_damageMultipliers[effectNumber]);
1028            if ( m_applyMultiplierMask & (1 << effectNumber) )
1029            {
1030                // Get multiplier
1031                float multiplier = m_spellInfo->DmgMultiplier[effectNumber];
1032                // Apply multiplier mods
1033                if(Player* modOwner = m_originalCaster->GetSpellModOwner())
1034                    modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_EFFECT_PAST_FIRST, multiplier,this);
1035                m_damageMultipliers[effectNumber] *= multiplier;
1036            }
1037        }
1038    }
1039}
1040
1041void Spell::DoAllEffectOnTarget(GOTargetInfo *target)
1042{
1043    if (target->processed)                                  // Check target
1044        return;
1045    target->processed = true;                               // Target checked in apply effects procedure
1046
1047    uint32 effectMask = target->effectMask;
1048    if(!effectMask)
1049        return;
1050
1051    GameObject* go = ObjectAccessor::GetGameObject(*m_caster, target->targetGUID);
1052    if(!go)
1053        return;
1054
1055    for(uint32 effectNumber=0;effectNumber<3;effectNumber++)
1056        if (effectMask & (1<<effectNumber))
1057            HandleEffects(NULL,NULL,go,effectNumber);
1058
1059    // cast at creature (or GO) quest objectives update at successful cast finished (+channel finished)
1060    // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... )
1061    if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() )
1062        ((Player*)m_caster)->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id);
1063}
1064
1065void Spell::DoAllEffectOnTarget(ItemTargetInfo *target)
1066{
1067    uint32 effectMask = target->effectMask;
1068    if(!target->item || !effectMask)
1069        return;
1070
1071    for(uint32 effectNumber=0;effectNumber<3;effectNumber++)
1072        if (effectMask & (1<<effectNumber))
1073            HandleEffects(NULL, target->item, NULL, effectNumber);
1074}
1075
1076bool Spell::IsAliveUnitPresentInTargetList()
1077{
1078    // Not need check return true
1079    if (m_needAliveTargetMask == 0)
1080        return true;
1081
1082    uint8 needAliveTargetMask = m_needAliveTargetMask;
1083
1084    for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1085    {
1086        if( ihit->missCondition == SPELL_MISS_NONE && (needAliveTargetMask & ihit->effectMask) )
1087        {
1088            Unit *unit = m_caster->GetGUID()==ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
1089
1090            if (unit && unit->isAlive())
1091                needAliveTargetMask &= ~ihit->effectMask;   // remove from need alive mask effect that have alive target
1092        }
1093    }
1094
1095    // is all effects from m_needAliveTargetMask have alive targets
1096    return needAliveTargetMask==0;
1097}
1098
1099// Helper for Chain Healing
1100// Spell target first
1101// Raidmates then descending by injury suffered (MaxHealth - Health)
1102// Other players/mobs then descending by injury suffered (MaxHealth - Health)
1103struct ChainHealingOrder : public std::binary_function<const Unit*, const Unit*, bool>
1104{
1105    const Unit* MainTarget;
1106    ChainHealingOrder(Unit const* Target) : MainTarget(Target) {};
1107    // functor for operator ">"
1108    bool operator()(Unit const* _Left, Unit const* _Right) const
1109    {
1110        return (ChainHealingHash(_Left) < ChainHealingHash(_Right));
1111    }
1112    int32 ChainHealingHash(Unit const* Target) const
1113    {
1114        if (Target == MainTarget)
1115            return 0;
1116        else if (Target->GetTypeId() == TYPEID_PLAYER && MainTarget->GetTypeId() == TYPEID_PLAYER &&
1117            ((Player const*)Target)->IsInSameRaidWith((Player const*)MainTarget))
1118        {
1119            if (Target->GetHealth() == Target->GetMaxHealth())
1120                return 40000;
1121            else
1122                return 20000 - Target->GetMaxHealth() + Target->GetHealth();
1123        }
1124        else
1125            return 40000 - Target->GetMaxHealth() + Target->GetHealth();
1126    }
1127};
1128
1129class ChainHealingFullHealth: std::unary_function<const Unit*, bool>
1130{
1131    public:
1132        const Unit* MainTarget;
1133        ChainHealingFullHealth(const Unit* Target) : MainTarget(Target) {};
1134
1135        bool operator()(const Unit* Target)
1136        {
1137            return (Target != MainTarget && Target->GetHealth() == Target->GetMaxHealth());
1138        }
1139};
1140
1141// Helper for targets nearest to the spell target
1142// The spell target is always first unless there is a target at _completely_ the same position (unbelievable case)
1143struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, bool>
1144{
1145    const Unit* MainTarget;
1146    TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {};
1147    // functor for operator ">"
1148    bool operator()(const Unit* _Left, const Unit* _Right) const
1149    {
1150        return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right));
1151    }
1152};
1153
1154void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
1155{
1156    float radius;
1157    if (m_spellInfo->EffectRadiusIndex[i])
1158        radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
1159    else
1160        radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
1161
1162    if(m_originalCaster)
1163        if(Player* modOwner = m_originalCaster->GetSpellModOwner())
1164            modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius,this);
1165
1166    uint32 EffectChainTarget = m_spellInfo->EffectChainTarget[i];
1167    if(m_originalCaster)
1168        if(Player* modOwner = m_originalCaster->GetSpellModOwner())
1169            modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, EffectChainTarget, this);
1170
1171    uint32 unMaxTargets = m_spellInfo->MaxAffectedTargets;
1172    switch(cur)
1173    {
1174        case TARGET_TOTEM_EARTH:
1175        case TARGET_TOTEM_WATER:
1176        case TARGET_TOTEM_AIR:
1177        case TARGET_TOTEM_FIRE:
1178        case TARGET_SELF:
1179        case TARGET_SELF2:
1180        case TARGET_DYNAMIC_OBJECT:
1181        case TARGET_AREAEFFECT_CUSTOM:
1182        case TARGET_AREAEFFECT_CUSTOM_2:
1183        case TARGET_SUMMON:
1184        {
1185            TagUnitMap.push_back(m_caster);
1186            break;
1187        }
1188        case TARGET_RANDOM_ENEMY_CHAIN_IN_AREA:
1189        {
1190            m_targets.m_targetMask = 0;
1191            unMaxTargets = EffectChainTarget;
1192            float max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS;
1193
1194            CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
1195            Cell cell(p);
1196            cell.data.Part.reserved = ALL_DISTRICT;
1197            cell.SetNoCreate();
1198
1199            std::list<Unit *> tempUnitMap;
1200
1201            {
1202                MaNGOS::AnyAoETargetUnitInObjectRangeCheck u_check(m_caster, m_caster, max_range);
1203                MaNGOS::UnitListSearcher<MaNGOS::AnyAoETargetUnitInObjectRangeCheck> searcher(tempUnitMap, u_check);
1204
1205                TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyAoETargetUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
1206                TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyAoETargetUnitInObjectRangeCheck>, GridTypeMapContainer >  grid_unit_searcher(searcher);
1207
1208                CellLock<GridReadGuard> cell_lock(cell, p);
1209                cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1210                cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1211            }
1212
1213            if(tempUnitMap.empty())
1214                break;
1215
1216            tempUnitMap.sort(TargetDistanceOrder(m_caster));
1217
1218            //Now to get us a random target that's in the initial range of the spell
1219            uint32 t = 0;
1220            std::list<Unit *>::iterator itr = tempUnitMap.begin();
1221            while(itr!= tempUnitMap.end() && (*itr)->GetDistance(m_caster) < radius)
1222                ++t, ++itr;
1223
1224            if(!t)
1225                break;
1226
1227            itr = tempUnitMap.begin();
1228            std::advance(itr, rand()%t);
1229            Unit *pUnitTarget = *itr;
1230            TagUnitMap.push_back(pUnitTarget);
1231
1232            tempUnitMap.erase(itr);
1233
1234            tempUnitMap.sort(TargetDistanceOrder(pUnitTarget));
1235
1236            t = unMaxTargets - 1;
1237            Unit *prev = pUnitTarget;
1238            std::list<Unit*>::iterator next = tempUnitMap.begin();
1239
1240            while(t && next != tempUnitMap.end() )
1241            {
1242                if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS)
1243                    break;
1244
1245                if(!prev->IsWithinLOSInMap(*next))
1246                {
1247                    ++next;
1248                    continue;
1249                }
1250
1251                prev = *next;
1252                TagUnitMap.push_back(prev);
1253                tempUnitMap.erase(next);
1254                tempUnitMap.sort(TargetDistanceOrder(prev));
1255                next = tempUnitMap.begin();
1256
1257                --t;
1258            }
1259        }break;
1260        case TARGET_PET:
1261        {
1262            Pet* tmpUnit = m_caster->GetPet();
1263            if (!tmpUnit) break;
1264            TagUnitMap.push_back(tmpUnit);
1265            break;
1266        }
1267        case TARGET_CHAIN_DAMAGE:
1268        {
1269            if (EffectChainTarget <= 1)
1270            {
1271                Unit* pUnitTarget = SelectMagnetTarget();
1272                if(pUnitTarget)
1273                    TagUnitMap.push_back(pUnitTarget);
1274            }
1275            else
1276            {
1277                Unit* pUnitTarget = m_targets.getUnitTarget();
1278                if(!pUnitTarget)
1279                    break;
1280
1281                unMaxTargets = EffectChainTarget;
1282
1283                float max_range;
1284                if(m_spellInfo->DmgClass==SPELL_DAMAGE_CLASS_MELEE)
1285                    max_range = radius;                     //
1286                else
1287                    //FIXME: This very like horrible hack and wrong for most spells
1288                    max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS;
1289
1290                CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
1291                Cell cell(p);
1292                cell.data.Part.reserved = ALL_DISTRICT;
1293                cell.SetNoCreate();
1294
1295                Unit* originalCaster = GetOriginalCaster();
1296                if(originalCaster)
1297                {
1298                    std::list<Unit *> tempUnitMap;
1299
1300                    {
1301                        MaNGOS::AnyAoETargetUnitInObjectRangeCheck u_check(pUnitTarget, originalCaster, max_range);
1302                        MaNGOS::UnitListSearcher<MaNGOS::AnyAoETargetUnitInObjectRangeCheck> searcher(tempUnitMap, u_check);
1303
1304                        TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyAoETargetUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
1305                        TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyAoETargetUnitInObjectRangeCheck>, GridTypeMapContainer >  grid_unit_searcher(searcher);
1306
1307                        CellLock<GridReadGuard> cell_lock(cell, p);
1308                        cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1309                        cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1310                    }
1311
1312                    tempUnitMap.sort(TargetDistanceOrder(pUnitTarget));
1313
1314                    if(tempUnitMap.empty())
1315                        break;
1316
1317                    if(*tempUnitMap.begin() == pUnitTarget)
1318                        tempUnitMap.erase(tempUnitMap.begin());
1319
1320                    TagUnitMap.push_back(pUnitTarget);
1321                    uint32 t = unMaxTargets - 1;
1322                    Unit *prev = pUnitTarget;
1323                    std::list<Unit*>::iterator next = tempUnitMap.begin();
1324
1325                    while(t && next != tempUnitMap.end() )
1326                    {
1327                        if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS)
1328                            break;
1329
1330                        if(!prev->IsWithinLOSInMap(*next))
1331                        {
1332                            ++next;
1333                            continue;
1334                        }
1335
1336                        prev = *next;
1337                        TagUnitMap.push_back(prev);
1338                        tempUnitMap.erase(next);
1339                        tempUnitMap.sort(TargetDistanceOrder(prev));
1340                        next = tempUnitMap.begin();
1341
1342                        --t;
1343                    }
1344                }
1345            }
1346        }break;
1347        case TARGET_ALL_ENEMY_IN_AREA:
1348        {
1349        }break;
1350        case TARGET_ALL_ENEMY_IN_AREA_INSTANT:
1351        {
1352            // targets the ground, not the units in the area
1353            if (m_spellInfo->Effect[i]!=SPELL_EFFECT_PERSISTENT_AREA_AURA)
1354            {
1355                CellPair p(MaNGOS::ComputeCellPair(m_targets.m_destX, m_targets.m_destY));
1356                Cell cell(p);
1357                cell.data.Part.reserved = ALL_DISTRICT;
1358                cell.SetNoCreate();
1359
1360                MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_AOE_DAMAGE);
1361
1362                TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier);
1363                TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, GridTypeMapContainer >  grid_object_notifier(notifier);
1364
1365                CellLock<GridReadGuard> cell_lock(cell, p);
1366                cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1367                cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1368
1369                // exclude caster (this can be important if this not original caster)
1370                TagUnitMap.remove(m_caster);
1371            }
1372        }break;
1373        case TARGET_DUELVSPLAYER_COORDINATES:
1374        {
1375            if(Unit* currentTarget = m_targets.getUnitTarget())
1376            {
1377                m_targets.setDestination(currentTarget->GetPositionX(), currentTarget->GetPositionY(), currentTarget->GetPositionZ());
1378                TagUnitMap.push_back(currentTarget);
1379            }
1380        }break;
1381        case TARGET_ALL_PARTY_AROUND_CASTER:
1382        case TARGET_ALL_PARTY_AROUND_CASTER_2:
1383        case TARGET_ALL_PARTY:
1384        {
1385            Player *pTarget = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself();
1386            Group *pGroup = pTarget ? pTarget->GetGroup() : NULL;
1387
1388            if(pGroup)
1389            {
1390                uint8 subgroup = pTarget->GetSubGroup();
1391
1392                for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
1393                {
1394                    Player* Target = itr->getSource();
1395
1396                    // IsHostileTo check duel and controlled by enemy
1397                    if( Target && Target->GetSubGroup()==subgroup && !m_caster->IsHostileTo(Target) )
1398                    {
1399                        if( m_caster->IsWithinDistInMap(Target, radius) )
1400                            TagUnitMap.push_back(Target);
1401
1402                        if(Pet* pet = Target->GetPet())
1403                            if( m_caster->IsWithinDistInMap(pet, radius) )
1404                                TagUnitMap.push_back(pet);
1405                    }
1406                }
1407            }
1408            else
1409            {
1410                Unit* ownerOrSelf = pTarget ? pTarget : m_caster->GetCharmerOrOwnerOrSelf();
1411                if(ownerOrSelf==m_caster || m_caster->IsWithinDistInMap(ownerOrSelf, radius))
1412                    TagUnitMap.push_back(ownerOrSelf);
1413                if(Pet* pet = ownerOrSelf->GetPet())
1414                    if( m_caster->IsWithinDistInMap(pet, radius) )
1415                        TagUnitMap.push_back(pet);
1416            }
1417        }break;
1418        case TARGET_RANDOM_RAID_MEMBER:
1419        {
1420            if (m_caster->GetTypeId() == TYPEID_PLAYER)
1421                if(Player* target = ((Player*)m_caster)->GetNextRandomRaidMember(radius))
1422                    TagUnitMap.push_back(target);
1423        }break;
1424        case TARGET_SINGLE_FRIEND:
1425        case TARGET_SINGLE_FRIEND_2:
1426        {
1427            if(m_targets.getUnitTarget())
1428                TagUnitMap.push_back(m_targets.getUnitTarget());
1429        }break;
1430        case TARGET_NONCOMBAT_PET:
1431        {
1432            if(Unit* target = m_targets.getUnitTarget())
1433                if( target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isPet() && ((Pet*)target)->getPetType() == MINI_PET)
1434                    TagUnitMap.push_back(target);
1435        }break;
1436        case TARGET_ALL_AROUND_CASTER:
1437        {
1438            CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
1439            Cell cell(p);
1440            cell.data.Part.reserved = ALL_DISTRICT;
1441            cell.SetNoCreate();
1442
1443            MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_SELF_CENTER,SPELL_TARGETS_AOE_DAMAGE);
1444
1445            TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier);
1446            TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, GridTypeMapContainer >  grid_object_notifier(notifier);
1447
1448            CellLock<GridReadGuard> cell_lock(cell, p);
1449            cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1450            cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1451        }break;
1452        case TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER:
1453        {
1454            CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
1455            Cell cell(p);
1456            cell.data.Part.reserved = ALL_DISTRICT;
1457            cell.SetNoCreate();
1458
1459            MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_SELF_CENTER,SPELL_TARGETS_FRIENDLY);
1460
1461            TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier);
1462            TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, GridTypeMapContainer >  grid_object_notifier(notifier);
1463
1464            CellLock<GridReadGuard> cell_lock(cell, p);
1465            cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1466            cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1467        }break;
1468        case TARGET_ALL_FRIENDLY_UNITS_IN_AREA:
1469        {
1470            CellPair p(MaNGOS::ComputeCellPair(m_targets.m_destX, m_targets.m_destY));
1471            Cell cell(p);
1472            cell.data.Part.reserved = ALL_DISTRICT;
1473            cell.SetNoCreate();
1474
1475            MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_FRIENDLY);
1476
1477            TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier);
1478            TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, GridTypeMapContainer >  grid_object_notifier(notifier);
1479
1480            CellLock<GridReadGuard> cell_lock(cell, p);
1481            cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1482            cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1483        }break;
1484        // TARGET_SINGLE_PARTY means that the spells can only be casted on a party member and not on the caster (some sceals, fire shield from imp, etc..)
1485        case TARGET_SINGLE_PARTY:
1486        {
1487            Unit *target = m_targets.getUnitTarget();
1488            // Thoses spells apparently can't be casted on the caster.
1489            if( target && target != m_caster)
1490            {
1491                // Can only be casted on group's members or its pets
1492                Group  *pGroup = NULL;
1493
1494                Unit* owner = m_caster->GetCharmerOrOwner();
1495                Unit *targetOwner = target->GetCharmerOrOwner();
1496                if(owner)
1497                {
1498                    if(owner->GetTypeId() == TYPEID_PLAYER)
1499                    {
1500                        if( target == owner )
1501                        {
1502                            TagUnitMap.push_back(target);
1503                            break;
1504                        }
1505                        pGroup = ((Player*)owner)->GetGroup();
1506                    }
1507                }
1508                else if (m_caster->GetTypeId() == TYPEID_PLAYER)
1509                {
1510                    if( targetOwner == m_caster && target->GetTypeId()==TYPEID_UNIT && ((Creature*)target)->isPet())
1511                    {
1512                        TagUnitMap.push_back(target);
1513                        break;
1514                    }
1515                    pGroup = ((Player*)m_caster)->GetGroup();
1516                }
1517
1518                if(pGroup)
1519                {
1520                    // Our target can also be a player's pet who's grouped with us or our pet. But can't be controlled player
1521                    if(targetOwner)
1522                    {
1523                        if( targetOwner->GetTypeId() == TYPEID_PLAYER &&
1524                            target->GetTypeId()==TYPEID_UNIT && (((Creature*)target)->isPet()) &&
1525                            target->GetOwnerGUID()==targetOwner->GetGUID() &&
1526                            pGroup->IsMember(((Player*)targetOwner)->GetGUID()))
1527                        {
1528                            TagUnitMap.push_back(target);
1529                        }
1530                    }
1531                    // 1Our target can be a player who is on our group
1532                    else if (target->GetTypeId() == TYPEID_PLAYER && pGroup->IsMember(((Player*)target)->GetGUID()))
1533                    {
1534                        TagUnitMap.push_back(target);
1535                    }
1536                }
1537            }
1538        }break;
1539        case TARGET_GAMEOBJECT:
1540        {
1541            if(m_targets.getGOTarget())
1542                AddGOTarget(m_targets.getGOTarget(), i);
1543        }break;
1544        case TARGET_IN_FRONT_OF_CASTER:
1545        {
1546            CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
1547            Cell cell(p);
1548            cell.data.Part.reserved = ALL_DISTRICT;
1549            cell.SetNoCreate();
1550
1551            bool inFront = m_spellInfo->SpellVisual != 3879;
1552            MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, inFront ? PUSH_IN_FRONT : PUSH_IN_BACK,SPELL_TARGETS_AOE_DAMAGE);
1553
1554            TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier);
1555            TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, GridTypeMapContainer >  grid_object_notifier(notifier);
1556
1557            CellLock<GridReadGuard> cell_lock(cell, p);
1558            cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1559            cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1560        }break;
1561        case TARGET_DUELVSPLAYER:
1562        {
1563            Unit *target = m_targets.getUnitTarget();
1564            if(target)
1565            {
1566                if(m_caster->IsFriendlyTo(target))
1567                {
1568                    TagUnitMap.push_back(target);
1569                }
1570                else
1571                {
1572                    Unit* pUnitTarget = SelectMagnetTarget();
1573                    if(pUnitTarget)
1574                        TagUnitMap.push_back(pUnitTarget);
1575                }
1576            }
1577        }break;
1578        case TARGET_GAMEOBJECT_ITEM:
1579        {
1580            if(m_targets.getGOTargetGUID())
1581                AddGOTarget(m_targets.getGOTarget(), i);
1582            else if(m_targets.getItemTarget())
1583                AddItemTarget(m_targets.getItemTarget(), i);
1584            break;
1585        }
1586        case TARGET_MASTER:
1587        {
1588            if(Unit* owner = m_caster->GetCharmerOrOwner())
1589                TagUnitMap.push_back(owner);
1590            break;
1591        }
1592        case TARGET_ALL_ENEMY_IN_AREA_CHANNELED:
1593        {
1594            // targets the ground, not the units in the area
1595            if (m_spellInfo->Effect[i]!=SPELL_EFFECT_PERSISTENT_AREA_AURA)
1596            {
1597                CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
1598                Cell cell(p);
1599                cell.data.Part.reserved = ALL_DISTRICT;
1600                cell.SetNoCreate();
1601
1602                MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_AOE_DAMAGE);
1603
1604                TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier);
1605                TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, GridTypeMapContainer >  grid_object_notifier(notifier);
1606
1607                CellLock<GridReadGuard> cell_lock(cell, p);
1608                cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1609                cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1610            }
1611        }break;
1612        case TARGET_MINION:
1613        {
1614            if(m_spellInfo->Effect[i] != SPELL_EFFECT_DUEL)
1615                TagUnitMap.push_back(m_caster);
1616        }break;
1617        case TARGET_SINGLE_ENEMY:
1618        {
1619            Unit* pUnitTarget = SelectMagnetTarget();
1620            if(pUnitTarget)
1621                TagUnitMap.push_back(pUnitTarget);
1622        }break;
1623        case TARGET_AREAEFFECT_PARTY:
1624        {
1625            Unit* owner = m_caster->GetCharmerOrOwner();
1626            Player *pTarget = NULL;
1627
1628            if(owner)
1629            {
1630                TagUnitMap.push_back(m_caster);
1631                if(owner->GetTypeId() == TYPEID_PLAYER)
1632                    pTarget = (Player*)owner;
1633            }
1634            else if (m_caster->GetTypeId() == TYPEID_PLAYER)
1635            {
1636                if(Unit* target = m_targets.getUnitTarget())
1637                {
1638                    if( target->GetTypeId() != TYPEID_PLAYER)
1639                    {
1640                        if(((Creature*)target)->isPet())
1641                        {
1642                            Unit *targetOwner = target->GetOwner();
1643                            if(targetOwner->GetTypeId() == TYPEID_PLAYER)
1644                                pTarget = (Player*)targetOwner;
1645                        }
1646                    }
1647                    else
1648                        pTarget = (Player*)target;
1649                }
1650            }
1651
1652            Group* pGroup = pTarget ? pTarget->GetGroup() : NULL;
1653
1654            if(pGroup)
1655            {
1656                uint8 subgroup = pTarget->GetSubGroup();
1657
1658                for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
1659                {
1660                    Player* Target = itr->getSource();
1661
1662                    // IsHostileTo check duel and controlled by enemy
1663                    if(Target && Target->GetSubGroup()==subgroup && !m_caster->IsHostileTo(Target))
1664                    {
1665                        if( pTarget->IsWithinDistInMap(Target, radius) )
1666                            TagUnitMap.push_back(Target);
1667
1668                        if(Pet* pet = Target->GetPet())
1669                            if( pTarget->IsWithinDistInMap(pet, radius) )
1670                                TagUnitMap.push_back(pet);
1671                    }
1672                }
1673            }
1674            else if (owner)
1675            {
1676                if(m_caster->IsWithinDistInMap(owner, radius))
1677                    TagUnitMap.push_back(owner);
1678            }
1679            else if(pTarget)
1680            {
1681                TagUnitMap.push_back(pTarget);
1682
1683                if(Pet* pet = pTarget->GetPet())
1684                    if( m_caster->IsWithinDistInMap(pet, radius) )
1685                        TagUnitMap.push_back(pet);
1686            }
1687
1688        }break;
1689        case TARGET_SCRIPT:
1690        {
1691            if(m_targets.getUnitTarget())
1692                TagUnitMap.push_back(m_targets.getUnitTarget());
1693            if(m_targets.getItemTarget())
1694                AddItemTarget(m_targets.getItemTarget(), i);
1695        }break;
1696        case TARGET_SELF_FISHING:
1697        {
1698            TagUnitMap.push_back(m_caster);
1699        }break;
1700        case TARGET_CHAIN_HEAL:
1701        {
1702            Unit* pUnitTarget = m_targets.getUnitTarget();
1703            if(!pUnitTarget)
1704                break;
1705
1706            if (EffectChainTarget <= 1)
1707                TagUnitMap.push_back(pUnitTarget);
1708            else
1709            {
1710                unMaxTargets = EffectChainTarget;
1711                float max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS;
1712
1713                std::list<Unit *> tempUnitMap;
1714
1715                {
1716                    CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
1717                    Cell cell(p);
1718                    cell.data.Part.reserved = ALL_DISTRICT;
1719                    cell.SetNoCreate();
1720
1721                    MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, tempUnitMap, max_range, PUSH_SELF_CENTER, SPELL_TARGETS_FRIENDLY);
1722
1723                    TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier);
1724                    TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, GridTypeMapContainer >  grid_object_notifier(notifier);
1725
1726                    CellLock<GridReadGuard> cell_lock(cell, p);
1727                    cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1728                    cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1729
1730                }
1731
1732                if(m_caster != pUnitTarget && std::find(tempUnitMap.begin(),tempUnitMap.end(),m_caster) == tempUnitMap.end() )
1733                    tempUnitMap.push_front(m_caster);
1734
1735                tempUnitMap.sort(TargetDistanceOrder(pUnitTarget));
1736
1737                if(tempUnitMap.empty())
1738                    break;
1739
1740                if(*tempUnitMap.begin() == pUnitTarget)
1741                    tempUnitMap.erase(tempUnitMap.begin());
1742
1743                TagUnitMap.push_back(pUnitTarget);
1744                uint32 t = unMaxTargets - 1;
1745                Unit *prev = pUnitTarget;
1746                std::list<Unit*>::iterator next = tempUnitMap.begin();
1747
1748                while(t && next != tempUnitMap.end() )
1749                {
1750                    if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS)
1751                        break;
1752
1753                    if(!prev->IsWithinLOSInMap(*next))
1754                    {
1755                        ++next;
1756                        continue;
1757                    }
1758
1759                    if((*next)->GetHealth() == (*next)->GetMaxHealth())
1760                    {
1761                        next = tempUnitMap.erase(next);
1762                        continue;
1763                    }
1764
1765                    prev = *next;
1766                    TagUnitMap.push_back(prev);
1767                    tempUnitMap.erase(next);
1768                    tempUnitMap.sort(TargetDistanceOrder(prev));
1769                    next = tempUnitMap.begin();
1770
1771                    --t;
1772                }
1773            }
1774        }break;
1775        case TARGET_CURRENT_ENEMY_COORDINATES:
1776        {
1777            Unit* currentTarget = m_targets.getUnitTarget();
1778            if(currentTarget)
1779            {
1780                TagUnitMap.push_back(currentTarget);
1781                m_targets.setDestination(currentTarget->GetPositionX(), currentTarget->GetPositionY(), currentTarget->GetPositionZ());
1782                if(m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_ENEMY_IN_AREA_INSTANT)
1783                {
1784                    CellPair p(MaNGOS::ComputeCellPair(currentTarget->GetPositionX(), currentTarget->GetPositionY()));
1785                    Cell cell(p);
1786                    cell.data.Part.reserved = ALL_DISTRICT;
1787                    cell.SetNoCreate();
1788                    MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius,PUSH_TARGET_CENTER, SPELL_TARGETS_AOE_DAMAGE);
1789                    TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_notifier(notifier);
1790                    TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_notifier(notifier);
1791                    CellLock<GridReadGuard> cell_lock(cell, p);
1792                    cell_lock->Visit(cell_lock, world_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1793                    cell_lock->Visit(cell_lock, grid_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1794                }
1795            }
1796        }break;
1797        case TARGET_AREAEFFECT_PARTY_AND_CLASS:
1798        {
1799            Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER
1800                ? (Player*)m_targets.getUnitTarget() : NULL;
1801
1802            Group* pGroup = targetPlayer ? targetPlayer->GetGroup() : NULL;
1803            if(pGroup)
1804            {
1805                for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
1806                {
1807                    Player* Target = itr->getSource();
1808
1809                    // IsHostileTo check duel and controlled by enemy
1810                    if( Target && targetPlayer->IsWithinDistInMap(Target, radius) &&
1811                        targetPlayer->getClass() == Target->getClass() &&
1812                        !m_caster->IsHostileTo(Target) )
1813                    {
1814                        TagUnitMap.push_back(Target);
1815                    }
1816                }
1817            }
1818            else if(m_targets.getUnitTarget())
1819                TagUnitMap.push_back(m_targets.getUnitTarget());
1820            break;
1821        }
1822        case TARGET_TABLE_X_Y_Z_COORDINATES:
1823        {
1824            SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
1825            if(st)
1826            {
1827                if (st->target_mapId == m_caster->GetMapId())
1828                    m_targets.setDestination(st->target_X, st->target_Y, st->target_Z);
1829
1830                // if B==TARGET_TABLE_X_Y_Z_COORDINATES then A already fill all required targets
1831                if (m_spellInfo->EffectImplicitTargetB[i] && m_spellInfo->EffectImplicitTargetB[i]!=TARGET_TABLE_X_Y_Z_COORDINATES)
1832                {
1833                    CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
1834                    Cell cell(p);
1835                    cell.data.Part.reserved = ALL_DISTRICT;
1836                    cell.SetNoCreate();
1837
1838                    SpellTargets targetB = SPELL_TARGETS_AOE_DAMAGE;
1839                    // Select friendly targets for positive effect
1840                    if (IsPositiveEffect(m_spellInfo->Id, i))
1841                        targetB = SPELL_TARGETS_FRIENDLY;
1842
1843                    MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius,PUSH_DEST_CENTER, targetB);
1844
1845                    TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_notifier(notifier);
1846                    TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_notifier(notifier);
1847
1848                    CellLock<GridReadGuard> cell_lock(cell, p);
1849                    cell_lock->Visit(cell_lock, world_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1850                    cell_lock->Visit(cell_lock, grid_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
1851                }
1852            }
1853            else
1854                sLog.outError( "SPELL: unknown target coordinates for spell ID %u\n", m_spellInfo->Id );
1855        }break;
1856        case TARGET_BEHIND_VICTIM:
1857        {
1858            Unit *pTarget = m_caster->getVictim();
1859            if(!pTarget && m_caster->GetTypeId() == TYPEID_PLAYER)
1860                pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
1861
1862            if(pTarget)
1863            {
1864                float _target_x, _target_y, _target_z;
1865                pTarget->GetClosePoint(_target_x, _target_y, _target_z, m_caster->GetObjectSize(), CONTACT_DISTANCE, M_PI);
1866                if(pTarget->IsWithinLOS(_target_x,_target_y,_target_z))
1867                    m_targets.setDestination(_target_x, _target_y, _target_z);
1868            }
1869        }break;
1870        default:
1871            break;
1872    }
1873
1874    if (unMaxTargets && TagUnitMap.size() > unMaxTargets)
1875    {
1876        // make sure one unit is always removed per iteration
1877        uint32 removed_utarget = 0;
1878        for (std::list<Unit*>::iterator itr = TagUnitMap.begin(), next; itr != TagUnitMap.end(); itr = next)
1879        {
1880            next = itr;
1881            ++next;
1882            if (!*itr) continue;
1883            if ((*itr) == m_targets.getUnitTarget())
1884            {
1885                TagUnitMap.erase(itr);
1886                removed_utarget = 1;
1887                //        break;
1888            }
1889        }
1890        // remove random units from the map
1891        while (TagUnitMap.size() > unMaxTargets - removed_utarget)
1892        {
1893            uint32 poz = urand(0, TagUnitMap.size()-1);
1894            for (std::list<Unit*>::iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end(); ++itr, --poz)
1895            {
1896                if (!*itr) continue;
1897                if (!poz)
1898                {
1899                    TagUnitMap.erase(itr);
1900                    break;
1901                }
1902            }
1903        }
1904        // the player's target will always be added to the map
1905        if (removed_utarget && m_targets.getUnitTarget())
1906            TagUnitMap.push_back(m_targets.getUnitTarget());
1907    }
1908}
1909
1910void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)
1911{
1912    m_targets = *targets;
1913
1914    m_spellState = SPELL_STATE_PREPARING;
1915
1916    m_castPositionX = m_caster->GetPositionX();
1917    m_castPositionY = m_caster->GetPositionY();
1918    m_castPositionZ = m_caster->GetPositionZ();
1919    m_castOrientation = m_caster->GetOrientation();
1920
1921    if(triggeredByAura)
1922        m_triggeredByAuraSpell  = triggeredByAura->GetSpellProto();
1923
1924    // create and add update event for this spell
1925    SpellEvent* Event = new SpellEvent(this);
1926    m_caster->m_Events.AddEvent(Event, m_caster->m_Events.CalculateTime(1));
1927
1928    //Prevent casting at cast another spell (ServerSide check)
1929    if(m_caster->IsNonMeleeSpellCasted(false, true) && m_cast_count)
1930    {
1931        SendCastResult(SPELL_FAILED_SPELL_IN_PROGRESS);
1932        finish(false);
1933        return;
1934    }
1935
1936    // Fill cost data
1937    m_powerCost = CalculatePowerCost();
1938
1939    uint8 result = CanCast(true);
1940    if(result != 0 && !IsAutoRepeat())                      //always cast autorepeat dummy for triggering
1941    {
1942        if(triggeredByAura)
1943        {
1944            SendChannelUpdate(0);
1945            triggeredByAura->SetAuraDuration(0);
1946        }
1947        SendCastResult(result);
1948        finish(false);
1949        return;
1950    }
1951
1952    // calculate cast time (calculated after first CanCast check to prevent charge counting for first CanCast fail)
1953    m_casttime = GetSpellCastTime(m_spellInfo, this);
1954
1955    // set timer base at cast time
1956    ReSetTimer();
1957
1958    // stealth must be removed at cast starting (at show channel bar)
1959    // skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
1960    if ( !m_IsTriggeredSpell && isSpellBreakStealth(m_spellInfo) )
1961    {
1962        m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
1963        m_caster->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
1964    }
1965
1966    if(m_IsTriggeredSpell)
1967        cast(true);
1968    else
1969    {
1970        m_caster->SetCurrentCastedSpell( this );
1971        m_selfContainer = &(m_caster->m_currentSpells[GetCurrentContainer()]);
1972        SendSpellStart();
1973    }
1974}
1975
1976void Spell::cancel()
1977{
1978    if(m_spellState == SPELL_STATE_FINISHED)
1979        return;
1980
1981    m_autoRepeat = false;
1982    switch (m_spellState)
1983    {
1984        case SPELL_STATE_PREPARING:
1985        case SPELL_STATE_DELAYED:
1986        {
1987            SendInterrupted(0);
1988            SendCastResult(SPELL_FAILED_INTERRUPTED);
1989        } break;
1990
1991        case SPELL_STATE_CASTING:
1992        {
1993            for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1994            {
1995                if( ihit->missCondition == SPELL_MISS_NONE )
1996                {
1997                    Unit* unit = m_caster->GetGUID()==(*ihit).targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
1998                    if( unit && unit->isAlive() )
1999                        unit->RemoveAurasDueToSpell(m_spellInfo->Id);
2000                }
2001            }
2002
2003            m_caster->RemoveAurasDueToSpell(m_spellInfo->Id);
2004            SendChannelUpdate(0);
2005            SendInterrupted(0);
2006            SendCastResult(SPELL_FAILED_INTERRUPTED);
2007        } break;
2008
2009        default:
2010        {
2011        } break;
2012    }
2013
2014    finish(false);
2015    m_caster->RemoveDynObject(m_spellInfo->Id);
2016    m_caster->RemoveGameObject(m_spellInfo->Id,true);
2017}
2018
2019void Spell::cast(bool skipCheck)
2020{
2021    uint8 castResult = 0;
2022
2023    // update pointers base at GUIDs to prevent access to non-existed already object
2024    UpdatePointers();
2025
2026    // cancel at lost main target unit
2027    if(!m_targets.getUnitTarget() && m_targets.getUnitTargetGUID() && m_targets.getUnitTargetGUID() != m_caster->GetGUID())
2028    {
2029        cancel();
2030        return;
2031    }
2032
2033    if(m_caster->GetTypeId() != TYPEID_PLAYER && m_targets.getUnitTarget() && m_targets.getUnitTarget() != m_caster)
2034        m_caster->SetInFront(m_targets.getUnitTarget());
2035
2036    castResult = CheckPower();
2037    if(castResult != 0)
2038    {
2039        SendCastResult(castResult);
2040        finish(false);
2041        return;
2042    }
2043
2044    // triggered cast called from Spell::prepare where it was already checked
2045    if(!skipCheck)
2046    {
2047        castResult = CanCast(false);
2048        if(castResult != 0)
2049        {
2050            SendCastResult(castResult);
2051            finish(false);
2052            return;
2053        }
2054    }
2055
2056    // Conflagrate - consumes immolate
2057    if ((m_spellInfo->TargetAuraState == AURA_STATE_IMMOLATE) && m_targets.getUnitTarget())
2058    {
2059        // for caster applied auras only
2060        Unit::AuraList const &mPeriodic = m_targets.getUnitTarget()->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
2061        for(Unit::AuraList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i)
2062        {
2063            if( (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && ((*i)->GetSpellProto()->SpellFamilyFlags & 4) &&
2064                (*i)->GetCasterGUID()==m_caster->GetGUID() )
2065            {
2066                m_targets.getUnitTarget()->RemoveAura((*i)->GetId(), (*i)->GetEffIndex());
2067                break;
2068            }
2069        }
2070    }
2071
2072    // traded items have trade slot instead of guid in m_itemTargetGUID
2073    // set to real guid to be sent later to the client
2074    m_targets.updateTradeSlotItem();
2075
2076    // CAST SPELL
2077    SendSpellCooldown();
2078
2079    TakePower();
2080    TakeReagents();                                         // we must remove reagents before HandleEffects to allow place crafted item in same slot
2081    FillTargetMap();
2082
2083    if(m_spellState == SPELL_STATE_FINISHED)                // stop cast if spell marked as finish somewhere in Take*/FillTargetMap
2084        return;
2085
2086    SendCastResult(castResult);
2087    SendSpellGo();                                          // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
2088
2089    // Pass cast spell event to handler (not send triggered by aura spells)
2090    if (m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED && !m_triggeredByAuraSpell)
2091    {
2092        m_caster->ProcDamageAndSpell(m_targets.getUnitTarget(), PROC_FLAG_CAST_SPELL, PROC_FLAG_NONE, 0, SPELL_SCHOOL_MASK_NONE, m_spellInfo, m_IsTriggeredSpell);
2093
2094        // update pointers base at GUIDs to prevent access to non-existed already object
2095        UpdatePointers();                                   // pointers can be invalidate at triggered spell casting
2096    }
2097
2098    // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
2099    if (m_spellInfo->speed > 0.0f)
2100    {
2101
2102        // Remove used for cast item if need (it can be already NULL after TakeReagents call
2103        // in case delayed spell remove item at cast delay start
2104        TakeCastItem();
2105
2106        // Okay, maps created, now prepare flags
2107        m_immediateHandled = false;
2108        m_spellState = SPELL_STATE_DELAYED;
2109        SetDelayStart(0);
2110    }
2111    else
2112    {
2113        // Immediate spell, no big deal
2114        handle_immediate();
2115    }
2116}
2117
2118void Spell::handle_immediate()
2119{
2120    // start channeling if applicable
2121    if(IsChanneledSpell(m_spellInfo))
2122    {
2123        m_spellState = SPELL_STATE_CASTING;
2124        SendChannelStart(GetSpellDuration(m_spellInfo));
2125    }
2126
2127    // process immediate effects (items, ground, etc.) also initialize some variables
2128    _handle_immediate_phase();
2129
2130    for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
2131        DoAllEffectOnTarget(&(*ihit));
2132
2133    for(std::list<GOTargetInfo>::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit)
2134        DoAllEffectOnTarget(&(*ihit));
2135
2136    // spell is finished, perform some last features of the spell here
2137    _handle_finish_phase();
2138
2139    // Remove used for cast item if need (it can be already NULL after TakeReagents call
2140    TakeCastItem();
2141
2142    if(m_spellState != SPELL_STATE_CASTING)
2143        finish(true);                                       // successfully finish spell cast (not last in case autorepeat or channel spell)
2144}
2145
2146uint64 Spell::handle_delayed(uint64 t_offset)
2147{
2148    uint64 next_time = 0;
2149
2150    if (!m_immediateHandled)
2151    {
2152        _handle_immediate_phase();
2153        m_immediateHandled = true;
2154    }
2155
2156    // now recheck units targeting correctness (need before any effects apply to prevent adding immunity at first effect not allow apply second spell effect and similar cases)
2157    for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end();++ihit)
2158    {
2159        if (ihit->processed == false)
2160        {
2161            if ( ihit->timeDelay <= t_offset )
2162                DoAllEffectOnTarget(&(*ihit));
2163            else if( next_time == 0 || ihit->timeDelay < next_time )
2164                next_time = ihit->timeDelay;
2165        }
2166    }
2167
2168    // now recheck gameobject targeting correctness
2169    for(std::list<GOTargetInfo>::iterator ighit= m_UniqueGOTargetInfo.begin(); ighit != m_UniqueGOTargetInfo.end();++ighit)
2170    {
2171        if (ighit->processed == false)
2172        {
2173            if ( ighit->timeDelay <= t_offset )
2174                DoAllEffectOnTarget(&(*ighit));
2175            else if( next_time == 0 || ighit->timeDelay < next_time )
2176                next_time = ighit->timeDelay;
2177        }
2178    }
2179    // All targets passed - need finish phase
2180    if (next_time == 0)
2181    {
2182        // spell is finished, perform some last features of the spell here
2183        _handle_finish_phase();
2184
2185        finish(true);                                       // successfully finish spell cast
2186
2187        // return zero, spell is finished now
2188        return 0;
2189    }
2190    else
2191    {
2192        // spell is unfinished, return next execution time
2193        return next_time;
2194    }
2195}
2196
2197void Spell::_handle_immediate_phase()
2198{
2199    // handle some immediate features of the spell here
2200    HandleThreatSpells(m_spellInfo->Id);
2201
2202    m_needSpellLog = IsNeedSendToClient();
2203    for(uint32 j = 0;j<3;j++)
2204    {
2205        if(m_spellInfo->Effect[j]==0)
2206            continue;
2207
2208        // apply Send Event effect to ground in case empty target lists
2209        if( m_spellInfo->Effect[j] == SPELL_EFFECT_SEND_EVENT && !HaveTargetsForEffect(j) )
2210        {
2211            HandleEffects(NULL,NULL,NULL, j);
2212            continue;
2213        }
2214
2215        // Don't do spell log, if is school damage spell
2216        if(m_spellInfo->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE || m_spellInfo->Effect[j] == 0)
2217            m_needSpellLog = false;
2218
2219        uint32 EffectChainTarget = m_spellInfo->EffectChainTarget[j];
2220        if(m_originalCaster)
2221            if(Player* modOwner = m_originalCaster->GetSpellModOwner())
2222                modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, EffectChainTarget, this);
2223
2224        // initialize multipliers
2225        m_damageMultipliers[j] = 1.0f;
2226        if( (m_spellInfo->EffectImplicitTargetA[j] == TARGET_CHAIN_DAMAGE || m_spellInfo->EffectImplicitTargetA[j] == TARGET_CHAIN_HEAL) &&
2227            (EffectChainTarget > 1) )
2228            m_applyMultiplierMask |= 1 << j;
2229    }
2230
2231    // initialize Diminishing Returns Data
2232    m_diminishLevel = DIMINISHING_LEVEL_1;
2233    m_diminishGroup = DIMINISHING_NONE;
2234
2235    // process items
2236    for(std::list<ItemTargetInfo>::iterator ihit= m_UniqueItemInfo.begin();ihit != m_UniqueItemInfo.end();++ihit)
2237        DoAllEffectOnTarget(&(*ihit));
2238
2239    // process ground
2240    for(uint32 j = 0;j<3;j++)
2241    {
2242        // persistent area auras target only the ground
2243        if(m_spellInfo->Effect[j] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
2244            HandleEffects(NULL,NULL,NULL, j);
2245    }
2246}
2247
2248void Spell::_handle_finish_phase()
2249{
2250    // spell log
2251    if(m_needSpellLog)
2252        SendLogExecute();
2253}
2254
2255void Spell::SendSpellCooldown()
2256{
2257    if(m_caster->GetTypeId() != TYPEID_PLAYER)
2258        return;
2259
2260    Player* _player = (Player*)m_caster;
2261    // Add cooldown for max (disable spell)
2262    // Cooldown started on SendCooldownEvent call
2263    if (m_spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
2264    {
2265        _player->AddSpellCooldown(m_spellInfo->Id, 0, time(NULL) - 1);
2266        return;
2267    }
2268
2269    // init cooldown values
2270    uint32 cat   = 0;
2271    int32 rec    = -1;
2272    int32 catrec = -1;
2273
2274    // some special item spells without correct cooldown in SpellInfo
2275    // cooldown information stored in item prototype
2276    // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client.
2277
2278    if(m_CastItem)
2279    {
2280        ItemPrototype const* proto = m_CastItem->GetProto();
2281        if(proto)
2282        {
2283            for(int idx = 0; idx < 5; ++idx)
2284            {
2285                if(proto->Spells[idx].SpellId == m_spellInfo->Id)
2286                {
2287                    cat    = proto->Spells[idx].SpellCategory;
2288                    rec    = proto->Spells[idx].SpellCooldown;
2289                    catrec = proto->Spells[idx].SpellCategoryCooldown;
2290                    break;
2291                }
2292            }
2293        }
2294    }
2295
2296    // if no cooldown found above then base at DBC data
2297    if(rec < 0 && catrec < 0)
2298    {
2299        cat = m_spellInfo->Category;
2300        rec = m_spellInfo->RecoveryTime;
2301        catrec = m_spellInfo->CategoryRecoveryTime;
2302    }
2303
2304    // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
2305    // prevent 0 cooldowns set by another way
2306    if (rec <= 0 && catrec <= 0 && (cat == 76 || cat == 351))
2307        rec = _player->GetAttackTime(RANGED_ATTACK);
2308
2309    // Now we have cooldown data (if found any), time to apply mods
2310    if(rec > 0)
2311        _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, rec, this);
2312
2313    if(catrec > 0)
2314        _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, catrec, this);
2315
2316    // replace negative cooldowns by 0
2317    if (rec < 0) rec = 0;
2318    if (catrec < 0) catrec = 0;
2319
2320    // no cooldown after applying spell mods
2321    if( rec == 0 && catrec == 0)
2322        return;
2323
2324    time_t curTime = time(NULL);
2325
2326    time_t catrecTime = catrec ? curTime+catrec/1000 : 0;   // in secs
2327    time_t recTime    = rec ? curTime+rec/1000 : catrecTime;// in secs
2328
2329    // self spell cooldown
2330    if(recTime > 0)
2331        _player->AddSpellCooldown(m_spellInfo->Id, m_CastItem ? m_CastItem->GetEntry() : 0, recTime);
2332
2333    // category spells
2334    if (catrec > 0)
2335    {
2336        SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat);
2337        if(i_scstore != sSpellCategoryStore.end())
2338        {
2339            for(SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
2340            {
2341                if(*i_scset == m_spellInfo->Id)             // skip main spell, already handled above
2342                    continue;
2343
2344                _player->AddSpellCooldown(m_spellInfo->Id, m_CastItem ? m_CastItem->GetEntry() : 0, catrecTime);
2345            }
2346        }
2347    }
2348}
2349
2350void Spell::update(uint32 difftime)
2351{
2352    // update pointers based at it's GUIDs
2353    UpdatePointers();
2354
2355    if(m_targets.getUnitTargetGUID() && !m_targets.getUnitTarget())
2356    {
2357        cancel();
2358        return;
2359    }
2360
2361    // check if the player caster has moved before the spell finished
2362    if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) &&
2363        (m_castPositionX != m_caster->GetPositionX() || m_castPositionY != m_caster->GetPositionY() || m_castPositionZ != m_caster->GetPositionZ()) &&
2364        (m_spellInfo->Effect[0] != SPELL_EFFECT_STUCK || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING)))
2365    {
2366        // always cancel for channeled spells
2367        if( m_spellState == SPELL_STATE_CASTING )
2368            cancel();
2369        // don't cancel for melee, autorepeat, triggered and instant spells
2370        else if(!IsNextMeleeSwingSpell() && !IsAutoRepeat() && !m_IsTriggeredSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT))
2371            cancel();
2372    }
2373
2374    switch(m_spellState)
2375    {
2376        case SPELL_STATE_PREPARING:
2377        {
2378            if(m_timer)
2379            {
2380                if(difftime >= m_timer)
2381                    m_timer = 0;
2382                else
2383                    m_timer -= difftime;
2384            }
2385
2386            if(m_timer == 0 && !IsNextMeleeSwingSpell() && !IsAutoRepeat())
2387                cast();
2388        } break;
2389        case SPELL_STATE_CASTING:
2390        {
2391            if(m_timer > 0)
2392            {
2393                if( m_caster->GetTypeId() == TYPEID_PLAYER )
2394                {
2395                    // check if player has jumped before the channeling finished
2396                    if(m_caster->HasUnitMovementFlag(MOVEMENTFLAG_JUMPING))
2397                        cancel();
2398
2399                    // check for incapacitating player states
2400                    if( m_caster->hasUnitState(UNIT_STAT_STUNDED | UNIT_STAT_CONFUSED))
2401                        cancel();
2402
2403                    // check if player has turned if flag is set
2404                    if( m_spellInfo->ChannelInterruptFlags & CHANNEL_FLAG_TURNING && m_castOrientation != m_caster->GetOrientation() )
2405                        cancel();
2406                }
2407
2408                // check if there are alive targets left
2409                if (!IsAliveUnitPresentInTargetList())
2410                {
2411                    SendChannelUpdate(0);
2412                    finish();
2413                }
2414
2415                if(difftime >= m_timer)
2416                    m_timer = 0;
2417                else
2418                    m_timer -= difftime;
2419            }
2420
2421            if(m_timer == 0)
2422            {
2423                SendChannelUpdate(0);
2424
2425                // channeled spell processed independently for quest targeting
2426                // cast at creature (or GO) quest objectives update at successful cast channel finished
2427                // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... )
2428                if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() )
2429                {
2430                    for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
2431                    {
2432                        TargetInfo* target = &*ihit;
2433                        if(!IS_CREATURE_GUID(target->targetGUID))
2434                            continue;
2435
2436                        Unit* unit = m_caster->GetGUID()==target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster,target->targetGUID);
2437                        if (unit==NULL)
2438                            continue;
2439
2440                        ((Player*)m_caster)->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id);
2441                    }
2442
2443                    for(std::list<GOTargetInfo>::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit)
2444                    {
2445                        GOTargetInfo* target = &*ihit;
2446
2447                        GameObject* go = ObjectAccessor::GetGameObject(*m_caster, target->targetGUID);
2448                        if(!go)
2449                            continue;
2450
2451                        ((Player*)m_caster)->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id);
2452                    }
2453                }
2454
2455                finish();
2456            }
2457        } break;
2458        default:
2459        {
2460        }break;
2461    }
2462}
2463
2464void Spell::finish(bool ok)
2465{
2466    if(!m_caster)
2467        return;
2468
2469    if(m_spellState == SPELL_STATE_FINISHED)
2470        return;
2471
2472    m_spellState = SPELL_STATE_FINISHED;
2473
2474    //remove spell mods
2475    if (m_caster->GetTypeId() == TYPEID_PLAYER)
2476        ((Player*)m_caster)->RemoveSpellMods(this);
2477
2478    // other code related only to successfully finished spells
2479    if(!ok)
2480        return;
2481
2482    //handle SPELL_AURA_ADD_TARGET_TRIGGER auras
2483    Unit::AuraList const& targetTriggers = m_caster->GetAurasByType(SPELL_AURA_ADD_TARGET_TRIGGER);
2484    for(Unit::AuraList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i)
2485    {
2486        SpellEntry const *auraSpellInfo = (*i)->GetSpellProto();
2487        uint32 auraSpellIdx = (*i)->GetEffIndex();
2488        if (IsAffectedBy(auraSpellInfo, auraSpellIdx))
2489        {
2490            for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
2491                if( ihit->effectMask & (1<<auraSpellIdx) )
2492            {
2493                // check m_caster->GetGUID() let load auras at login and speedup most often case
2494                Unit *unit = m_caster->GetGUID()== ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
2495                if (unit && unit->isAlive())
2496                {
2497                    // Calculate chance at that moment (can be depend for example from combo points)
2498                    int32 chance = m_caster->CalculateSpellDamage(auraSpellInfo, auraSpellIdx, (*i)->GetBasePoints(),unit);
2499
2500                    if(roll_chance_i(chance))
2501                        m_caster->CastSpell(unit, auraSpellInfo->EffectTriggerSpell[auraSpellIdx], true, NULL, (*i));
2502                }
2503            }
2504        }
2505    }
2506
2507    if (IsMeleeAttackResetSpell())
2508    {
2509        m_caster->resetAttackTimer(BASE_ATTACK);
2510        if(m_caster->haveOffhandWeapon())
2511            m_caster->resetAttackTimer(OFF_ATTACK);
2512    }
2513
2514    /*if (IsRangedAttackResetSpell())
2515        m_caster->resetAttackTimer(RANGED_ATTACK);*/
2516
2517    // Clear combo at finish state
2518    if(m_caster->GetTypeId() == TYPEID_PLAYER && NeedsComboPoints(m_spellInfo))
2519        ((Player*)m_caster)->ClearComboPoints();
2520
2521    // call triggered spell only at successful cast (after clear combo points -> for add some if need)
2522    if(!m_TriggerSpells.empty())
2523        TriggerSpell();
2524
2525    // Stop Attack for some spells
2526    if( m_spellInfo->Attributes & SPELL_ATTR_STOP_ATTACK_TARGET )
2527        m_caster->AttackStop();
2528}
2529
2530void Spell::SendCastResult(uint8 result)
2531{
2532    if (m_caster->GetTypeId() != TYPEID_PLAYER)
2533        return;
2534
2535    if(((Player*)m_caster)->GetSession()->PlayerLoading())  // don't send cast results at loading time
2536        return;
2537
2538    if(result != 0)
2539    {
2540        WorldPacket data(SMSG_CAST_FAILED, (4+1+1));
2541        data << uint32(m_spellInfo->Id);
2542        data << uint8(result);                              // problem
2543        data << uint8(m_cast_count);                        // single cast or multi 2.3 (0/1)
2544        switch (result)
2545        {
2546            case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
2547                data << uint32(m_spellInfo->RequiresSpellFocus);
2548                break;
2549            case SPELL_FAILED_REQUIRES_AREA:
2550                // hardcode areas limitation case
2551                if( m_spellInfo->Id==41618 || m_spellInfo->Id==41620 )
2552                    data << uint32(3842);
2553                else if( m_spellInfo->Id==41617 || m_spellInfo->Id==41619 )
2554                    data << uint32(3905);
2555                // normal case
2556                else
2557                    data << uint32(m_spellInfo->AreaId);
2558                break;
2559            case SPELL_FAILED_TOTEMS:
2560                if(m_spellInfo->Totem[0])
2561                    data << uint32(m_spellInfo->Totem[0]);
2562                if(m_spellInfo->Totem[1])
2563                    data << uint32(m_spellInfo->Totem[1]);
2564                break;
2565            case SPELL_FAILED_TOTEM_CATEGORY:
2566                if(m_spellInfo->TotemCategory[0])
2567                    data << uint32(m_spellInfo->TotemCategory[0]);
2568                if(m_spellInfo->TotemCategory[1])
2569                    data << uint32(m_spellInfo->TotemCategory[1]);
2570                break;
2571            case SPELL_FAILED_EQUIPPED_ITEM_CLASS:
2572                data << uint32(m_spellInfo->EquippedItemClass);
2573                data << uint32(m_spellInfo->EquippedItemSubClassMask);
2574                data << uint32(m_spellInfo->EquippedItemInventoryTypeMask);
2575                break;
2576        }
2577        ((Player*)m_caster)->GetSession()->SendPacket(&data);
2578    }
2579    else
2580    {
2581        WorldPacket data(SMSG_CLEAR_EXTRA_AURA_INFO, (8+4));
2582        data.append(m_caster->GetPackGUID());
2583        data << uint32(m_spellInfo->Id);
2584        ((Player*)m_caster)->GetSession()->SendPacket(&data);
2585    }
2586}
2587
2588void Spell::SendSpellStart()
2589{
2590    if(!IsNeedSendToClient())
2591        return;
2592
2593    sLog.outDebug("Sending SMSG_SPELL_START id=%u",m_spellInfo->Id);
2594
2595    uint16 castFlags = CAST_FLAG_UNKNOWN1;
2596    if(IsRangedSpell())
2597        castFlags |= CAST_FLAG_AMMO;
2598
2599    Unit * target;
2600    if(!m_targets.getUnitTarget())
2601        target = m_caster;
2602    else
2603        target = m_targets.getUnitTarget();
2604
2605    WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2));
2606    if(m_CastItem)
2607        data.append(m_CastItem->GetPackGUID());
2608    else
2609        data.append(m_caster->GetPackGUID());
2610
2611    data.append(m_caster->GetPackGUID());
2612    data << uint32(m_spellInfo->Id);
2613    data << uint8(m_cast_count);                            // single cast or multi 2.3 (0/1)
2614    data << uint16(castFlags);
2615    data << uint32(m_timer);
2616
2617    m_targets.write(&data);
2618
2619    if( castFlags & CAST_FLAG_AMMO )
2620        WriteAmmoToPacket(&data);
2621
2622    m_caster->SendMessageToSet(&data, true);
2623}
2624
2625void Spell::SendSpellGo()
2626{
2627    // not send invisible spell casting
2628    if(!IsNeedSendToClient())
2629        return;
2630
2631    sLog.outDebug("Sending SMSG_SPELL_GO id=%u",m_spellInfo->Id);
2632
2633    Unit * target;
2634    if(!m_targets.getUnitTarget())
2635        target = m_caster;
2636    else
2637        target = m_targets.getUnitTarget();
2638
2639    uint16 castFlags = CAST_FLAG_UNKNOWN3;
2640    if(IsRangedSpell())
2641        castFlags |= CAST_FLAG_AMMO;
2642
2643    WorldPacket data(SMSG_SPELL_GO, 50);                    // guess size
2644    if(m_CastItem)
2645        data.append(m_CastItem->GetPackGUID());
2646    else
2647        data.append(m_caster->GetPackGUID());
2648
2649    data.append(m_caster->GetPackGUID());
2650    data << uint32(m_spellInfo->Id);
2651    data << uint16(castFlags);
2652    data << uint32(getMSTime());                            // timestamp
2653
2654    WriteSpellGoTargets(&data);
2655
2656    m_targets.write(&data);
2657
2658    if( castFlags & CAST_FLAG_AMMO )
2659        WriteAmmoToPacket(&data);
2660
2661    m_caster->SendMessageToSet(&data, true);
2662}
2663
2664void Spell::WriteAmmoToPacket( WorldPacket * data )
2665{
2666    uint32 ammoInventoryType = 0;
2667    uint32 ammoDisplayID = 0;
2668
2669    if (m_caster->GetTypeId() == TYPEID_PLAYER)
2670    {
2671        Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
2672        if(pItem)
2673        {
2674            ammoInventoryType = pItem->GetProto()->InventoryType;
2675            if( ammoInventoryType == INVTYPE_THROWN )
2676                ammoDisplayID = pItem->GetProto()->DisplayInfoID;
2677            else
2678            {
2679                uint32 ammoID = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID);
2680                if(ammoID)
2681                {
2682                    ItemPrototype const *pProto = objmgr.GetItemPrototype( ammoID );
2683                    if(pProto)
2684                    {
2685                        ammoDisplayID = pProto->DisplayInfoID;
2686                        ammoInventoryType = pProto->InventoryType;
2687                    }
2688                }
2689                else if(m_caster->GetDummyAura(46699))      // Requires No Ammo
2690                {
2691                    ammoDisplayID = 5996;                   // normal arrow
2692                    ammoInventoryType = INVTYPE_AMMO;
2693                }
2694            }
2695        }
2696    }
2697    // TODO: implement selection ammo data based at ranged weapon stored in equipmodel/equipinfo/equipslot fields
2698
2699    *data << uint32(ammoDisplayID);
2700    *data << uint32(ammoInventoryType);
2701}
2702
2703void Spell::WriteSpellGoTargets( WorldPacket * data )
2704{
2705    *data << (uint8)m_countOfHit;
2706    for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
2707        if ((*ihit).missCondition == SPELL_MISS_NONE)       // Add only hits
2708            *data << uint64(ihit->targetGUID);
2709
2710    for(std::list<GOTargetInfo>::iterator ighit= m_UniqueGOTargetInfo.begin();ighit != m_UniqueGOTargetInfo.end();++ighit)
2711        *data << uint64(ighit->targetGUID);                 // Always hits
2712
2713    *data << (uint8)m_countOfMiss;
2714    for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
2715    {
2716        if( ihit->missCondition != SPELL_MISS_NONE )        // Add only miss
2717        {
2718            *data << uint64(ihit->targetGUID);
2719            *data << uint8(ihit->missCondition);
2720            if( ihit->missCondition == SPELL_MISS_REFLECT )
2721                *data << uint8(ihit->reflectResult);
2722        }
2723    }
2724}
2725
2726void Spell::SendLogExecute()
2727{
2728    Unit *target = m_targets.getUnitTarget() ? m_targets.getUnitTarget() : m_caster;
2729
2730    WorldPacket data(SMSG_SPELLLOGEXECUTE, (8+4+4+4+4+8));
2731
2732    if(m_caster->GetTypeId() == TYPEID_PLAYER)
2733        data.append(m_caster->GetPackGUID());
2734    else
2735        data.append(target->GetPackGUID());
2736
2737    data << uint32(m_spellInfo->Id);
2738    uint32 count1 = 1;
2739    data << uint32(count1);                                 // count1 (effect count?)
2740    for(uint32 i = 0; i < count1; ++i)
2741    {
2742        data << uint32(m_spellInfo->Effect[0]);             // spell effect?
2743        uint32 count2 = 1;
2744        data << uint32(count2);                             // count2 (target count?)
2745        for(uint32 j = 0; j < count2; ++j)
2746        {
2747            switch(m_spellInfo->Effect[0])
2748            {
2749                case SPELL_EFFECT_POWER_DRAIN:
2750                    if(Unit *unit = m_targets.getUnitTarget())
2751                        data.append(unit->GetPackGUID());
2752                    else
2753                        data << uint8(0);
2754                    data << uint32(0);
2755                    data << uint32(0);
2756                    data << float(0);
2757                    break;
2758                case SPELL_EFFECT_ADD_EXTRA_ATTACKS:
2759                    if(Unit *unit = m_targets.getUnitTarget())
2760                        data.append(unit->GetPackGUID());
2761                    else
2762                        data << uint8(0);
2763                    data << uint32(0);                      // count?
2764                    break;
2765                case SPELL_EFFECT_INTERRUPT_CAST:
2766                    if(Unit *unit = m_targets.getUnitTarget())
2767                        data.append(unit->GetPackGUID());
2768                    else
2769                        data << uint8(0);
2770                    data << uint32(0);                      // spellid
2771                    break;
2772                case SPELL_EFFECT_DURABILITY_DAMAGE:
2773                    if(Unit *unit = m_targets.getUnitTarget())
2774                        data.append(unit->GetPackGUID());
2775                    else
2776                        data << uint8(0);
2777                    data << uint32(0);
2778                    data << uint32(0);
2779                    break;
2780                case SPELL_EFFECT_OPEN_LOCK:
2781                case SPELL_EFFECT_OPEN_LOCK_ITEM:
2782                    if(Item *item = m_targets.getItemTarget())
2783                        data.append(item->GetPackGUID());
2784                    else
2785                        data << uint8(0);
2786                    break;
2787                case SPELL_EFFECT_CREATE_ITEM:
2788                    data << uint32(m_spellInfo->EffectItemType[0]);
2789                    break;
2790                case SPELL_EFFECT_SUMMON:
2791                case SPELL_EFFECT_SUMMON_WILD:
2792                case SPELL_EFFECT_SUMMON_GUARDIAN:
2793                case SPELL_EFFECT_TRANS_DOOR:
2794                case SPELL_EFFECT_SUMMON_PET:
2795                case SPELL_EFFECT_SUMMON_POSSESSED:
2796                case SPELL_EFFECT_SUMMON_TOTEM:
2797                case SPELL_EFFECT_SUMMON_OBJECT_WILD:
2798                case SPELL_EFFECT_CREATE_HOUSE:
2799                case SPELL_EFFECT_DUEL:
2800                case SPELL_EFFECT_SUMMON_TOTEM_SLOT1:
2801                case SPELL_EFFECT_SUMMON_TOTEM_SLOT2:
2802                case SPELL_EFFECT_SUMMON_TOTEM_SLOT3:
2803                case SPELL_EFFECT_SUMMON_TOTEM_SLOT4:
2804                case SPELL_EFFECT_SUMMON_PHANTASM:
2805                case SPELL_EFFECT_SUMMON_CRITTER:
2806                case SPELL_EFFECT_SUMMON_OBJECT_SLOT1:
2807                case SPELL_EFFECT_SUMMON_OBJECT_SLOT2:
2808                case SPELL_EFFECT_SUMMON_OBJECT_SLOT3:
2809                case SPELL_EFFECT_SUMMON_OBJECT_SLOT4:
2810                case SPELL_EFFECT_SUMMON_DEMON:
2811                case SPELL_EFFECT_150:
2812                    if(Unit *unit = m_targets.getUnitTarget())
2813                        data.append(unit->GetPackGUID());
2814                    else if(m_targets.getItemTargetGUID())
2815                        data.appendPackGUID(m_targets.getItemTargetGUID());
2816                    else if(GameObject *go = m_targets.getGOTarget())
2817                        data.append(go->GetPackGUID());
2818                    else
2819                        data << uint8(0);                   // guid
2820                    break;
2821                case SPELL_EFFECT_FEED_PET:
2822                    data << uint32(m_targets.getItemTargetEntry());
2823                    break;
2824                case SPELL_EFFECT_DISMISS_PET:
2825                    if(Unit *unit = m_targets.getUnitTarget())
2826                        data.append(unit->GetPackGUID());
2827                    else
2828                        data << uint8(0);
2829                    break;
2830                default:
2831                    return;
2832            }
2833        }
2834    }
2835
2836    m_caster->SendMessageToSet(&data, true);
2837}
2838
2839void Spell::SendInterrupted(uint8 result)
2840{
2841    WorldPacket data(SMSG_SPELL_FAILURE, (8+4+1));
2842    data.append(m_caster->GetPackGUID());
2843    data << m_spellInfo->Id;
2844    data << result;
2845    m_caster->SendMessageToSet(&data, true);
2846
2847    data.Initialize(SMSG_SPELL_FAILED_OTHER, (8+4));
2848    data.append(m_caster->GetPackGUID());
2849    data << m_spellInfo->Id;
2850    m_caster->SendMessageToSet(&data, true);
2851}
2852
2853void Spell::SendChannelUpdate(uint32 time)
2854{
2855    if(time == 0)
2856    {
2857        m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,0);
2858        m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL,0);
2859    }
2860
2861    if (m_caster->GetTypeId() != TYPEID_PLAYER)
2862        return;
2863
2864    WorldPacket data( MSG_CHANNEL_UPDATE, 8+4 );
2865    data.append(m_caster->GetPackGUID());
2866    data << time;
2867
2868    ((Player*)m_caster)->GetSession()->SendPacket( &data );
2869}
2870
2871void Spell::SendChannelStart(uint32 duration)
2872{
2873    WorldObject* target = NULL;
2874
2875    // select first not rsusted target from target list for _0_ effect
2876    if(!m_UniqueTargetInfo.empty())
2877    {
2878        for(std::list<TargetInfo>::iterator itr= m_UniqueTargetInfo.begin();itr != m_UniqueTargetInfo.end();++itr)
2879        {
2880            if( (itr->effectMask & (1<<0)) && itr->reflectResult==SPELL_MISS_NONE && itr->targetGUID != m_caster->GetGUID())
2881            {
2882                target = ObjectAccessor::GetUnit(*m_caster, itr->targetGUID);
2883                break;
2884            }
2885        }
2886    }
2887    else if(!m_UniqueGOTargetInfo.empty())
2888    {
2889        for(std::list<GOTargetInfo>::iterator itr= m_UniqueGOTargetInfo.begin();itr != m_UniqueGOTargetInfo.end();++itr)
2890        {
2891            if(itr->effectMask & (1<<0) )
2892            {
2893                target = ObjectAccessor::GetGameObject(*m_caster, itr->targetGUID);
2894                break;
2895            }
2896        }
2897    }
2898
2899    if (m_caster->GetTypeId() == TYPEID_PLAYER)
2900    {
2901        WorldPacket data( MSG_CHANNEL_START, (8+4+4) );
2902        data.append(m_caster->GetPackGUID());
2903        data << m_spellInfo->Id;
2904        data << duration;
2905
2906        ((Player*)m_caster)->GetSession()->SendPacket( &data );
2907    }
2908
2909    m_timer = duration;
2910    if(target)
2911        m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, target->GetGUID());
2912    m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL, m_spellInfo->Id);
2913}
2914
2915void Spell::SendResurrectRequest(Player* target)
2916{
2917    WorldPacket data(SMSG_RESURRECT_REQUEST, (8+4+2+4));
2918    data << m_caster->GetGUID();
2919    data << uint32(1) << uint16(0) << uint32(1);
2920
2921    target->GetSession()->SendPacket(&data);
2922}
2923
2924void Spell::SendPlaySpellVisual(uint32 SpellID)
2925{
2926    if (m_caster->GetTypeId() != TYPEID_PLAYER)
2927        return;
2928
2929    WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12);
2930    data << m_caster->GetGUID();
2931    data << SpellID;
2932    ((Player*)m_caster)->GetSession()->SendPacket(&data);
2933}
2934
2935void Spell::TakeCastItem()
2936{
2937    if(!m_CastItem || m_caster->GetTypeId() != TYPEID_PLAYER)
2938        return;
2939
2940    // not remove cast item at triggered spell (equipping, weapon damage, etc)
2941    if(m_IsTriggeredSpell)
2942        return;
2943
2944    ItemPrototype const *proto = m_CastItem->GetProto();
2945
2946    if(!proto)
2947    {
2948        // This code is to avoid a crash
2949        // I'm not sure, if this is really an error, but I guess every item needs a prototype
2950        sLog.outError("Cast item has no item prototype highId=%d, lowId=%d",m_CastItem->GetGUIDHigh(), m_CastItem->GetGUIDLow());
2951        return;
2952    }
2953
2954    bool expendable = false;
2955    bool withoutCharges = false;
2956
2957    for (int i = 0; i<5; i++)
2958    {
2959        if (proto->Spells[i].SpellId)
2960        {
2961            // item has limited charges
2962            if (proto->Spells[i].SpellCharges)
2963            {
2964                if (proto->Spells[i].SpellCharges < 0)
2965                    expendable = true;
2966
2967                int32 charges = m_CastItem->GetSpellCharges(i);
2968
2969                // item has charges left
2970                if (charges)
2971                {
2972                    (charges > 0) ? --charges : ++charges;  // abs(charges) less at 1 after use
2973                    if (proto->Stackable < 2)
2974                        m_CastItem->SetSpellCharges(i, charges);
2975                    m_CastItem->SetState(ITEM_CHANGED, (Player*)m_caster);
2976                }
2977
2978                // all charges used
2979                withoutCharges = (charges == 0);
2980            }
2981        }
2982    }
2983
2984    if (expendable && withoutCharges)
2985    {
2986        uint32 count = 1;
2987        ((Player*)m_caster)->DestroyItemCount(m_CastItem, count, true);
2988
2989        // prevent crash at access to deleted m_targets.getItemTarget
2990        if(m_CastItem==m_targets.getItemTarget())
2991            m_targets.setItemTarget(NULL);
2992
2993        m_CastItem = NULL;
2994    }
2995}
2996
2997void Spell::TakePower()
2998{
2999    if(m_CastItem || m_triggeredByAuraSpell)
3000        return;
3001
3002    // health as power used
3003    if(m_spellInfo->powerType == POWER_HEALTH)
3004    {
3005        m_caster->ModifyHealth( -(int32)m_powerCost );
3006        return;
3007    }
3008
3009    if(m_spellInfo->powerType >= MAX_POWERS)
3010    {
3011        sLog.outError("Spell::TakePower: Unknown power type '%d'", m_spellInfo->powerType);
3012        return;
3013    }
3014
3015    Powers powerType = Powers(m_spellInfo->powerType);
3016
3017    m_caster->ModifyPower(powerType, -(int32)m_powerCost);
3018
3019    // Set the five second timer
3020    if (powerType == POWER_MANA && m_powerCost > 0)
3021        m_caster->SetLastManaUse(getMSTime());
3022}
3023
3024void Spell::TakeReagents()
3025{
3026    if(m_IsTriggeredSpell)                                  // reagents used in triggered spell removed by original spell or don't must be removed.
3027        return;
3028
3029    if (m_caster->GetTypeId() != TYPEID_PLAYER)
3030        return;
3031
3032    if (m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP &&
3033        m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION))
3034        return;
3035
3036    Player* p_caster = (Player*)m_caster;
3037
3038    for(uint32 x=0;x<8;x++)
3039    {
3040        if(m_spellInfo->Reagent[x] <= 0)
3041            continue;
3042
3043        uint32 itemid = m_spellInfo->Reagent[x];
3044        uint32 itemcount = m_spellInfo->ReagentCount[x];
3045
3046        // if CastItem is also spell reagent
3047        if (m_CastItem)
3048        {
3049            ItemPrototype const *proto = m_CastItem->GetProto();
3050            if( proto && proto->ItemId == itemid )
3051            {
3052                for(int s=0;s<5;s++)
3053                {
3054                    // CastItem will be used up and does not count as reagent
3055                    int32 charges = m_CastItem->GetSpellCharges(s);
3056                    if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2)
3057                    {
3058                        ++itemcount;
3059                        break;
3060                    }
3061                }
3062
3063                m_CastItem = NULL;
3064            }
3065        }
3066
3067        // if getItemTarget is also spell reagent
3068        if (m_targets.getItemTargetEntry()==itemid)
3069            m_targets.setItemTarget(NULL);
3070
3071        p_caster->DestroyItemCount(itemid, itemcount, true);
3072    }
3073}
3074
3075void Spell::HandleThreatSpells(uint32 spellId)
3076{
3077    if(!m_targets.getUnitTarget() || !spellId)
3078        return;
3079
3080    if(!m_targets.getUnitTarget()->CanHaveThreatList())
3081        return;
3082
3083    SpellThreatEntry const *threatSpell = sSpellThreatStore.LookupEntry<SpellThreatEntry>(spellId);
3084    if(!threatSpell)
3085        return;
3086
3087    m_targets.getUnitTarget()->AddThreat(m_caster, float(threatSpell->threat));
3088
3089    DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threatSpell->threat);
3090}
3091
3092void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i, float DamageMultiplier)
3093{
3094    unitTarget = pUnitTarget;
3095    itemTarget = pItemTarget;
3096    gameObjTarget = pGOTarget;
3097
3098    uint8 eff = m_spellInfo->Effect[i];
3099    uint32 mechanic = m_spellInfo->EffectMechanic[i];
3100
3101    damage = int32(CalculateDamage((uint8)i,unitTarget)*DamageMultiplier);
3102
3103    sLog.outDebug( "Spell: Effect : %u", eff);
3104
3105    //Simply return. Do not display "immune" in red text on client
3106    if(unitTarget && unitTarget->IsImmunedToSpellEffect(eff, mechanic))
3107        return;
3108
3109    if(eff<TOTAL_SPELL_EFFECTS)
3110    {
3111        //sLog.outDebug( "WORLD: Spell FX %d < TOTAL_SPELL_EFFECTS ", eff);
3112        (*this.*SpellEffects[eff])(i);
3113    }
3114    /*
3115    else
3116    {
3117        sLog.outDebug( "WORLD: Spell FX %d > TOTAL_SPELL_EFFECTS ", eff);
3118        if (m_CastItem)
3119            EffectEnchantItemTmp(i);
3120        else
3121        {
3122            sLog.outError("SPELL: unknown effect %u spell id %u\n",
3123                eff, m_spellInfo->Id);
3124        }
3125    }
3126    */
3127}
3128
3129void Spell::TriggerSpell()
3130{
3131    for(TriggerSpells::iterator si=m_TriggerSpells.begin(); si!=m_TriggerSpells.end(); ++si)
3132    {
3133        Spell* spell = new Spell(m_caster, (*si), true, m_originalCasterGUID, this->m_selfContainer);
3134        spell->prepare(&m_targets);                         // use original spell original targets
3135    }
3136}
3137
3138uint8 Spell::CanCast(bool strict)
3139{
3140    // check cooldowns to prevent cheating
3141    if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id))
3142    {
3143        if(m_triggeredByAuraSpell)
3144            return SPELL_FAILED_DONT_REPORT;
3145        else
3146            return SPELL_FAILED_NOT_READY;
3147    }
3148
3149    // only allow triggered spells if at an ended battleground
3150    if( !m_IsTriggeredSpell && m_caster->GetTypeId() == TYPEID_PLAYER)
3151        if(BattleGround * bg = ((Player*)m_caster)->GetBattleGround())
3152            if(bg->GetStatus() == STATUS_WAIT_LEAVE)
3153                return SPELL_FAILED_DONT_REPORT;
3154
3155    // only check at first call, Stealth auras are already removed at second call
3156    // for now, ignore triggered spells
3157    if( strict && !m_IsTriggeredSpell)
3158    {
3159        // Cannot be used in this stance/form
3160        if(uint8 shapeError = GetErrorAtShapeshiftedCast(m_spellInfo, m_caster->m_form))
3161            return shapeError;
3162
3163        if ((m_spellInfo->Attributes & SPELL_ATTR_ONLY_STEALTHED) && !(m_caster->HasStealthAura()))
3164            return SPELL_FAILED_ONLY_STEALTHED;
3165    }
3166
3167    // caster state requirements
3168    if(m_spellInfo->CasterAuraState && !m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraState)))
3169        return SPELL_FAILED_CASTER_AURASTATE;
3170    if(m_spellInfo->CasterAuraStateNot && m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraStateNot)))
3171        return SPELL_FAILED_CASTER_AURASTATE;
3172
3173    // cancel autorepeat spells if cast start when moving
3174    // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code)
3175    if( m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->isMoving() )
3176    {
3177        // skip stuck spell to allow use it in falling case and apply spell limitations at movement
3178        if( (!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING) || m_spellInfo->Effect[0] != SPELL_EFFECT_STUCK) &&
3179            (IsAutoRepeat() || (m_spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED) != 0) )
3180            return SPELL_FAILED_MOVING;
3181    }
3182
3183    Unit *target = m_targets.getUnitTarget();
3184
3185    if(target)
3186    {
3187        // target state requirements (not allowed state), apply to self also
3188        if(m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot)))
3189            return SPELL_FAILED_TARGET_AURASTATE;
3190
3191
3192        if(target != m_caster)
3193        {
3194            // target state requirements (apply to non-self only), to allow cast affects to self like Dirty Deeds
3195            if(m_spellInfo->TargetAuraState && !target->HasAuraState(AuraState(m_spellInfo->TargetAuraState)))
3196                return SPELL_FAILED_TARGET_AURASTATE;
3197
3198            // Not allow casting on flying player
3199            if (target->isInFlight())
3200                return SPELL_FAILED_BAD_TARGETS;
3201
3202            if(VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target))
3203                return SPELL_FAILED_LINE_OF_SIGHT;
3204
3205            // auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode
3206            // this case can be triggered if rank not found (too low-level target for first rank)
3207            if(m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem)
3208            {
3209                for(int i=0;i<3;i++)
3210                {
3211                    if(IsPositiveEffect(m_spellInfo->Id, i) && m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA)
3212                        if(target->getLevel() + 10 < m_spellInfo->spellLevel)
3213                            return SPELL_FAILED_LOWLEVEL;
3214                }
3215            }
3216        }
3217
3218        // check pet presents
3219        for(int j=0;j<3;j++)
3220        {
3221            if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_PET)
3222            {
3223                target = m_caster->GetPet();
3224                if(!target)
3225                {
3226                    if(m_triggeredByAuraSpell)              // not report pet not existence for triggered spells
3227                        return SPELL_FAILED_DONT_REPORT;
3228                    else
3229                        return SPELL_FAILED_NO_PET;
3230                }
3231                break;
3232            }
3233        }
3234
3235        //check creature type
3236        //ignore self casts (including area casts when caster selected as target)
3237        if(target != m_caster)
3238        {
3239            if(!CheckTargetCreatureType(target))
3240            {
3241                if(target->GetTypeId()==TYPEID_PLAYER)
3242                    return SPELL_FAILED_TARGET_IS_PLAYER;
3243                else
3244                    return SPELL_FAILED_BAD_TARGETS;
3245            }
3246        }
3247
3248        // TODO: this check can be applied and for player to prevent cheating when IsPositiveSpell will return always correct result.
3249        // check target for pet/charmed casts (not self targeted), self targeted cast used for area effects and etc
3250        if(m_caster != target && m_caster->GetTypeId()==TYPEID_UNIT && m_caster->GetCharmerOrOwnerGUID())
3251        {
3252            // check correctness positive/negative cast target (pet cast real check and cheating check)
3253            if(IsPositiveSpell(m_spellInfo->Id))
3254            {
3255                if(m_caster->IsHostileTo(target))
3256                    return SPELL_FAILED_BAD_TARGETS;
3257            }
3258            else
3259            {
3260                if(m_caster->IsFriendlyTo(target))
3261                    return SPELL_FAILED_BAD_TARGETS;
3262            }
3263        }
3264
3265        if(IsPositiveSpell(m_spellInfo->Id))
3266        {
3267            if(target->IsImmunedToSpell(m_spellInfo,false))
3268                return SPELL_FAILED_TARGET_AURASTATE;
3269        }
3270
3271        //Must be behind the target.
3272        if( m_spellInfo->AttributesEx2 == 0x100000 && (m_spellInfo->AttributesEx & 0x200) == 0x200 && target->HasInArc(M_PI, m_caster) )
3273        {
3274            SendInterrupted(2);
3275            return SPELL_FAILED_NOT_BEHIND;
3276        }
3277
3278        //Target must be facing you.
3279        if((m_spellInfo->Attributes == 0x150010) && !target->HasInArc(M_PI, m_caster) )
3280        {
3281            SendInterrupted(2);
3282            return SPELL_FAILED_NOT_INFRONT;
3283        }
3284
3285        // check if target is in combat
3286        if (target != m_caster && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat())
3287        {
3288            return SPELL_FAILED_TARGET_AFFECTING_COMBAT;
3289        }
3290    }
3291    // Spell casted only on battleground
3292    if((m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_BATTLEGROUND) &&  m_caster->GetTypeId()==TYPEID_PLAYER)
3293        if(!((Player*)m_caster)->InBattleGround())
3294            return SPELL_FAILED_ONLY_BATTLEGROUNDS;
3295
3296    // do not allow spells to be cast in arenas
3297    // - with greater than 15 min CD without SPELL_ATTR_EX4_USABLE_IN_ARENA flag
3298    // - with SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA flag
3299    if( (m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA) ||
3300        GetSpellRecoveryTime(m_spellInfo) > 15 * MINUTE * 1000 && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA) )
3301        if(MapEntry const* mapEntry = sMapStore.LookupEntry(m_caster->GetMapId()))
3302            if(mapEntry->IsBattleArena())
3303                return SPELL_FAILED_NOT_IN_ARENA;
3304
3305    // zone check
3306    if(!IsSpellAllowedInLocation(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId()))
3307        return SPELL_FAILED_REQUIRES_AREA;
3308
3309    // not let players cast spells at mount (and let do it to creatures)
3310    if( m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell &&
3311        !IsPassiveSpell(m_spellInfo->Id) && !(m_spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_MOUNTED) )
3312    {
3313        if(m_caster->isInFlight())
3314            return SPELL_FAILED_NOT_FLYING;
3315        else
3316            return SPELL_FAILED_NOT_MOUNTED;
3317    }
3318
3319    // always (except passive spells) check items (focus object can be required for any type casts)
3320    if(!IsPassiveSpell(m_spellInfo->Id))
3321        if(uint8 castResult = CheckItems())
3322            return castResult;
3323
3324    //ImpliciteTargetA-B = 38, If fact there is 0 Spell with  ImpliciteTargetB=38
3325    if(m_UniqueTargetInfo.empty())                          // skip second canCast apply (for delayed spells for example)
3326    {
3327        for(uint8 j = 0; j < 3; j++)
3328        {
3329            if( m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT ||
3330                m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[j] != TARGET_SELF ||
3331                m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES ||
3332                m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES )
3333            {
3334                bool okDoo = false;
3335
3336                SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id);
3337                SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id);
3338                if(lower==upper)
3339                    sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT or TARGET_SCRIPT_COORDINATES, but does not have record in `spell_script_target`",m_spellInfo->Id);
3340
3341                SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
3342                float range = GetSpellMaxRange(srange);
3343
3344                Creature* creatureScriptTarget = NULL;
3345                GameObject* goScriptTarget = NULL;
3346
3347                for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST)
3348                {
3349                    switch(i_spellST->second.type)
3350                    {
3351                        case SPELL_TARGET_TYPE_GAMEOBJECT:
3352                        {
3353                            GameObject* p_GameObject = NULL;
3354
3355                            if(i_spellST->second.targetEntry)
3356                            {
3357                                CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
3358                                Cell cell(p);
3359                                cell.data.Part.reserved = ALL_DISTRICT;
3360
3361                                MaNGOS::NearestGameObjectEntryInObjectRangeCheck go_check(*m_caster,i_spellST->second.targetEntry,range);
3362                                MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck> checker(p_GameObject,go_check);
3363
3364                                TypeContainerVisitor<MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker);
3365                                CellLock<GridReadGuard> cell_lock(cell, p);
3366                                cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
3367
3368                                if(p_GameObject)
3369                                {
3370                                    // remember found target and range, next attempt will find more near target with another entry
3371                                    creatureScriptTarget = NULL;
3372                                    goScriptTarget = p_GameObject;
3373                                    range = go_check.GetLastRange();
3374                                }
3375                            }
3376                            else if( focusObject )          //Focus Object
3377                            {
3378                                float frange = m_caster->GetDistance(focusObject);
3379                                if(range >= frange)
3380                                {
3381                                    creatureScriptTarget = NULL;
3382                                    goScriptTarget = focusObject;
3383                                    range = frange;
3384                                }
3385                            }
3386                            break;
3387                        }
3388                        case SPELL_TARGET_TYPE_CREATURE:
3389                        case SPELL_TARGET_TYPE_DEAD:
3390                        default:
3391                        {
3392                            Creature *p_Creature = NULL;
3393
3394                            CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
3395                            Cell cell(p);
3396                            cell.data.Part.reserved = ALL_DISTRICT;
3397                            cell.SetNoCreate();             // Really don't know what is that???
3398
3399                            MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type!=SPELL_TARGET_TYPE_DEAD,range);
3400                            MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(p_Creature, u_check);
3401
3402                            TypeContainerVisitor<MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer >  grid_creature_searcher(searcher);
3403
3404                            CellLock<GridReadGuard> cell_lock(cell, p);
3405                            cell_lock->Visit(cell_lock, grid_creature_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
3406
3407                            if(p_Creature )
3408                            {
3409                                creatureScriptTarget = p_Creature;
3410                                goScriptTarget = NULL;
3411                                range = u_check.GetLastRange();
3412                            }
3413                            break;
3414                        }
3415                    }
3416                }
3417
3418                if(creatureScriptTarget)
3419                {
3420                    // store coordinates for TARGET_SCRIPT_COORDINATES
3421                    if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES ||
3422                        m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES )
3423                    {
3424                        m_targets.setDestination(creatureScriptTarget->GetPositionX(),creatureScriptTarget->GetPositionY(),creatureScriptTarget->GetPositionZ());
3425
3426                        if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j]!=SPELL_EFFECT_PERSISTENT_AREA_AURA)
3427                            AddUnitTarget(creatureScriptTarget, j);
3428                    }
3429                    // store explicit target for TARGET_SCRIPT
3430                    else
3431                        AddUnitTarget(creatureScriptTarget, j);
3432                }
3433                else if(goScriptTarget)
3434                {
3435                    // store coordinates for TARGET_SCRIPT_COORDINATES
3436                    if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES ||
3437                        m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES )
3438                    {
3439                        m_targets.setDestination(goScriptTarget->GetPositionX(),goScriptTarget->GetPositionY(),goScriptTarget->GetPositionZ());
3440
3441                        if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j]!=SPELL_EFFECT_PERSISTENT_AREA_AURA)
3442                            AddGOTarget(goScriptTarget, j);
3443                    }
3444                    // store explicit target for TARGET_SCRIPT
3445                    else
3446                        AddGOTarget(goScriptTarget, j);
3447                }
3448                //Missing DB Entry or targets for this spellEffect.
3449                else
3450                {
3451                    // not report target not existence for triggered spells
3452                    if(m_triggeredByAuraSpell || m_IsTriggeredSpell)
3453                        return SPELL_FAILED_DONT_REPORT;
3454                    else
3455                        return SPELL_FAILED_BAD_TARGETS;
3456                }
3457            }
3458        }
3459    }
3460
3461    if(uint8 castResult = CheckRange(strict))
3462        return castResult;
3463
3464    {
3465        if(uint8 castResult = CheckPower())
3466            return castResult;
3467    }
3468
3469    if(!m_triggeredByAuraSpell)                             // triggered spell not affected by stun/etc
3470        if(uint8 castResult = CheckCasterAuras())
3471            return castResult;
3472
3473    for (int i = 0; i < 3; i++)
3474    {
3475        // for effects of spells that have only one target
3476        switch(m_spellInfo->Effect[i])
3477        {
3478            case SPELL_EFFECT_DUMMY:
3479            {
3480                if(m_spellInfo->SpellIconID == 1648)        // Execute
3481                {
3482                    if(!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2)
3483                        return SPELL_FAILED_BAD_TARGETS;
3484                }
3485                else if (m_spellInfo->Id == 51582)          // Rocket Boots Engaged
3486                {
3487                    if(m_caster->IsInWater())
3488                        return SPELL_FAILED_ONLY_ABOVEWATER;
3489                }
3490                else if(m_spellInfo->SpellIconID==156)      // Holy Shock
3491                {
3492                    // spell different for friends and enemies
3493                    // hart version required facing
3494                    if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, target ))
3495                        return SPELL_FAILED_UNIT_NOT_INFRONT;
3496                }
3497                break;
3498            }
3499            case SPELL_EFFECT_SCHOOL_DAMAGE:
3500            {
3501                // Hammer of Wrath
3502                if(m_spellInfo->SpellVisual == 7250)
3503                {
3504                    if (!m_targets.getUnitTarget())
3505                        return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
3506
3507                    if(m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2)
3508                        return SPELL_FAILED_BAD_TARGETS;
3509                }
3510                break;
3511            }
3512            case SPELL_EFFECT_TAMECREATURE:
3513            {
3514                if (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER)
3515                    return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
3516
3517                if (m_targets.getUnitTarget()->getLevel() > m_caster->getLevel())
3518                    return SPELL_FAILED_HIGHLEVEL;
3519
3520                CreatureInfo const *cinfo = ((Creature*)m_targets.getUnitTarget())->GetCreatureInfo();
3521                if( cinfo->type != CREATURE_TYPE_BEAST )
3522                    return SPELL_FAILED_BAD_TARGETS;
3523
3524                // use SMSG_PET_TAME_FAILURE?
3525                if( !(cinfo->flag1 & 1) || !(cinfo->family) )
3526                    return SPELL_FAILED_BAD_TARGETS;
3527
3528                if(m_caster->GetPetGUID())
3529                    return SPELL_FAILED_ALREADY_HAVE_SUMMON;
3530
3531                if(m_caster->GetCharmGUID())
3532                    return SPELL_FAILED_ALREADY_HAVE_CHARM;
3533
3534                break;
3535            }
3536            case SPELL_EFFECT_LEARN_SPELL:
3537            {
3538                if(m_spellInfo->EffectImplicitTargetA[i] != TARGET_PET)
3539                    break;
3540
3541                Pet* pet = m_caster->GetPet();
3542
3543                if(!pet)
3544                    return SPELL_FAILED_NO_PET;
3545
3546                SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
3547
3548                if(!learn_spellproto)
3549                    return SPELL_FAILED_NOT_KNOWN;
3550
3551                if(!pet->CanTakeMoreActiveSpells(learn_spellproto->Id))
3552                    return SPELL_FAILED_TOO_MANY_SKILLS;
3553
3554                if(m_spellInfo->spellLevel > pet->getLevel())
3555                    return SPELL_FAILED_LOWLEVEL;
3556
3557                if(!pet->HasTPForSpell(learn_spellproto->Id))
3558                    return SPELL_FAILED_TRAINING_POINTS;
3559
3560                break;
3561            }
3562            case SPELL_EFFECT_LEARN_PET_SPELL:
3563            {
3564                Pet* pet = m_caster->GetPet();
3565
3566                if(!pet)
3567                    return SPELL_FAILED_NO_PET;
3568
3569                SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
3570
3571                if(!learn_spellproto)
3572                    return SPELL_FAILED_NOT_KNOWN;
3573
3574                if(!pet->CanTakeMoreActiveSpells(learn_spellproto->Id))
3575                    return SPELL_FAILED_TOO_MANY_SKILLS;
3576
3577                if(m_spellInfo->spellLevel > pet->getLevel())
3578                    return SPELL_FAILED_LOWLEVEL;
3579
3580                if(!pet->HasTPForSpell(learn_spellproto->Id))
3581                    return SPELL_FAILED_TRAINING_POINTS;
3582
3583                break;
3584            }
3585            case SPELL_EFFECT_FEED_PET:
3586            {
3587                if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_targets.getItemTarget() )
3588                    return SPELL_FAILED_BAD_TARGETS;
3589
3590                Pet* pet = m_caster->GetPet();
3591
3592                if(!pet)
3593                    return SPELL_FAILED_NO_PET;
3594
3595                if(!pet->HaveInDiet(m_targets.getItemTarget()->GetProto()))
3596                    return SPELL_FAILED_WRONG_PET_FOOD;
3597
3598                if(!pet->GetCurrentFoodBenefitLevel(m_targets.getItemTarget()->GetProto()->ItemLevel))
3599                    return SPELL_FAILED_FOOD_LOWLEVEL;
3600
3601                if(m_caster->isInCombat() || pet->isInCombat())
3602                    return SPELL_FAILED_AFFECTING_COMBAT;
3603
3604                break;
3605            }
3606            case SPELL_EFFECT_POWER_BURN:
3607            case SPELL_EFFECT_POWER_DRAIN:
3608            {
3609                // Can be area effect, Check only for players and not check if target - caster (spell can have multiply drain/burn effects)
3610                if(m_caster->GetTypeId() == TYPEID_PLAYER)
3611                    if(Unit* target = m_targets.getUnitTarget())
3612                        if(target!=m_caster && target->getPowerType()!=m_spellInfo->EffectMiscValue[i])
3613                            return SPELL_FAILED_BAD_TARGETS;
3614                break;
3615            }
3616            case SPELL_EFFECT_CHARGE:
3617            {
3618                if (m_caster->hasUnitState(UNIT_STAT_ROOT))
3619                    return SPELL_FAILED_ROOTED;
3620
3621                break;
3622            }
3623            case SPELL_EFFECT_SKINNING:
3624            {
3625                if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTypeId() != TYPEID_UNIT)
3626                    return SPELL_FAILED_BAD_TARGETS;
3627
3628                if( !(m_targets.getUnitTarget()->GetUInt32Value(UNIT_FIELD_FLAGS) & UNIT_FLAG_SKINNABLE) )
3629                    return SPELL_FAILED_TARGET_UNSKINNABLE;
3630
3631                Creature* creature = (Creature*)m_targets.getUnitTarget();
3632                if ( creature->GetCreatureType() != CREATURE_TYPE_CRITTER && ( !creature->lootForBody || !creature->loot.empty() ) )
3633                {
3634                    return SPELL_FAILED_TARGET_NOT_LOOTED;
3635                }
3636
3637                uint32 skill;
3638                if(creature->GetCreatureInfo()->flag1 & 256)
3639                    skill = SKILL_HERBALISM;                // special case
3640                else if(creature->GetCreatureInfo()->flag1 & 512)
3641                    skill = SKILL_MINING;                   // special case
3642                else
3643                    skill = SKILL_SKINNING;                 // normal case
3644
3645                int32 skillValue = ((Player*)m_caster)->GetSkillValue(skill);
3646                int32 TargetLevel = m_targets.getUnitTarget()->getLevel();
3647                int32 ReqValue = (skillValue < 100 ? (TargetLevel-10)*10 : TargetLevel*5);
3648                if (ReqValue > skillValue)
3649                    return SPELL_FAILED_LOW_CASTLEVEL;
3650
3651                // chance for fail at orange skinning attempt
3652                if( (m_selfContainer && (*m_selfContainer) == this) &&
3653                    skillValue < sWorld.GetConfigMaxSkillValue() &&
3654                    (ReqValue < 0 ? 0 : ReqValue) > irand(skillValue-25, skillValue+37) )
3655                    return SPELL_FAILED_TRY_AGAIN;
3656
3657                break;
3658            }
3659            case SPELL_EFFECT_OPEN_LOCK_ITEM:
3660            case SPELL_EFFECT_OPEN_LOCK:
3661            {
3662                if( m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT &&
3663                    m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT_ITEM )
3664                    break;
3665
3666                if( m_caster->GetTypeId() != TYPEID_PLAYER  // only players can open locks, gather etc.
3667                    // we need a go target in case of TARGET_GAMEOBJECT
3668                    || m_spellInfo->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT && !m_targets.getGOTarget()
3669                    // we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM
3670                    || m_spellInfo->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT_ITEM && !m_targets.getGOTarget() &&
3671                    (!m_targets.getItemTarget() || !m_targets.getItemTarget()->GetProto()->LockID || m_targets.getItemTarget()->GetOwner() != m_caster ) )
3672                    return SPELL_FAILED_BAD_TARGETS;
3673
3674                // get the lock entry
3675                LockEntry const *lockInfo = NULL;
3676                if (GameObject* go=m_targets.getGOTarget())
3677                    lockInfo = sLockStore.LookupEntry(go->GetLockId());
3678                else if(Item* itm=m_targets.getItemTarget())
3679                    lockInfo = sLockStore.LookupEntry(itm->GetProto()->LockID);
3680
3681                // check lock compatibility
3682                if (lockInfo)
3683                {
3684                    // check for lock - key pair (checked by client also, just prevent cheating
3685                    bool ok_key = false;
3686                    for(int it = 0; it < 5; ++it)
3687                    {
3688                        switch(lockInfo->keytype[it])
3689                        {
3690                            case LOCK_KEY_NONE:
3691                                break;
3692                            case LOCK_KEY_ITEM:
3693                            {
3694                                if(lockInfo->key[it])
3695                                {
3696                                    if(m_CastItem && m_CastItem->GetEntry()==lockInfo->key[it])
3697                                        ok_key =true;
3698                                    break;
3699                                }
3700                            }
3701                            case LOCK_KEY_SKILL:
3702                            {
3703                                if(uint32(m_spellInfo->EffectMiscValue[i])!=lockInfo->key[it])
3704                                    break;
3705
3706                                switch(lockInfo->key[it])
3707                                {
3708                                    case LOCKTYPE_HERBALISM:
3709                                        if(((Player*)m_caster)->HasSkill(SKILL_HERBALISM))
3710                                            ok_key =true;
3711                                        break;
3712                                    case LOCKTYPE_MINING:
3713                                        if(((Player*)m_caster)->HasSkill(SKILL_MINING))
3714                                            ok_key =true;
3715                                        break;
3716                                    default:
3717                                        ok_key =true;
3718                                        break;
3719                                }
3720                            }
3721                        }
3722                        if(ok_key)
3723                            break;
3724                    }
3725
3726                    if(!ok_key)
3727                        return SPELL_FAILED_BAD_TARGETS;
3728                }
3729
3730                // chance for fail at orange mining/herb/LockPicking gathering attempt
3731                if (!m_selfContainer || ((*m_selfContainer) != this))
3732                    break;
3733
3734                // get the skill value of the player
3735                int32 SkillValue = 0;
3736                bool canFailAtMax = true;
3737                if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_HERBALISM)
3738                {
3739                    SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_HERBALISM);
3740                    canFailAtMax = false;
3741                }
3742                else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_MINING)
3743                {
3744                    SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_MINING);
3745                    canFailAtMax = false;
3746                }
3747                else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK)
3748                    SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_LOCKPICKING);
3749
3750                // castitem check: rogue using skeleton keys. the skill values should not be added in this case.
3751                if(m_CastItem)
3752                    SkillValue = 0;
3753
3754                // add the damage modifier from the spell casted (cheat lock / skeleton key etc.) (use m_currentBasePoints, CalculateDamage returns wrong value)
3755                SkillValue += m_currentBasePoints[i]+1;
3756
3757                // get the required lock value
3758                int32 ReqValue=0;
3759                if (lockInfo)
3760                {
3761                    // check for lock - key pair
3762                    bool ok = false;
3763                    for(int it = 0; it < 5; ++it)
3764                    {
3765                        if(lockInfo->keytype[it]==LOCK_KEY_ITEM && lockInfo->key[it] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[it])
3766                        {
3767                            // if so, we're good to go
3768                            ok = true;
3769                            break;
3770                        }
3771                    }
3772                    if(ok)
3773                        break;
3774
3775                    if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK)
3776                        ReqValue = lockInfo->requiredlockskill;
3777                    else
3778                        ReqValue = lockInfo->requiredminingskill;
3779                }
3780
3781                // skill doesn't meet the required value
3782                if (ReqValue > SkillValue)
3783                    return SPELL_FAILED_LOW_CASTLEVEL;
3784
3785                // chance for failure in orange gather / lockpick (gathering skill can't fail at maxskill)
3786                if((canFailAtMax || SkillValue < sWorld.GetConfigMaxSkillValue()) && ReqValue > irand(SkillValue-25, SkillValue+37))
3787                    return SPELL_FAILED_TRY_AGAIN;
3788
3789                break;
3790            }
3791            case SPELL_EFFECT_SUMMON_DEAD_PET:
3792            {
3793                Creature *pet = m_caster->GetPet();
3794                if(!pet)
3795                    return SPELL_FAILED_NO_PET;
3796
3797                if(pet->isAlive())
3798                    return SPELL_FAILED_ALREADY_HAVE_SUMMON;
3799
3800                break;
3801            }
3802            // This is generic summon effect now and don't make this check for summon types similar
3803            // SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN.
3804            // These won't show up in m_caster->GetPetGUID()
3805            case SPELL_EFFECT_SUMMON:
3806            {
3807                switch(m_spellInfo->EffectMiscValueB[i])
3808                {
3809                    case SUMMON_TYPE_POSESSED:
3810                    case SUMMON_TYPE_POSESSED2:
3811                    case SUMMON_TYPE_DEMON:
3812                    case SUMMON_TYPE_SUMMON:
3813                    {
3814                        if(m_caster->GetPetGUID())
3815                            return SPELL_FAILED_ALREADY_HAVE_SUMMON;
3816
3817                        if(m_caster->GetCharmGUID())
3818                            return SPELL_FAILED_ALREADY_HAVE_CHARM;
3819                        break;
3820                    }
3821                }
3822                break;
3823            }
3824            // Don't make this check for SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN.
3825            // These won't show up in m_caster->GetPetGUID()
3826            case SPELL_EFFECT_SUMMON_POSSESSED:
3827            case SPELL_EFFECT_SUMMON_PHANTASM:
3828            case SPELL_EFFECT_SUMMON_DEMON:
3829            {
3830                if(m_caster->GetPetGUID())
3831                    return SPELL_FAILED_ALREADY_HAVE_SUMMON;
3832
3833                if(m_caster->GetCharmGUID())
3834                    return SPELL_FAILED_ALREADY_HAVE_CHARM;
3835
3836                break;
3837            }
3838            case SPELL_EFFECT_SUMMON_PET:
3839            {
3840                if(m_caster->GetPetGUID())                  //let warlock do a replacement summon
3841                {
3842
3843                    Pet* pet = ((Player*)m_caster)->GetPet();
3844
3845                    if (m_caster->GetTypeId()==TYPEID_PLAYER && m_caster->getClass()==CLASS_WARLOCK)
3846                    {
3847                        if (strict)                         //starting cast, trigger pet stun (cast by pet so it doesn't attack player)
3848                            pet->CastSpell(pet, 32752, true, NULL, NULL, pet->GetGUID());
3849                    }
3850                    else
3851                        return SPELL_FAILED_ALREADY_HAVE_SUMMON;
3852                }
3853
3854                if(m_caster->GetCharmGUID())
3855                    return SPELL_FAILED_ALREADY_HAVE_CHARM;
3856
3857                break;
3858            }
3859            case SPELL_EFFECT_SUMMON_PLAYER:
3860            {
3861                if(m_caster->GetTypeId()!=TYPEID_PLAYER)
3862                    return SPELL_FAILED_BAD_TARGETS;
3863                if(!((Player*)m_caster)->GetSelection())
3864                    return SPELL_FAILED_BAD_TARGETS;
3865
3866                Player* target = objmgr.GetPlayer(((Player*)m_caster)->GetSelection());
3867                if( !target || ((Player*)m_caster)==target || !target->IsInSameRaidWith((Player*)m_caster) )
3868                    return SPELL_FAILED_BAD_TARGETS;
3869
3870                // check if our map is dungeon
3871                if( sMapStore.LookupEntry(m_caster->GetMapId())->IsDungeon() )
3872                {
3873                    InstanceTemplate const* instance = ObjectMgr::GetInstanceTemplate(m_caster->GetMapId());
3874                    if(!instance)
3875                        return SPELL_FAILED_TARGET_NOT_IN_INSTANCE;
3876                    if ( instance->levelMin > target->getLevel() )
3877                        return SPELL_FAILED_LOWLEVEL;
3878                    if ( instance->levelMax && instance->levelMax < target->getLevel() )
3879                        return SPELL_FAILED_HIGHLEVEL;
3880                }
3881                break;
3882            }
3883            case SPELL_EFFECT_LEAP:
3884            case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER:
3885            {
3886                float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3887                float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation());
3888                float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation());
3889                // teleport a bit above terrain level to avoid falling below it
3890                float fz = MapManager::Instance().GetBaseMap(m_caster->GetMapId())->GetHeight(fx,fy,m_caster->GetPositionZ(),true);
3891                if(fz <= INVALID_HEIGHT)                    // note: this also will prevent use effect in instances without vmaps height enabled
3892                    return SPELL_FAILED_TRY_AGAIN;
3893
3894                float caster_pos_z = m_caster->GetPositionZ();
3895                // Control the caster to not climb or drop when +-fz > 8
3896                if(!(fz<=caster_pos_z+8 && fz>=caster_pos_z-8))
3897                    return SPELL_FAILED_TRY_AGAIN;
3898
3899                // not allow use this effect at battleground until battleground start
3900                if(m_caster->GetTypeId()==TYPEID_PLAYER)
3901                    if(BattleGround const *bg = ((Player*)m_caster)->GetBattleGround())
3902                        if(bg->GetStatus() != STATUS_IN_PROGRESS)
3903                            return SPELL_FAILED_TRY_AGAIN;
3904                break;
3905            }
3906            case SPELL_EFFECT_STEAL_BENEFICIAL_BUFF:
3907            {
3908                if (m_targets.getUnitTarget()==m_caster)
3909                    return SPELL_FAILED_BAD_TARGETS;
3910                break;
3911            }
3912            default:break;
3913        }
3914    }
3915
3916    for (int i = 0; i < 3; i++)
3917    {
3918        switch(m_spellInfo->EffectApplyAuraName[i])
3919        {
3920            case SPELL_AURA_MOD_POSSESS:
3921            case SPELL_AURA_MOD_CHARM:
3922            {
3923                if(m_caster->GetPetGUID())
3924                    return SPELL_FAILED_ALREADY_HAVE_SUMMON;
3925
3926                if(m_caster->GetCharmGUID())
3927                    return SPELL_FAILED_ALREADY_HAVE_CHARM;
3928
3929                if(m_caster->GetCharmerGUID())
3930                    return SPELL_FAILED_CHARMED;
3931
3932                if(!m_targets.getUnitTarget())
3933                    return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
3934
3935                if(m_targets.getUnitTarget()->GetCharmerGUID())
3936                    return SPELL_FAILED_CHARMED;
3937
3938                if(int32(m_targets.getUnitTarget()->getLevel()) > CalculateDamage(i,m_targets.getUnitTarget()))
3939                    return SPELL_FAILED_HIGHLEVEL;
3940            };break;
3941            case SPELL_AURA_MOUNTED:
3942            {
3943                if (m_caster->IsInWater())
3944                    return SPELL_FAILED_ONLY_ABOVEWATER;
3945
3946                if (m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->GetTransport())
3947                    return SPELL_FAILED_NO_MOUNTS_ALLOWED;
3948
3949                // Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells
3950                if (m_caster->GetTypeId()==TYPEID_PLAYER && !sMapStore.LookupEntry(m_caster->GetMapId())->IsMountAllowed() && !m_IsTriggeredSpell && !m_spellInfo->AreaId)
3951                    return SPELL_FAILED_NO_MOUNTS_ALLOWED;
3952
3953                if (m_caster->GetAreaId()==35)
3954                    return SPELL_FAILED_NO_MOUNTS_ALLOWED;
3955
3956                ShapeshiftForm form = m_caster->m_form;
3957                if( form == FORM_CAT          || form == FORM_TREE      || form == FORM_TRAVEL   ||
3958                    form == FORM_AQUA         || form == FORM_BEAR      || form == FORM_DIREBEAR ||
3959                    form == FORM_CREATUREBEAR || form == FORM_GHOSTWOLF || form == FORM_FLIGHT   ||
3960                    form == FORM_FLIGHT_EPIC  || form == FORM_MOONKIN )
3961                    return SPELL_FAILED_NOT_SHAPESHIFT;
3962
3963                break;
3964            }
3965            case SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS:
3966            {
3967                if(!m_targets.getUnitTarget())
3968                    return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
3969
3970                // can be casted at non-friendly unit or own pet/charm
3971                if(m_caster->IsFriendlyTo(m_targets.getUnitTarget()))
3972                    return SPELL_FAILED_TARGET_FRIENDLY;
3973            };break;
3974            case SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED:
3975            case SPELL_AURA_FLY:
3976            {
3977                // not allow cast fly spells at old maps by players (all spells is self target)
3978                if(m_caster->GetTypeId()==TYPEID_PLAYER)
3979                {
3980                    if( !((Player*)m_caster)->isGameMaster() &&
3981                        GetVirtualMapForMapAndZone(m_caster->GetMapId(),m_caster->GetZoneId()) != 530)
3982                        return SPELL_FAILED_NOT_HERE;
3983                }
3984            };break;
3985            case SPELL_AURA_PERIODIC_MANA_LEECH:
3986            {
3987                if (!m_targets.getUnitTarget())
3988                    return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
3989
3990                if (m_caster->GetTypeId()!=TYPEID_PLAYER || m_CastItem)
3991                    break;
3992
3993                if(m_targets.getUnitTarget()->getPowerType()!=POWER_MANA)
3994                    return SPELL_FAILED_BAD_TARGETS;
3995                break;
3996            }
3997            default:break;
3998        }
3999    }
4000
4001    // all ok
4002    return 0;
4003}
4004
4005int16 Spell::PetCanCast(Unit* target)
4006{
4007    if(!m_caster->isAlive())
4008        return SPELL_FAILED_CASTER_DEAD;
4009
4010    if(m_caster->IsNonMeleeSpellCasted(false))              //prevent spellcast interuption by another spellcast
4011        return SPELL_FAILED_SPELL_IN_PROGRESS;
4012    if(m_caster->isInCombat() && IsNonCombatSpell(m_spellInfo))
4013        return SPELL_FAILED_AFFECTING_COMBAT;
4014
4015    if(m_caster->GetTypeId()==TYPEID_UNIT && (((Creature*)m_caster)->isPet() || m_caster->isCharmed()))
4016    {
4017                                                            //dead owner (pets still alive when owners ressed?)
4018        if(m_caster->GetCharmerOrOwner() && !m_caster->GetCharmerOrOwner()->isAlive())
4019            return SPELL_FAILED_CASTER_DEAD;
4020
4021        if(!target && m_targets.getUnitTarget())
4022            target = m_targets.getUnitTarget();
4023
4024        bool need = false;
4025        for(uint32 i = 0;i<3;i++)
4026        {
4027            if(m_spellInfo->EffectImplicitTargetA[i] == TARGET_CHAIN_DAMAGE || m_spellInfo->EffectImplicitTargetA[i] == TARGET_SINGLE_FRIEND || m_spellInfo->EffectImplicitTargetA[i] == TARGET_DUELVSPLAYER || m_spellInfo->EffectImplicitTargetA[i] == TARGET_SINGLE_PARTY || m_spellInfo->EffectImplicitTargetA[i] == TARGET_CURRENT_ENEMY_COORDINATES)
4028            {
4029                need = true;
4030                if(!target)
4031                    return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
4032                break;
4033            }
4034        }
4035        if(need)
4036            m_targets.setUnitTarget(target);
4037
4038        Unit* _target = m_targets.getUnitTarget();
4039
4040        if(_target)                                         //for target dead/target not valid
4041        {
4042            if(!_target->isAlive())
4043                return SPELL_FAILED_BAD_TARGETS;
4044
4045            if(IsPositiveSpell(m_spellInfo->Id))
4046            {
4047                if(m_caster->IsHostileTo(_target))
4048                    return SPELL_FAILED_BAD_TARGETS;
4049            }
4050            else
4051            {
4052                bool duelvsplayertar = false;
4053                for(int j=0;j<3;j++)
4054                {
4055                                                            //TARGET_DUELVSPLAYER is positive AND negative
4056                    duelvsplayertar |= (m_spellInfo->EffectImplicitTargetA[j] == TARGET_DUELVSPLAYER);
4057                }
4058                if(m_caster->IsFriendlyTo(target) && !duelvsplayertar)
4059                {
4060                    return SPELL_FAILED_BAD_TARGETS;
4061                }
4062            }
4063        }
4064                                                            //cooldown
4065        if(((Creature*)m_caster)->HasSpellCooldown(m_spellInfo->Id))
4066            return SPELL_FAILED_NOT_READY;
4067    }
4068
4069    uint16 result = CanCast(true);
4070    if(result != 0)
4071        return result;
4072    else
4073        return -1;                                          //this allows to check spell fail 0, in combat
4074}
4075
4076uint8 Spell::CheckCasterAuras() const
4077{
4078    // Flag drop spells totally immuned to caster auras
4079    // FIXME: find more nice check for all totally immuned spells
4080    // AttributesEx3 & 0x10000000?
4081    if(m_spellInfo->Id==23336 || m_spellInfo->Id==23334 || m_spellInfo->Id==34991)
4082        return 0;
4083
4084    uint8 school_immune = 0;
4085    uint32 mechanic_immune = 0;
4086    uint32 dispel_immune = 0;
4087
4088    //Check if the spell grants school or mechanic immunity.
4089    //We use bitmasks so the loop is done only once and not on every aura check below.
4090    if ( m_spellInfo->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY )
4091    {
4092        for(int i = 0;i < 3; i ++)
4093        {
4094            if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_SCHOOL_IMMUNITY)
4095                school_immune |= uint32(m_spellInfo->EffectMiscValue[i]);
4096            else if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MECHANIC_IMMUNITY)
4097                mechanic_immune |= 1 << uint32(m_spellInfo->EffectMiscValue[i]);
4098            else if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_DISPEL_IMMUNITY)
4099                dispel_immune |= GetDispellMask(DispelType(m_spellInfo->EffectMiscValue[i]));
4100        }
4101        //immune movement impairement and loss of control
4102        if(m_spellInfo->Id==(uint32)42292)
4103            mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
4104    }
4105
4106    //Check whether the cast should be prevented by any state you might have.
4107    uint8 prevented_reason = 0;
4108    // Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out
4109    if(!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED) && m_caster->HasAuraType(SPELL_AURA_MOD_STUN))
4110        prevented_reason = SPELL_FAILED_STUNNED;
4111    else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED) && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED))
4112        prevented_reason = SPELL_FAILED_CONFUSED;
4113    else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING) && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED))
4114        prevented_reason = SPELL_FAILED_FLEEING;
4115    else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED) && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE)
4116        prevented_reason = SPELL_FAILED_SILENCED;
4117    else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY)
4118        prevented_reason = SPELL_FAILED_PACIFIED;
4119
4120    // Attr must make flag drop spell totally immuned from all effects
4121    if(prevented_reason)
4122    {
4123        if(school_immune || mechanic_immune || dispel_immune)
4124        {
4125            //Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
4126            Unit::AuraMap const& auras = m_caster->GetAuras();
4127            for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); itr++)
4128            {
4129                if(itr->second)
4130                {
4131                    if( GetSpellMechanicMask(itr->second->GetSpellProto(), itr->second->GetEffIndex()) & mechanic_immune )
4132                        continue;
4133                    if( GetSpellSchoolMask(itr->second->GetSpellProto()) & school_immune )
4134                        continue;
4135                    if( (1<<(itr->second->GetSpellProto()->Dispel)) & dispel_immune)
4136                        continue;
4137
4138                    //Make a second check for spell failed so the right SPELL_FAILED message is returned.
4139                    //That is needed when your casting is prevented by multiple states and you are only immune to some of them.
4140                    switch(itr->second->GetModifier()->m_auraname)
4141                    {
4142                        case SPELL_AURA_MOD_STUN:
4143                            if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED))
4144                                return SPELL_FAILED_STUNNED;
4145                            break;
4146                        case SPELL_AURA_MOD_CONFUSE:
4147                            if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED))
4148                                return SPELL_FAILED_CONFUSED;
4149                            break;
4150                        case SPELL_AURA_MOD_FEAR:
4151                            if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED))
4152                                return SPELL_FAILED_FLEEING;
4153                            break;
4154                        case SPELL_AURA_MOD_SILENCE:
4155                        case SPELL_AURA_MOD_PACIFY:
4156                        case SPELL_AURA_MOD_PACIFY_SILENCE:
4157                            if( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY)
4158                                return SPELL_FAILED_PACIFIED;
4159                            else if ( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE)
4160                                return SPELL_FAILED_SILENCED;
4161                            break;
4162                    }
4163                }
4164            }
4165        }
4166        //You are prevented from casting and the spell casted does not grant immunity. Return a failed error.
4167        else
4168            return prevented_reason;
4169    }
4170    return 0;                                               // all ok
4171}
4172
4173bool Spell::CanAutoCast(Unit* target)
4174{
4175    uint64 targetguid = target->GetGUID();
4176
4177    for(uint32 j = 0;j<3;j++)
4178    {
4179        if(m_spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA)
4180        {
4181            if( m_spellInfo->StackAmount <= 1)
4182            {
4183                if( target->HasAura(m_spellInfo->Id, j) )
4184                    return false;
4185            }
4186            else
4187            {
4188                if( target->GetAuras().count(Unit::spellEffectPair(m_spellInfo->Id, j)) >= m_spellInfo->StackAmount)
4189                    return false;
4190            }
4191        }
4192        else if ( IsAreaAuraEffect( m_spellInfo->Effect[j] ))
4193        {
4194                if( target->HasAura(m_spellInfo->Id, j) )
4195                    return false;
4196        }
4197    }
4198
4199    int16 result = PetCanCast(target);
4200
4201    if(result == -1 || result == SPELL_FAILED_UNIT_NOT_INFRONT)
4202    {
4203        FillTargetMap();
4204        //check if among target units, our WANTED target is as well (->only self cast spells return false)
4205        for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
4206            if( ihit->targetGUID == targetguid )
4207                return true;
4208    }
4209    return false;                                           //target invalid
4210}
4211
4212uint8 Spell::CheckRange(bool strict)
4213{
4214    float range_mod;
4215
4216    // self cast doesn't need range checking -- also for Starshards fix
4217    if (m_spellInfo->rangeIndex == 1) return 0;
4218
4219    if (strict)                                             //add radius of caster
4220        range_mod = 1.25;
4221    else                                                    //add radius of caster and ~5 yds "give"
4222        range_mod = 6.25;
4223
4224    SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
4225    float max_range = GetSpellMaxRange(srange) + range_mod;
4226    float min_range = GetSpellMinRange(srange);
4227
4228    if(Player* modOwner = m_caster->GetSpellModOwner())
4229        modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, max_range, this);
4230
4231    Unit *target = m_targets.getUnitTarget();
4232
4233    if(target && target != m_caster)
4234    {
4235        // distance from target center in checks
4236        float dist = m_caster->GetDistance(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ());
4237        if(dist > max_range)
4238            return SPELL_FAILED_OUT_OF_RANGE;               //0x5A;
4239        if(dist < min_range)
4240            return SPELL_FAILED_TOO_CLOSE;
4241        if( m_caster->GetTypeId() == TYPEID_PLAYER &&
4242            (m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc( M_PI, target ) )
4243            return SPELL_FAILED_UNIT_NOT_INFRONT;
4244    }
4245
4246    if(m_targets.m_targetMask == TARGET_FLAG_DEST_LOCATION && m_targets.m_destX != 0 && m_targets.m_destY != 0 && m_targets.m_destZ != 0)
4247    {
4248        float dist = m_caster->GetDistance(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ);
4249        if(dist > max_range)
4250            return SPELL_FAILED_OUT_OF_RANGE;
4251        if(dist < min_range)
4252            return SPELL_FAILED_TOO_CLOSE;
4253    }
4254
4255    return 0;                                               // ok
4256}
4257
4258int32 Spell::CalculatePowerCost()
4259{
4260    // item cast not used power
4261    if(m_CastItem)
4262        return 0;
4263
4264    // Spell drain all exist power on cast (Only paladin lay of Hands)
4265    if (m_spellInfo->AttributesEx & SPELL_ATTR_EX_DRAIN_ALL_POWER)
4266    {
4267        // If power type - health drain all
4268        if (m_spellInfo->powerType == POWER_HEALTH)
4269            return m_caster->GetHealth();
4270        // Else drain all power
4271        if (m_spellInfo->powerType < MAX_POWERS)
4272            return m_caster->GetPower(Powers(m_spellInfo->powerType));
4273        sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id);
4274        return 0;
4275    }
4276
4277    // Base powerCost
4278    int32 powerCost = m_spellInfo->manaCost;
4279    // PCT cost from total amount
4280    if (m_spellInfo->ManaCostPercentage)
4281    {
4282        switch (m_spellInfo->powerType)
4283        {
4284            // health as power used
4285            case POWER_HEALTH:
4286                powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateHealth() / 100;
4287                break;
4288            case POWER_MANA:
4289                powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateMana() / 100;
4290                break;
4291            case POWER_RAGE:
4292            case POWER_FOCUS:
4293            case POWER_ENERGY:
4294            case POWER_HAPPINESS:
4295                //            case POWER_RUNES:
4296                powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetMaxPower(Powers(m_spellInfo->powerType)) / 100;
4297                break;
4298            default:
4299                sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id);
4300                return 0;
4301        }
4302    }
4303    SpellSchools school = GetFirstSchoolInMask(m_spellSchoolMask);
4304    // Flat mod from caster auras by spell school
4305    powerCost += m_caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school);
4306    // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost)
4307    if ( m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST )
4308        powerCost += m_caster->GetAttackTime(OFF_ATTACK)/100;
4309    // Apply cost mod by spell
4310    if(Player* modOwner = m_caster->GetSpellModOwner())
4311        modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, powerCost, this);
4312
4313    if(m_spellInfo->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION)
4314        powerCost = int32(powerCost/ (1.117f* m_spellInfo->spellLevel / m_caster->getLevel() -0.1327f));
4315
4316    // PCT mod from user auras by school
4317    powerCost = int32(powerCost * (1.0f+m_caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+school)));
4318    if (powerCost < 0)
4319        powerCost = 0;
4320    return powerCost;
4321}
4322
4323uint8 Spell::CheckPower()
4324{
4325    // item cast not used power
4326    if(m_CastItem)
4327        return 0;
4328
4329    // health as power used - need check health amount
4330    if(m_spellInfo->powerType == POWER_HEALTH)
4331    {
4332        if(m_caster->GetHealth() <= m_powerCost)
4333            return SPELL_FAILED_CASTER_AURASTATE;
4334        return 0;
4335    }
4336    // Check valid power type
4337    if( m_spellInfo->powerType >= MAX_POWERS )
4338    {
4339        sLog.outError("Spell::CheckMana: Unknown power type '%d'", m_spellInfo->powerType);
4340        return SPELL_FAILED_UNKNOWN;
4341    }
4342    // Check power amount
4343    Powers powerType = Powers(m_spellInfo->powerType);
4344    if(m_caster->GetPower(powerType) < m_powerCost)
4345        return SPELL_FAILED_NO_POWER;
4346    else
4347        return 0;
4348}
4349
4350uint8 Spell::CheckItems()
4351{
4352    if (m_caster->GetTypeId() != TYPEID_PLAYER)
4353        return 0;
4354
4355    uint32 itemid, itemcount;
4356    Player* p_caster = (Player*)m_caster;
4357
4358    if(m_CastItem)
4359    {
4360        itemid = m_CastItem->GetEntry();
4361        if( !p_caster->HasItemCount(itemid,1) )
4362            return SPELL_FAILED_ITEM_NOT_READY;
4363        else
4364        {
4365            ItemPrototype const *proto = m_CastItem->GetProto();
4366            if(!proto)
4367                return SPELL_FAILED_ITEM_NOT_READY;
4368
4369            for (int i = 0; i<5; i++)
4370            {
4371                if (proto->Spells[i].SpellCharges)
4372                {
4373                    if(m_CastItem->GetSpellCharges(i)==0)
4374                        return SPELL_FAILED_NO_CHARGES_REMAIN;
4375                }
4376            }
4377
4378            uint32 ItemClass = proto->Class;
4379            if (ItemClass == ITEM_CLASS_CONSUMABLE && m_targets.getUnitTarget())
4380            {
4381                for (int i = 0; i < 3; i++)
4382                {
4383                    // skip check, pet not required like checks, and for TARGET_PET m_targets.getUnitTarget() is not the real target but the caster
4384                    if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_PET)
4385                        continue;
4386
4387                    if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL)
4388                        if (m_targets.getUnitTarget()->GetHealth() == m_targets.getUnitTarget()->GetMaxHealth())
4389                            return (uint8)SPELL_FAILED_ALREADY_AT_FULL_HEALTH;
4390
4391                    // Mana Potion, Rage Potion, Thistle Tea(Rogue), ...
4392                    if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE)
4393                    {
4394                        if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
4395                            return (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER;
4396
4397                        Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
4398
4399                        if (m_targets.getUnitTarget()->GetPower(power) == m_targets.getUnitTarget()->GetMaxPower(power))
4400                            return (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER;
4401                    }
4402                }
4403            }
4404        }
4405    }
4406
4407    if(m_targets.getItemTargetGUID())
4408    {
4409        if(m_caster->GetTypeId() != TYPEID_PLAYER)
4410            return SPELL_FAILED_BAD_TARGETS;
4411
4412        if(!m_targets.getItemTarget())
4413            return SPELL_FAILED_ITEM_GONE;
4414
4415        if(!m_targets.getItemTarget()->IsFitToSpellRequirements(m_spellInfo))
4416            return SPELL_FAILED_EQUIPPED_ITEM_CLASS;
4417    }
4418    // if not item target then required item must be equipped
4419    else
4420    {
4421        if(m_caster->GetTypeId() == TYPEID_PLAYER && !((Player*)m_caster)->HasItemFitToSpellReqirements(m_spellInfo))
4422            return SPELL_FAILED_EQUIPPED_ITEM_CLASS;
4423    }
4424
4425    if(m_spellInfo->RequiresSpellFocus)
4426    {
4427        CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
4428        Cell cell(p);
4429        cell.data.Part.reserved = ALL_DISTRICT;
4430
4431        GameObject* ok = NULL;
4432        MaNGOS::GameObjectFocusCheck go_check(m_caster,m_spellInfo->RequiresSpellFocus);
4433        MaNGOS::GameObjectSearcher<MaNGOS::GameObjectFocusCheck> checker(ok,go_check);
4434
4435        TypeContainerVisitor<MaNGOS::GameObjectSearcher<MaNGOS::GameObjectFocusCheck>, GridTypeMapContainer > object_checker(checker);
4436        CellLock<GridReadGuard> cell_lock(cell, p);
4437        cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
4438
4439        if(!ok)
4440            return (uint8)SPELL_FAILED_REQUIRES_SPELL_FOCUS;
4441
4442        focusObject = ok;                                   // game object found in range
4443    }
4444
4445    if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP &&
4446        m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION)))
4447    {
4448        for(uint32 i=0;i<8;i++)
4449        {
4450            if(m_spellInfo->Reagent[i] <= 0)
4451                continue;
4452
4453            itemid    = m_spellInfo->Reagent[i];
4454            itemcount = m_spellInfo->ReagentCount[i];
4455
4456            // if CastItem is also spell reagent
4457            if( m_CastItem && m_CastItem->GetEntry() == itemid )
4458            {
4459                ItemPrototype const *proto = m_CastItem->GetProto();
4460                if(!proto)
4461                    return SPELL_FAILED_ITEM_NOT_READY;
4462                for(int s=0;s<5;s++)
4463                {
4464                    // CastItem will be used up and does not count as reagent
4465                    int32 charges = m_CastItem->GetSpellCharges(s);
4466                    if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2)
4467                    {
4468                        ++itemcount;
4469                        break;
4470                    }
4471                }
4472            }
4473            if( !p_caster->HasItemCount(itemid,itemcount) )
4474                return (uint8)SPELL_FAILED_ITEM_NOT_READY;      //0x54
4475        }
4476    }
4477
4478    uint32 totems = 2;
4479    for(int i=0;i<2;++i)
4480    {
4481        if(m_spellInfo->Totem[i] != 0)
4482        {
4483            if( p_caster->HasItemCount(m_spellInfo->Totem[i],1) )
4484            {
4485                totems -= 1;
4486                continue;
4487            }
4488        }else
4489        totems -= 1;
4490    }
4491    if(totems != 0)
4492        return (uint8)SPELL_FAILED_TOTEMS;                  //0x7C
4493
4494    //Check items for TotemCategory
4495    uint32 TotemCategory = 2;
4496    for(int i=0;i<2;++i)
4497    {
4498        if(m_spellInfo->TotemCategory[i] != 0)
4499        {
4500            if( p_caster->HasItemTotemCategory(m_spellInfo->TotemCategory[i]) )
4501            {
4502                TotemCategory -= 1;
4503                continue;
4504            }
4505        }
4506        else
4507            TotemCategory -= 1;
4508    }
4509    if(TotemCategory != 0)
4510        return (uint8)SPELL_FAILED_TOTEM_CATEGORY;          //0x7B
4511
4512    for(int i = 0; i < 3; i++)
4513    {
4514        switch (m_spellInfo->Effect[i])
4515        {
4516            case SPELL_EFFECT_CREATE_ITEM:
4517            {
4518                if (!m_IsTriggeredSpell && m_spellInfo->EffectItemType[i])
4519                {
4520                    ItemPosCountVec dest;
4521                    uint8 msg = p_caster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->EffectItemType[i], 1 );
4522                    if (msg != EQUIP_ERR_OK )
4523                    {
4524                        p_caster->SendEquipError( msg, NULL, NULL );
4525                        return SPELL_FAILED_DONT_REPORT;
4526                    }
4527                }
4528                break;
4529            }
4530            case SPELL_EFFECT_ENCHANT_ITEM:
4531            {
4532                Item* targetItem = m_targets.getItemTarget();
4533                if(!targetItem)
4534                    return SPELL_FAILED_ITEM_NOT_FOUND;
4535
4536                if( targetItem->GetProto()->ItemLevel < m_spellInfo->baseLevel )
4537                    return SPELL_FAILED_LOWLEVEL;
4538                // Not allow enchant in trade slot for some enchant type
4539                if( targetItem->GetOwner() != m_caster )
4540                {
4541                    uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
4542                    SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
4543                    if(!pEnchant)
4544                        return SPELL_FAILED_ERROR;
4545                    if (pEnchant->slot & ENCHANTMENT_CAN_SOULBOUND)
4546                        return SPELL_FAILED_NOT_TRADEABLE;
4547                }
4548                break;
4549            }
4550            case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY:
4551            {
4552                Item *item = m_targets.getItemTarget();
4553                if(!item)
4554                    return SPELL_FAILED_ITEM_NOT_FOUND;
4555                // Not allow enchant in trade slot for some enchant type
4556                if( item->GetOwner() != m_caster )
4557                {
4558                    uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
4559                    SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
4560                    if(!pEnchant)
4561                        return SPELL_FAILED_ERROR;
4562                    if (pEnchant->slot & ENCHANTMENT_CAN_SOULBOUND)
4563                        return SPELL_FAILED_NOT_TRADEABLE;
4564                }
4565                break;
4566            }
4567            case SPELL_EFFECT_ENCHANT_HELD_ITEM:
4568                // check item existence in effect code (not output errors at offhand hold item effect to main hand for example
4569                break;
4570            case SPELL_EFFECT_DISENCHANT:
4571            {
4572                if(!m_targets.getItemTarget())
4573                    return SPELL_FAILED_CANT_BE_DISENCHANTED;
4574
4575                // prevent disenchanting in trade slot
4576                if( m_targets.getItemTarget()->GetOwnerGUID() != m_caster->GetGUID() )
4577                    return SPELL_FAILED_CANT_BE_DISENCHANTED;
4578
4579                ItemPrototype const* itemProto = m_targets.getItemTarget()->GetProto();
4580                if(!itemProto)
4581                    return SPELL_FAILED_CANT_BE_DISENCHANTED;
4582
4583                uint32 item_quality = itemProto->Quality;
4584                // 2.0.x addon: Check player enchanting level agains the item desenchanting requirements
4585                uint32 item_disenchantskilllevel = itemProto->RequiredDisenchantSkill;
4586                if (item_disenchantskilllevel == uint32(-1))
4587                    return SPELL_FAILED_CANT_BE_DISENCHANTED;
4588                if (item_disenchantskilllevel > p_caster->GetSkillValue(SKILL_ENCHANTING))
4589                    return SPELL_FAILED_LOW_CASTLEVEL;
4590                if(item_quality > 4 || item_quality < 2)
4591                    return SPELL_FAILED_CANT_BE_DISENCHANTED;
4592                if(itemProto->Class != ITEM_CLASS_WEAPON && itemProto->Class != ITEM_CLASS_ARMOR)
4593                    return SPELL_FAILED_CANT_BE_DISENCHANTED;
4594                if (!itemProto->DisenchantID)
4595                    return SPELL_FAILED_CANT_BE_DISENCHANTED;
4596                break;
4597            }
4598            case SPELL_EFFECT_PROSPECTING:
4599            {
4600                if(!m_targets.getItemTarget())
4601                    return SPELL_FAILED_CANT_BE_PROSPECTED;
4602                //ensure item is a prospectable ore
4603                if(!(m_targets.getItemTarget()->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP) || m_targets.getItemTarget()->GetProto()->Class != ITEM_CLASS_TRADE_GOODS)
4604                    return SPELL_FAILED_CANT_BE_PROSPECTED;
4605                //prevent prospecting in trade slot
4606                if( m_targets.getItemTarget()->GetOwnerGUID() != m_caster->GetGUID() )
4607                    return SPELL_FAILED_CANT_BE_PROSPECTED;
4608                //Check for enough skill in jewelcrafting
4609                uint32 item_prospectingskilllevel = m_targets.getItemTarget()->GetProto()->RequiredSkillRank;
4610                if(item_prospectingskilllevel >p_caster->GetSkillValue(SKILL_JEWELCRAFTING))
4611                    return SPELL_FAILED_LOW_CASTLEVEL;
4612                //make sure the player has the required ores in inventory
4613                if(m_targets.getItemTarget()->GetCount() < 5)
4614                    return SPELL_FAILED_PROSPECT_NEED_MORE;
4615
4616                if(!LootTemplates_Prospecting.HaveLootFor(m_targets.getItemTargetEntry()))
4617                    return SPELL_FAILED_CANT_BE_PROSPECTED;
4618
4619                break;
4620            }
4621            case SPELL_EFFECT_WEAPON_DAMAGE:
4622            case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4623            {
4624                if(m_caster->GetTypeId() != TYPEID_PLAYER) return SPELL_FAILED_TARGET_NOT_PLAYER;
4625                if( m_attackType != RANGED_ATTACK )
4626                    break;
4627                Item *pItem = ((Player*)m_caster)->GetWeaponForAttack(m_attackType);
4628                if(!pItem || pItem->IsBroken())
4629                    return SPELL_FAILED_EQUIPPED_ITEM;
4630
4631                switch(pItem->GetProto()->SubClass)
4632                {
4633                    case ITEM_SUBCLASS_WEAPON_THROWN:
4634                    {
4635                        uint32 ammo = pItem->GetEntry();
4636                        if( !((Player*)m_caster)->HasItemCount( ammo, 1 ) )
4637                            return SPELL_FAILED_NO_AMMO;
4638                    };  break;
4639                    case ITEM_SUBCLASS_WEAPON_GUN:
4640                    case ITEM_SUBCLASS_WEAPON_BOW:
4641                    case ITEM_SUBCLASS_WEAPON_CROSSBOW:
4642                    {
4643                        uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID);
4644                        if(!ammo)
4645                        {
4646                            // Requires No Ammo
4647                            if(m_caster->GetDummyAura(46699))
4648                                break;                      // skip other checks
4649
4650                            return SPELL_FAILED_NO_AMMO;
4651                        }
4652
4653                        ItemPrototype const *ammoProto = objmgr.GetItemPrototype( ammo );
4654                        if(!ammoProto)
4655                            return SPELL_FAILED_NO_AMMO;
4656
4657                        if(ammoProto->Class != ITEM_CLASS_PROJECTILE)
4658                            return SPELL_FAILED_NO_AMMO;
4659
4660                        // check ammo ws. weapon compatibility
4661                        switch(pItem->GetProto()->SubClass)
4662                        {
4663                            case ITEM_SUBCLASS_WEAPON_BOW:
4664                            case ITEM_SUBCLASS_WEAPON_CROSSBOW:
4665                                if(ammoProto->SubClass!=ITEM_SUBCLASS_ARROW)
4666                                    return SPELL_FAILED_NO_AMMO;
4667                                break;
4668                            case ITEM_SUBCLASS_WEAPON_GUN:
4669                                if(ammoProto->SubClass!=ITEM_SUBCLASS_BULLET)
4670                                    return SPELL_FAILED_NO_AMMO;
4671                                break;
4672                            default:
4673                                return SPELL_FAILED_NO_AMMO;
4674                        }
4675
4676                        if( !((Player*)m_caster)->HasItemCount( ammo, 1 ) )
4677                            return SPELL_FAILED_NO_AMMO;
4678                    };  break;
4679                    case ITEM_SUBCLASS_WEAPON_WAND:
4680                    default:
4681                        break;
4682                }
4683                break;
4684            }
4685            default:break;
4686        }
4687    }
4688
4689    return uint8(0);
4690}
4691
4692void Spell::Delayed()
4693{
4694    if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
4695        return;
4696
4697    if (m_spellState == SPELL_STATE_DELAYED)
4698        return;                                             // spell is active and can't be time-backed
4699
4700    // spells not loosing casting time ( slam, dynamites, bombs.. )
4701    if(!(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_DAMAGE))
4702        return;
4703
4704    //check resist chance
4705    int32 resistChance = 100;                               //must be initialized to 100 for percent modifiers
4706    ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance, this);
4707    resistChance += m_caster->GetTotalAuraModifier(SPELL_AURA_RESIST_PUSHBACK) - 100;
4708    if (roll_chance_i(resistChance))
4709        return;
4710
4711    int32 delaytime = GetNextDelayAtDamageMsTime();
4712
4713    if(int32(m_timer) + delaytime > m_casttime)
4714    {
4715        delaytime = m_casttime - m_timer;
4716        m_timer = m_casttime;
4717    }
4718    else
4719        m_timer += delaytime;
4720
4721    sLog.outDetail("Spell %u partially interrupted for (%d) ms at damage",m_spellInfo->Id,delaytime);
4722
4723    WorldPacket data(SMSG_SPELL_DELAYED, 8+4);
4724    data.append(m_caster->GetPackGUID());
4725    data << uint32(delaytime);
4726
4727    m_caster->SendMessageToSet(&data,true);
4728}
4729
4730void Spell::DelayedChannel()
4731{
4732    if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER || getState() != SPELL_STATE_CASTING)
4733        return;
4734
4735    //check resist chance
4736    int32 resistChance = 100;                               //must be initialized to 100 for percent modifiers
4737    ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance, this);
4738    resistChance += m_caster->GetTotalAuraModifier(SPELL_AURA_RESIST_PUSHBACK) - 100;
4739    if (roll_chance_i(resistChance))
4740        return;
4741
4742    int32 delaytime = GetNextDelayAtDamageMsTime();
4743
4744    if(int32(m_timer) < delaytime)
4745    {
4746        delaytime = m_timer;
4747        m_timer = 0;
4748    }
4749    else
4750        m_timer -= delaytime;
4751
4752    sLog.outDebug("Spell %u partially interrupted for %i ms, new duration: %u ms", m_spellInfo->Id, delaytime, m_timer);
4753
4754    for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
4755    {
4756        if ((*ihit).missCondition == SPELL_MISS_NONE)
4757        {
4758            Unit* unit = m_caster->GetGUID()==ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
4759            if (unit)
4760            {
4761                for (int j=0;j<3;j++)
4762                    if( ihit->effectMask & (1<<j) )
4763                        unit->DelayAura(m_spellInfo->Id, j, delaytime);
4764            }
4765
4766        }
4767    }
4768
4769    for(int j = 0; j < 3; j++)
4770    {
4771        // partially interrupt persistent area auras
4772        DynamicObject* dynObj = m_caster->GetDynObject(m_spellInfo->Id, j);
4773        if(dynObj)
4774            dynObj->Delay(delaytime);
4775    }
4776
4777    SendChannelUpdate(m_timer);
4778}
4779
4780void Spell::UpdatePointers()
4781{
4782    if(m_originalCasterGUID==m_caster->GetGUID())
4783        m_originalCaster = m_caster;
4784    else
4785    {
4786        m_originalCaster = ObjectAccessor::GetUnit(*m_caster,m_originalCasterGUID);
4787        if(m_originalCaster && !m_originalCaster->IsInWorld()) m_originalCaster = NULL;
4788    }
4789
4790    m_targets.Update(m_caster);
4791}
4792
4793bool Spell::IsAffectedBy(SpellEntry const *spellInfo, uint32 effectId)
4794{
4795    return spellmgr.IsAffectedBySpell(m_spellInfo,spellInfo->Id,effectId,spellInfo->EffectItemType[effectId]);
4796}
4797
4798bool Spell::CheckTargetCreatureType(Unit* target) const
4799{
4800    uint32 spellCreatureTargetMask = m_spellInfo->TargetCreatureType;
4801
4802    // Curse of Doom : not find another way to fix spell target check :/
4803    if(m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags == 0x0200000000LL)
4804    {
4805        // not allow cast at player
4806        if(target->GetTypeId()==TYPEID_PLAYER)
4807            return false;
4808
4809        spellCreatureTargetMask = 0x7FF;
4810    }
4811
4812    // Dismiss Pet and Taming Lesson skipped
4813    if(m_spellInfo->Id == 2641 || m_spellInfo->Id == 23356)
4814        spellCreatureTargetMask =  0;
4815
4816    if (spellCreatureTargetMask)
4817    {
4818        uint32 TargetCreatureType = target->GetCreatureTypeMask();
4819
4820        return !TargetCreatureType || (spellCreatureTargetMask & TargetCreatureType);
4821    }
4822    return true;
4823}
4824
4825CurrentSpellTypes Spell::GetCurrentContainer()
4826{
4827    if (IsNextMeleeSwingSpell())
4828        return(CURRENT_MELEE_SPELL);
4829    else if (IsAutoRepeat())
4830        return(CURRENT_AUTOREPEAT_SPELL);
4831    else if (IsChanneledSpell(m_spellInfo))
4832        return(CURRENT_CHANNELED_SPELL);
4833    else
4834        return(CURRENT_GENERIC_SPELL);
4835}
4836
4837bool Spell::CheckTarget( Unit* target, uint32 eff, bool hitPhase )
4838{
4839    // Check targets for creature type mask and remove not appropriate (skip explicit self target case, maybe need other explicit targets)
4840    if(m_spellInfo->EffectImplicitTargetA[eff]!=TARGET_SELF )
4841    {
4842        if (!CheckTargetCreatureType(target))
4843            return false;
4844    }
4845
4846    // Check targets for not_selectable unit flag and remove
4847    // A player can cast spells on his pet (or other controlled unit) though in any state
4848    if (target != m_caster && target->GetCharmerOrOwnerGUID() != m_caster->GetGUID())
4849    {
4850        // any unattackable target skipped
4851        if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
4852            return false;
4853
4854        // unselectable targets skipped in all cases except TARGET_SCRIPT targeting
4855        // in case TARGET_SCRIPT target selected by server always and can't be cheated
4856        if( target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE) &&
4857            m_spellInfo->EffectImplicitTargetA[eff] != TARGET_SCRIPT &&
4858            m_spellInfo->EffectImplicitTargetB[eff] != TARGET_SCRIPT )
4859            return false;
4860    }
4861
4862    //Check player targets and remove if in GM mode or GM invisibility (for not self casting case)
4863    if( target != m_caster && target->GetTypeId()==TYPEID_PLAYER)
4864    {
4865        if(((Player*)target)->GetVisibility()==VISIBILITY_OFF)
4866            return false;
4867
4868        if(((Player*)target)->isGameMaster() && !IsPositiveSpell(m_spellInfo->Id))
4869            return false;
4870    }
4871
4872    //Check targets for LOS visibility (except spells without range limitations )
4873    switch(m_spellInfo->Effect[eff])
4874    {
4875        case SPELL_EFFECT_SUMMON_PLAYER:                    // from anywhere
4876            break;
4877        case SPELL_EFFECT_DUMMY:
4878            if(m_spellInfo->Id!=20577)                      // Cannibalize
4879                break;
4880            //fall through
4881        case SPELL_EFFECT_RESURRECT_NEW:
4882            // player far away, maybe his corpse near?
4883            if(target!=m_caster && !target->IsWithinLOSInMap(m_caster))
4884            {
4885                if(!m_targets.getCorpseTargetGUID())
4886                    return false;
4887
4888                Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster,m_targets.getCorpseTargetGUID());
4889                if(!corpse)
4890                    return false;
4891
4892                if(target->GetGUID()!=corpse->GetOwnerGUID())
4893                    return false;
4894
4895                if(!corpse->IsWithinLOSInMap(m_caster))
4896                    return false;
4897            }
4898
4899            // all ok by some way or another, skip normal check
4900            break;
4901        default:                                            // normal case
4902            if(target!=m_caster && !target->IsWithinLOSInMap(m_caster))
4903                return false;
4904            break;
4905    }
4906
4907    return true;
4908}
4909
4910Unit* Spell::SelectMagnetTarget()
4911{
4912    Unit* target = m_targets.getUnitTarget();
4913
4914    if(target && target->HasAuraType(SPELL_AURA_SPELL_MAGNET) && !(m_spellInfo->Attributes & 0x10))
4915    {
4916        Unit::AuraList const& magnetAuras = target->GetAurasByType(SPELL_AURA_SPELL_MAGNET);
4917        for(Unit::AuraList::const_iterator itr = magnetAuras.begin(); itr != magnetAuras.end(); ++itr)
4918        {
4919            if(Unit* magnet = (*itr)->GetCaster())
4920            {
4921                if(magnet->IsWithinLOSInMap(m_caster))
4922                {
4923                    target = magnet;
4924                    m_targets.setUnitTarget(target);
4925                    break;
4926                }
4927            }
4928        }
4929    }
4930
4931    return target;
4932}
4933
4934bool Spell::IsNeedSendToClient() const
4935{
4936    return m_spellInfo->SpellVisual!=0 || IsChanneledSpell(m_spellInfo) ||
4937        m_spellInfo->speed > 0.0f || !m_triggeredByAuraSpell && !m_IsTriggeredSpell;
4938}
4939
4940bool Spell::HaveTargetsForEffect( uint8 effect ) const
4941{
4942    for(std::list<TargetInfo>::const_iterator itr= m_UniqueTargetInfo.begin();itr != m_UniqueTargetInfo.end();++itr)
4943        if(itr->effectMask & (1<<effect))
4944            return true;
4945
4946    for(std::list<GOTargetInfo>::const_iterator itr= m_UniqueGOTargetInfo.begin();itr != m_UniqueGOTargetInfo.end();++itr)
4947        if(itr->effectMask & (1<<effect))
4948            return true;
4949
4950    for(std::list<ItemTargetInfo>::const_iterator itr= m_UniqueItemInfo.begin();itr != m_UniqueItemInfo.end();++itr)
4951        if(itr->effectMask & (1<<effect))
4952            return true;
4953
4954    return false;
4955}
4956
4957SpellEvent::SpellEvent(Spell* spell) : BasicEvent()
4958{
4959    m_Spell = spell;
4960}
4961
4962SpellEvent::~SpellEvent()
4963{
4964    if (m_Spell->getState() != SPELL_STATE_FINISHED)
4965        m_Spell->cancel();
4966
4967    if (m_Spell->IsDeletable())
4968    {
4969        delete m_Spell;
4970    }
4971    else
4972    {
4973        sLog.outError("~SpellEvent: %s %u tried to delete non-deletable spell %u. Was not deleted, causes memory leak.",
4974            (m_Spell->GetCaster()->GetTypeId()==TYPEID_PLAYER?"Player":"Creature"), m_Spell->GetCaster()->GetGUIDLow(),m_Spell->m_spellInfo->Id);
4975    }
4976}
4977
4978bool SpellEvent::Execute(uint64 e_time, uint32 p_time)
4979{
4980    // update spell if it is not finished
4981    if (m_Spell->getState() != SPELL_STATE_FINISHED)
4982        m_Spell->update(p_time);
4983
4984    // check spell state to process
4985    switch (m_Spell->getState())
4986    {
4987        case SPELL_STATE_FINISHED:
4988        {
4989            // spell was finished, check deletable state
4990            if (m_Spell->IsDeletable())
4991            {
4992                // check, if we do have unfinished triggered spells
4993
4994                return(true);                               // spell is deletable, finish event
4995            }
4996            // event will be re-added automatically at the end of routine)
4997        } break;
4998
4999        case SPELL_STATE_CASTING:
5000        {
5001            // this spell is in channeled state, process it on the next update
5002            // event will be re-added automatically at the end of routine)
5003        } break;
5004
5005        case SPELL_STATE_DELAYED:
5006        {
5007            // first, check, if we have just started
5008            if (m_Spell->GetDelayStart() != 0)
5009            {
5010                // no, we aren't, do the typical update
5011                // check, if we have channeled spell on our hands
5012                if (IsChanneledSpell(m_Spell->m_spellInfo))
5013                {
5014                    // evented channeled spell is processed separately, casted once after delay, and not destroyed till finish
5015                    // check, if we have casting anything else except this channeled spell and autorepeat
5016                    if (m_Spell->GetCaster()->IsNonMeleeSpellCasted(false, true, true))
5017                    {
5018                        // another non-melee non-delayed spell is casted now, abort
5019                        m_Spell->cancel();
5020                    }
5021                    else
5022                    {
5023                        // do the action (pass spell to channeling state)
5024                        m_Spell->handle_immediate();
5025                    }
5026                    // event will be re-added automatically at the end of routine)
5027                }
5028                else
5029                {
5030                    // run the spell handler and think about what we can do next
5031                    uint64 t_offset = e_time - m_Spell->GetDelayStart();
5032                    uint64 n_offset = m_Spell->handle_delayed(t_offset);
5033                    if (n_offset)
5034                    {
5035                        // re-add us to the queue
5036                        m_Spell->GetCaster()->m_Events.AddEvent(this, m_Spell->GetDelayStart() + n_offset, false);
5037                        return(false);                      // event not complete
5038                    }
5039                    // event complete
5040                    // finish update event will be re-added automatically at the end of routine)
5041                }
5042            }
5043            else
5044            {
5045                // delaying had just started, record the moment
5046                m_Spell->SetDelayStart(e_time);
5047                // re-plan the event for the delay moment
5048                m_Spell->GetCaster()->m_Events.AddEvent(this, e_time + m_Spell->GetDelayMoment(), false);
5049                return(false);                              // event not complete
5050            }
5051        } break;
5052
5053        default:
5054        {
5055            // all other states
5056            // event will be re-added automatically at the end of routine)
5057        } break;
5058    }
5059
5060    // spell processing not complete, plan event on the next update interval
5061    m_Spell->GetCaster()->m_Events.AddEvent(this, e_time + 1, false);
5062    return(false);                                          // event not complete
5063}
5064
5065void SpellEvent::Abort(uint64 /*e_time*/)
5066{
5067    // oops, the spell we try to do is aborted
5068    if (m_Spell->getState() != SPELL_STATE_FINISHED)
5069        m_Spell->cancel();
5070}
Note: See TracBrowser for help on using the browser.