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

Revision 122, 193.2 kB (checked in by yumileroy, 17 years ago)

[svn] Fix a compile error about M_PI_2.
Update Felmyst script to test new setActive function.
Fix the bug that priest's fear is unbreakable (dirty hack before find the correct way).
(some unfinished unused content included, just ignore them, will finish them later)

Original author: megamage
Date: 2008-10-27 10:57:53-05:00

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