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

Revision 108, 192.2 kB (checked in by yumileroy, 17 years ago)

[svn] Continue the work of rewriting spell target selection functions (warning: this may cause some spells broken).
Add some spell_script_target.
Delete some workaround in scripts (since core provides spell support now).

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