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

Revision 145, 195.9 kB (checked in by yumileroy, 17 years ago)

[svn] Add function GameObject::CastSpell?. Used for hunter's trap and so.
Use original caster instead caster to check spell hit result.
Let spell triggers have the same faction as the summoner.
Fix the bug that trigger creatures attack enemy. (no need use civilian extra flag in the future, 128 is enough)
Fix shadow step.

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