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

Revision 138, 193.9 kB (checked in by yumileroy, 17 years ago)

[svn] Enable linked spells: cast spells/remove auras when spells casted/spells hitting/auras removed. Add new table "spell_linked_spell". Some illustrations provided in sql.
Let trigger creature cast AOE spells when summoned. Illustration provided in sql.
Let active creatures always visible if possible. (seems does not work for now, need to find out why)

Original author: megamage
Date: 2008-10-30 11:32:10-05:00

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