[3154] - Applied MaNGOS coding style (see trunk/bcpp.cfg).
[mangos-git.git] / src / game / Spell.cpp
blob23e0dac96cec76f2fc5685e085914525a1beab42
1 /*
2 * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "Database/DatabaseEnv.h"
21 #include "WorldPacket.h"
22 #include "WorldSession.h"
23 #include "GridNotifiers.h"
24 #include "GridNotifiersImpl.h"
25 #include "Opcodes.h"
26 #include "Log.h"
27 #include "UpdateMask.h"
28 #include "World.h"
29 #include "ObjectMgr.h"
30 #include "Player.h"
31 #include "Pet.h"
32 #include "Unit.h"
33 #include "Spell.h"
34 #include "DynamicObject.h"
35 #include "SpellAuras.h"
36 #include "Group.h"
37 #include "UpdateData.h"
38 #include "MapManager.h"
39 #include "ObjectAccessor.h"
40 #include "RedZoneDistrict.h"
41 #include "CellImpl.h"
42 #include "Policies/SingletonImp.h"
43 #include "SharedDefines.h"
44 #include "Tools.h"
46 #define SPELL_CHANNEL_UPDATE_INTERVAL 1000
48 extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
50 bool IsQuestTameSpell(uint32 spellId)
52 SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
53 if (!spellproto) return false;
55 return spellproto->Effect[0] == SPELL_EFFECT_THREAT
56 && spellproto->Effect[1] == SPELL_EFFECT_APPLY_AURA && spellproto->EffectApplyAuraName[1] == SPELL_AURA_DUMMY;
59 SpellCastTargets::SpellCastTargets()
61 m_unitTarget = NULL;
62 m_itemTarget = NULL;
63 m_GOTarget = NULL;
64 m_srcX = m_srcY = m_srcZ = m_destX = m_destY = m_destZ = 0;
65 m_strTarget = "";
66 m_targetMask = 0;
69 SpellCastTargets::~SpellCastTargets()
72 void SpellCastTargets::read ( WorldPacket * data,Unit *caster )
75 *data >> m_targetMask;
77 if(m_targetMask == TARGET_FLAG_SELF)
79 m_destX = caster->GetPositionX();
80 m_destY = caster->GetPositionY();
81 m_destZ = caster->GetPositionZ();
82 m_unitTarget = caster;
83 return;
86 if(m_targetMask & TARGET_FLAG_UNIT)
87 m_unitTarget = ObjectAccessor::Instance().GetUnit(*caster, readGUID(*data));
89 if(m_targetMask & TARGET_FLAG_OBJECT)
90 m_GOTarget = ObjectAccessor::Instance().GetGameObject(*caster, readGUID(*data));
92 if((m_targetMask & TARGET_FLAG_ITEM) && caster->GetTypeId() == TYPEID_PLAYER)
94 uint64 _guid = readGUID(*data);
95 m_itemTarget = ((Player*)caster)->GetItemByPos( ((Player*)caster)->GetPosByGuid(_guid));
96 if (!m_itemTarget)
98 Player* pTrader = ((Player*)caster)->GetTrader();
99 if(pTrader)
100 m_itemTarget = pTrader->GetItemByPos(pTrader->GetPosByGuid(_guid));
104 if(m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
105 *data >> m_srcX >> m_srcY >> m_srcZ;
107 if(m_targetMask & TARGET_FLAG_DEST_LOCATION)
108 *data >> m_destX >> m_destY >> m_destZ;
110 if(m_targetMask & TARGET_FLAG_STRING)
111 *data >> m_strTarget;
112 if(m_targetMask & 0x8000)
114 //0x8000 TARGET_CORPSE NEED TO ADD
118 void SpellCastTargets::write ( WorldPacket * data, bool forceAppend)
120 uint32 len = data->size();
122 // dont append targets when spell's for your own..
123 /*if(m_targetMask == TARGET_FLAG_SELF)
124 *data << (m_unitTarget ? m_unitTarget->GetGUID(): (uint64)0);*/
126 if(m_targetMask & TARGET_FLAG_UNIT)
127 if(m_unitTarget)
128 data->append(m_unitTarget->GetPackGUID());
129 else
130 *data << (uint8)0;
132 if(m_targetMask & TARGET_FLAG_OBJECT)
133 if(m_GOTarget)
134 data->append(m_GOTarget->GetPackGUID());
135 else
136 *data << (uint8)0;
138 if(m_targetMask & TARGET_FLAG_ITEM)
139 if(m_itemTarget)
140 data->append(m_itemTarget->GetPackGUID());
141 else
142 *data << (uint8)0;
144 if(m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
145 *data << m_srcX << m_srcY << m_srcZ;
147 if(m_targetMask & TARGET_FLAG_DEST_LOCATION)
148 *data << m_destX << m_destY << m_destZ;
150 if(m_targetMask & TARGET_FLAG_STRING)
151 *data << m_strTarget;
152 if(m_targetMask & 0x8000)
154 //0x8000 TARGET_CORPSE NEED TO ADD
157 if(forceAppend && data->size() == len)
158 *data << (uint8)0;
161 Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, Aura* Aur )
163 ASSERT( Caster != NULL && info != NULL );
165 Player* p_caster;
167 // make own copy of custom `info` (`info` can be created at stack)
168 // copy custom SpellEntry in m_spellInfo will be delete at Spell delete
169 if(info != sSpellStore.LookupEntry( info->Id ))
171 SpellEntry* sInfo = new SpellEntry;
172 *sInfo = *info;
173 m_spellInfo = sInfo;
175 else
176 m_spellInfo = info;
178 m_caster = Caster;
180 m_spellState = SPELL_STATE_NULL;
182 m_castPositionX = m_castPositionY = m_castPositionZ = 0;
183 m_TriggerSpell.clear();
184 m_targetCount = 0;
185 m_IsTriggeredSpell = triggered;
186 //m_AreaAura = false;
187 m_CastItem = NULL;
189 unitTarget = NULL;
190 itemTarget = NULL;
191 gameObjTarget = NULL;
192 focusObject = NULL;
194 m_triggeredByAura = Aur;
195 m_autoRepeat = false;
196 if( m_spellInfo->AttributesEx2 == 0x000020 ) //Auto Shot & Shoot
197 m_autoRepeat = true;
199 casttime = GetCastTime(sCastTimesStore.LookupEntry(m_spellInfo->CastingTimeIndex));
201 if( m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo )
203 p_caster = ((Player*)m_caster);
204 ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id, SPELLMOD_CASTING_TIME, casttime);
205 casttime = int32(casttime/(100+p_caster->m_modCastSpeedPct)*100);
208 m_timer = casttime<0?0:casttime;
210 for(int i=0;i<3;i++)
211 m_needAliveTarget[i] = false;
213 m_meleeSpell = false;
215 m_rangedShoot = ((m_spellInfo->Attributes & 18) == 18);
216 if( m_spellInfo->StartRecoveryTime == 0 && !m_autoRepeat && !m_rangedShoot )
218 for (int i = 0; i < 3; i++)
220 if (m_spellInfo->Effect[i]==SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL ||
221 m_spellInfo->Effect[i]==SPELL_EFFECT_WEAPON_DAMAGE)
223 m_meleeSpell = true;
224 break;
230 Spell::~Spell()
232 // free custom m_spellInfo
233 if(m_spellInfo != sSpellStore.LookupEntry(m_spellInfo->Id))
234 delete m_spellInfo;
237 void Spell::FillTargetMap()
239 // TODO: ADD the correct target FILLS!!!!!!
241 std::list<Unit*> tmpUnitMap;
242 std::list<Item*> tmpItemMap;
243 std::list<GameObject*> tmpGOMap;
245 for(uint32 i=0;i<3;i++)
247 SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap,tmpItemMap,tmpGOMap);
248 SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap,tmpItemMap,tmpGOMap);
250 if(!m_spellInfo->EffectImplicitTargetA[i] && !m_spellInfo->EffectImplicitTargetB[i] )
252 // add here custom effects that need default target.
253 // FOR EVERY TARGET TYPE THERE IS A DIFFERENT FILL!!
254 switch(m_spellInfo->Effect[i])
256 //case SPELL_EFFECT_PERSISTENT_AREA_AURA:
257 case SPELL_EFFECT_RESURRECT:
258 case SPELL_EFFECT_LEARN_SPELL:
259 case SPELL_EFFECT_SKILL_STEP:
260 case SPELL_EFFECT_SELF_RESURRECT:
261 case SPELL_EFFECT_RESURRECT_NEW:
262 case SPELL_EFFECT_PROFICIENCY:
263 case SPELL_EFFECT_PARRY:
264 case SPELL_EFFECT_DUMMY:
265 if(m_targets.getUnitTarget())
266 tmpUnitMap.push_back(m_targets.getUnitTarget());
267 break;
268 case SPELL_EFFECT_FEED_PET:
269 if(m_targets.m_itemTarget)
270 tmpItemMap.push_back(m_targets.m_itemTarget);
271 break;
272 case SPELL_EFFECT_SKILL:
273 case SPELL_EFFECT_SUMMON_CHANGE_ITEM:
274 tmpUnitMap.push_back(m_caster);
275 break;
276 case SPELL_EFFECT_LEARN_PET_SPELL:
277 if(Pet* pet = m_caster->GetPet())
278 tmpUnitMap.push_back(pet);
279 break;
280 case SPELL_EFFECT_DISENCHANT:
281 case SPELL_EFFECT_ENCHANT_ITEM:
282 case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY:
283 case SPELL_EFFECT_ENCHANT_HELD_ITEM:
284 tmpItemMap.push_back(itemTarget);
285 break;
286 case SPELL_EFFECT_APPLY_AREA_AURA:
287 if(m_spellInfo->Attributes == 0x9050000)// AreaAura
288 SetTargetMap(i,TARGET_AREAEFFECT_PARTY,tmpUnitMap,tmpItemMap,tmpGOMap);
289 break;
290 default:
291 break;
294 if(IsChanneledSpell() && !tmpUnitMap.empty())
295 m_needAliveTarget[i] = true;
297 if(m_caster->GetTypeId() == TYPEID_PLAYER && (!m_caster->IsPvP() || ((Player*)m_caster)->pvpInfo.endTimer != 0))
299 Player *me = (Player*)m_caster;
300 for (std::list<Unit*>::const_iterator itr = tmpUnitMap.begin(); itr != tmpUnitMap.end(); itr++)
302 Unit *owner = (*itr)->GetOwner();
303 Unit *u = owner ? owner : (*itr);
304 if(u->IsPvP() && (!me->duel || me->duel->opponent != u))
305 me->UpdatePvP(true);
309 //Check targets for immune and remove immuned targets
310 for (std::list<Unit*>::iterator itr = tmpUnitMap.begin() ; itr != tmpUnitMap.end();)
312 if ((*itr)->IsImmunedToSpell(m_spellInfo))
313 itr = tmpUnitMap.erase(itr);
314 else
315 ++itr;
318 m_targetUnitGUIDs[i].clear();
319 for(std::list<Unit*>::iterator iunit= tmpUnitMap.begin();iunit != tmpUnitMap.end();++iunit)
320 m_targetUnitGUIDs[i].push_back((*iunit)->GetGUID());
322 m_targetItems[i] = tmpItemMap;
323 m_targetGOs[i] = tmpGOMap;
325 tmpUnitMap.clear();
326 tmpItemMap.clear();
327 tmpGOMap.clear();
331 void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap,std::list<Item*> &TagItemMap,std::list<GameObject*> &TagGOMap)
333 float radius = GetRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
334 switch(cur)
336 case TARGET_TOTEM_EARTH:
337 case TARGET_TOTEM_WATER:
338 case TARGET_TOTEM_AIR:
339 case TARGET_TOTEM_FIRE:
340 case TARGET_SELF:
341 case TARGET_DYNAMIC_OBJECT:
343 TagUnitMap.push_back(m_caster);
344 }break;
345 case TARGET_PET:
347 Pet* tmpUnit = m_caster->GetPet();
348 if (!tmpUnit) break;
349 TagUnitMap.push_back(tmpUnit);
350 }break;
351 case TARGET_SINGLE_ENEMY:
353 Unit* pUnitTarget = m_targets.getUnitTarget();
354 if(!pUnitTarget)
355 break;
356 TagUnitMap.push_back(pUnitTarget);
357 if (m_spellInfo->EffectChainTarget[i])
359 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
360 Cell cell = RedZone::GetZone(p);
361 cell.data.Part.reserved = ALL_DISTRICT;
362 cell.SetNoCreate();
364 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(pUnitTarget, m_caster, radius ? radius : 5);
365 MaNGOS::UnitListSearcher<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck> searcher(TagUnitMap, u_check);
367 TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck>, TypeMapContainer<AllObjectTypes> > unit_searcher(searcher);
368 CellLock<GridReadGuard> cell_lock(cell, p);
369 cell_lock->Visit(cell_lock, unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId()));
371 }break;
372 case TARGET_ALL_ENEMY_IN_AREA:
374 }break;
375 case TARGET_ALL_ENEMY_IN_AREA_INSTANT:
377 // targets the ground, not the units in the area
378 if (m_spellInfo->Effect[i]!=SPELL_EFFECT_PERSISTENT_AREA_AURA)
380 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
381 Cell cell = RedZone::GetZone(p);
382 cell.data.Part.reserved = ALL_DISTRICT;
383 cell.SetNoCreate();
385 MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, i, PUSH_DEST_CENTER);
387 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, ContainerMapList<Player> > player_notifier(notifier);
388 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, TypeMapContainer<AllObjectTypes> > object_notifier(notifier);
390 CellLock<GridReadGuard> cell_lock(cell, p);
391 cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
392 cell_lock->Visit(cell_lock, object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
394 }break;
395 case TARGET_ALL_PARTY_AROUND_CASTER:
397 Group* pGroup = m_caster->GetTypeId() == TYPEID_PLAYER ? ((Player*)m_caster)->groupInfo.group : NULL;
398 if(pGroup)
400 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
402 if(!pGroup->SameSubGroup(m_caster->GetGUID(), pGroup->GetMemberGUID(p)))
403 continue;
405 Unit* Target = objmgr.GetPlayer(pGroup->GetMemberGUID(p));
406 if(!Target)
407 continue;
408 if(m_caster->IsWithinDist(Target, radius))
409 TagUnitMap.push_back(Target);
412 else
413 TagUnitMap.push_back(m_caster);
414 }break;
415 case TARGET_SINGLE_FRIEND:
416 case TARGET_SINGLE_FRIEND_2:
418 if(m_targets.getUnitTarget())
419 TagUnitMap.push_back(m_targets.getUnitTarget());
420 }break;
421 case TARGET_ALL_ENEMIES_AROUND_CASTER:
423 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
424 Cell cell = RedZone::GetZone(p);
425 cell.data.Part.reserved = ALL_DISTRICT;
426 cell.SetNoCreate();
428 MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, i, PUSH_SELF_CENTER);
430 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, ContainerMapList<Player> > player_notifier(notifier);
431 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, TypeMapContainer<AllObjectTypes> > object_notifier(notifier);
433 CellLock<GridReadGuard> cell_lock(cell, p);
434 cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
435 cell_lock->Visit(cell_lock, object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
436 }break;
437 case TARGET_GAMEOBJECT:
439 if(m_targets.m_GOTarget)
440 TagGOMap.push_back(m_targets.m_GOTarget);
441 }break;
442 case TARGET_IN_FRONT_OF_CASTER:
444 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
445 Cell cell = RedZone::GetZone(p);
446 cell.data.Part.reserved = ALL_DISTRICT;
447 cell.SetNoCreate();
449 MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, i, PUSH_IN_FRONT);
451 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, ContainerMapList<Player> > player_notifier(notifier);
452 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, TypeMapContainer<AllObjectTypes> > object_notifier(notifier);
454 CellLock<GridReadGuard> cell_lock(cell, p);
455 cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
456 cell_lock->Visit(cell_lock, object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
457 }break;
458 case TARGET_DUELVSPLAYER:
460 if(m_targets.getUnitTarget())
461 TagUnitMap.push_back(m_targets.getUnitTarget());
462 }break;
463 case TARGET_GAMEOBJECT_ITEM:
465 if(m_targets.m_GOTarget)
466 TagGOMap.push_back(m_targets.m_GOTarget);
467 else if(m_targets.m_itemTarget)
468 TagItemMap.push_back(m_targets.m_itemTarget);
469 }break;
470 case TARGET_ALL_ENEMY_IN_AREA_CHANNELED:
472 // targets the ground, not the units in the area
473 if (m_spellInfo->Effect[i]!=SPELL_EFFECT_PERSISTENT_AREA_AURA)
475 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
476 Cell cell = RedZone::GetZone(p);
477 cell.data.Part.reserved = ALL_DISTRICT;
478 cell.SetNoCreate();
480 MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, i, PUSH_DEST_CENTER);
482 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, ContainerMapList<Player> > player_notifier(notifier);
483 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, TypeMapContainer<AllObjectTypes> > object_notifier(notifier);
485 CellLock<GridReadGuard> cell_lock(cell, p);
486 cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
487 cell_lock->Visit(cell_lock, object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
489 }break;
490 case TARGET_MINION:
492 if(m_spellInfo->Effect[i] != 83) TagUnitMap.push_back(m_caster);
493 }break;
494 case TARGET_SINGLE_PARTY:
496 if(m_targets.getUnitTarget())
497 TagUnitMap.push_back(m_targets.getUnitTarget());
498 }break;
499 case TARGET_AREAEFFECT_PARTY:
501 Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER
502 ? (Player*)m_targets.getUnitTarget() : NULL;
504 Group* pGroup = targetPlayer ? targetPlayer->groupInfo.group : NULL;
505 if(pGroup)
507 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
509 if(!pGroup->SameSubGroup(m_caster->GetGUID(), pGroup->GetMemberGUID(p)))
510 continue;
512 Unit* Target = objmgr.GetPlayer(pGroup->GetMemberGUID(p));
513 if(m_targets.getUnitTarget() && Target && m_targets.getUnitTarget()->IsWithinDist(Target, radius) )
514 TagUnitMap.push_back(Target);
517 else if(m_targets.getUnitTarget())
518 TagUnitMap.push_back(m_targets.getUnitTarget());
519 }break;
520 case TARGET_SELF_FISHING:
522 TagUnitMap.push_back(m_caster);
523 }break;
524 case TARGET_CHAIN:
526 if(!m_targets.getUnitTarget())
527 break;
529 Group* pGroup = m_caster->GetTypeId() == TYPEID_PLAYER ? ((Player*)m_caster)->groupInfo.group : NULL;
530 if(pGroup)
532 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
534 if(!pGroup->SameSubGroup(m_caster->GetGUID(), pGroup->GetMemberGUID(p)))
535 continue;
537 Unit* Target = objmgr.GetPlayer(pGroup->GetMemberGUID(p));
539 if(!Target || Target->GetGUID() == m_caster->GetGUID())
540 continue;
541 if(m_caster->IsWithinDist(Target, radius))
542 TagUnitMap.push_back(Target);
545 else if(m_targets.getUnitTarget())
546 TagUnitMap.push_back(m_targets.getUnitTarget());
547 }break;
548 case TARGET_CURRENT_SELECTED_ENEMY:
550 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
551 Cell cell = RedZone::GetZone(p);
552 cell.data.Part.reserved = ALL_DISTRICT;
553 cell.SetNoCreate();
554 MaNGOS::SpellNotifierPlayer notifier(*this, TagUnitMap, i);
555 TypeContainerVisitor<MaNGOS::SpellNotifierPlayer, ContainerMapList<Player> > player_notifier(notifier);
556 CellLock<GridReadGuard> cell_lock(cell, p);
557 cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
558 }break;
559 default:
561 }break;
562 case TARGET_AREAEFFECT_PARTY_AND_CLASS:
564 Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER
565 ? (Player*)m_targets.getUnitTarget() : NULL;
567 Group* pGroup = targetPlayer ? targetPlayer->groupInfo.group : NULL;
568 if(pGroup)
570 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
572 if(!pGroup->SameSubGroup(m_caster->GetGUID(), pGroup->GetMemberGUID(p)))
573 continue;
575 Unit* Target = objmgr.GetPlayer(pGroup->GetMemberGUID(p));
576 if(Target && targetPlayer->IsWithinDist(Target, radius) &&
577 targetPlayer->getClass() == Target->getClass())
578 TagUnitMap.push_back(Target);
581 else if(m_targets.getUnitTarget())
582 TagUnitMap.push_back(m_targets.getUnitTarget());
583 }break;
586 uint32 unMaxTargets = 0;
587 if(m_spellInfo->MaxAffectedTargets == 0 && m_spellInfo->EffectChainTarget[i] == 0)
588 unMaxTargets = 0; //no limits
589 else if(m_spellInfo->MaxAffectedTargets == 0 && m_spellInfo->EffectChainTarget[i] != 0)
590 //selected enemy also
591 unMaxTargets = m_spellInfo->EffectChainTarget[i] + 1;
592 else if (m_spellInfo->MaxAffectedTargets != 0 && m_spellInfo->EffectChainTarget[i] != 0)
593 unMaxTargets = m_spellInfo->MaxAffectedTargets; //Unknown such spells;
595 if (m_spellInfo->EffectChainTarget[i] != 0 || (unMaxTargets != 0 && TagUnitMap.size() > unMaxTargets))
597 // make sure one unit is always removed per iteration
598 uint32 removed_utarget = 0;
599 for (std::list<Unit*>::iterator itr = TagUnitMap.begin(), next; itr != TagUnitMap.end(); itr = next)
601 next = itr;
602 next++;
603 if (!*itr) continue;
604 if ((*itr) == m_targets.getUnitTarget())
606 TagUnitMap.erase(itr);
607 removed_utarget = 1;
608 // break;
611 // remove random units from the map
612 while (TagUnitMap.size() > unMaxTargets - removed_utarget)
614 uint32 poz = urand(0, TagUnitMap.size()-1);
615 for (std::list<Unit*>::iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end(); ++itr, --poz)
617 if (!*itr) continue;
618 if (!poz)
620 TagUnitMap.erase(itr);
621 break;
625 // the player's target will always be added to the map
626 if (removed_utarget && m_targets.getUnitTarget())
627 TagUnitMap.push_back(m_targets.getUnitTarget());
631 void Spell::prepare(SpellCastTargets * targets)
633 m_targets = *targets;
634 if(!unitTarget)
635 unitTarget = m_targets.getUnitTarget();
636 if(!itemTarget)
637 itemTarget = m_targets.m_itemTarget;
638 if(!gameObjTarget)
639 gameObjTarget = m_targets.m_GOTarget;
641 m_spellState = SPELL_STATE_PREPARING;
643 m_castPositionX = m_caster->GetPositionX();
644 m_castPositionY = m_caster->GetPositionY();
645 m_castPositionZ = m_caster->GetPositionZ();
646 m_castOrientation = m_caster->GetOrientation();
648 uint8 result = CanCast();
649 if(result != 0)
651 if(m_triggeredByAura)
653 SendChannelUpdate(0);
654 m_triggeredByAura->SetAuraDuration(0);
656 SendCastResult(result);
657 finish(false);
658 return;
661 // stealth must be removed at cast starting (at show channel bar)
662 // skip trigered spell (item equip spell casting and other not explicit character casts/item uses)
663 if ( !m_IsTriggeredSpell && !CanUsedWhileStealthed(m_spellInfo->Id) )
664 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
666 // do first cast of autorepeat spell with recovery time delay (like after any authocast)
667 if(IsAutoRepeat())
668 m_spellState = SPELL_STATE_FINISHED;
670 if(m_IsTriggeredSpell)
671 cast(true);
672 else
674 m_caster->castSpell( this );
675 SendSpellStart();
679 void Spell::cancel()
681 if(m_spellState == SPELL_STATE_FINISHED)
682 return;
684 m_autoRepeat = false;
685 if(m_spellState == SPELL_STATE_PREPARING)
687 SendInterrupted(0);
688 SendCastResult(CAST_FAIL_INTERRUPTED);
690 else if(m_spellState == SPELL_STATE_CASTING)
692 for (int j = 0; j < 3; j++)
694 for(std::list<uint64>::iterator iunit= m_targetUnitGUIDs[j].begin();iunit != m_targetUnitGUIDs[j].end();++iunit)
696 // check m_caster->GetGUID() let load auras at login and speedup most often case
697 Unit* unit = m_caster->GetGUID()==*iunit ? m_caster : ObjectAccessor::Instance().GetUnit(*m_caster,*iunit);
698 if (unit && unit->isAlive())
699 unit->RemoveAurasDueToSpell(m_spellInfo->Id);
703 m_caster->RemoveAurasDueToSpell(m_spellInfo->Id);
704 SendChannelUpdate(0);
705 SendInterrupted(0);
706 SendCastResult(CAST_FAIL_INTERRUPTED);
709 finish(false);
710 m_caster->RemoveDynObject(m_spellInfo->Id);
711 m_caster->RemoveGameObject(m_spellInfo->Id,true);
714 void Spell::cast(bool skipCheck)
716 uint32 mana = 0;
717 uint8 castResult = 0;
718 if(m_caster->GetTypeId() != TYPEID_PLAYER && unitTarget)
719 m_caster->SetInFront(unitTarget);
721 castResult = CheckMana( &mana);
722 if(castResult != 0)
724 SendCastResult(castResult);
725 finish(false);
726 return;
729 // triggered cast called from Spell::prepare where it was already checked
730 if(!skipCheck)
732 castResult = CanCast();
733 if(castResult != 0)
735 SendCastResult(castResult);
736 finish(false);
737 return;
741 // CAST SPELL
742 SendSpellCooldown();
744 TakePower(mana);
745 TakeCastItem();
746 TakeReagents();
747 FillTargetMap();
748 SendCastResult(castResult);
749 SendSpellGo();
751 if(IsChanneledSpell())
753 m_spellState = SPELL_STATE_CASTING;
754 SendChannelStart(GetDuration(m_spellInfo));
757 // Pass cast spell event to handler
758 if (m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED)
759 m_caster->ProcDamageAndSpell(m_caster->getVictim(), PROC_FLAG_CAST_SPELL, PROC_FLAG_NONE, 0, m_spellInfo, m_IsTriggeredSpell);
761 HandleThreatSpells(m_spellInfo->Id);
763 std::list<Item*>::iterator iitem;
764 std::list<GameObject*>::iterator igo;
766 bool needspelllog = true;
767 for(uint32 j = 0;j<3;j++)
769 if(m_spellInfo->Effect[j] == SPELL_EFFECT_SEND_EVENT)
771 HandleEffects(NULL,NULL,NULL, j);
772 continue;
774 // Dont do spell log, if is school damage spell
775 if(m_spellInfo->Effect[j] == 2 || m_spellInfo->Effect[j] == 0)
776 needspelllog = false;
777 for(std::list<uint64>::iterator iunit= m_targetUnitGUIDs[j].begin();iunit != m_targetUnitGUIDs[j].end();++iunit)
779 // let the client worry about this
780 /*if((*iunit)->GetTypeId() != TYPEID_PLAYER && m_spellInfo->TargetCreatureType)
782 CreatureInfo const *cinfo = ((Creature*)(*iunit))->GetCreatureInfo();
783 if((m_spellInfo->TargetCreatureType & cinfo->type) == 0)
784 continue;
786 // check m_caster->GetGUID() let load auras at login and speedup most often case
787 Unit* unit = m_caster->GetGUID()==*iunit ? m_caster : ObjectAccessor::Instance().GetUnit(*m_caster,*iunit);
788 if(unit)
789 HandleEffects(unit,NULL,NULL,j);
791 for(iitem= m_targetItems[j].begin();iitem != m_targetItems[j].end();iitem++)
792 HandleEffects(NULL,(*iitem),NULL,j);
793 for(igo= m_targetGOs[j].begin();igo != m_targetGOs[j].end();igo++)
794 HandleEffects(NULL,NULL,(*igo),j);
796 // persistent area auras target only the ground
797 if(m_spellInfo->Effect[j] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
798 HandleEffects(NULL,NULL,NULL, j);
801 if(needspelllog)
802 SendLogExecute();
804 bool canreflect = false;
805 for(int j=0;j<3;j++)
807 switch(m_spellInfo->EffectImplicitTargetA[j])
809 case TARGET_SINGLE_ENEMY:
810 case TARGET_ALL_ENEMY_IN_AREA:
811 case TARGET_ALL_ENEMY_IN_AREA_INSTANT:
812 case TARGET_ALL_ENEMIES_AROUND_CASTER:
813 case TARGET_IN_FRONT_OF_CASTER:
814 case TARGET_DUELVSPLAYER:
815 case TARGET_ALL_ENEMY_IN_AREA_CHANNELED:
816 //case TARGET_AE_SELECTED:
817 canreflect = true;
818 break;
820 default:
821 canreflect = (m_spellInfo->AttributesEx & (1<<7)) ? true : false;
824 if(canreflect)
825 continue;
826 else
827 break;
830 if(canreflect)
832 for(std::list<Unit*>::iterator iunit= UniqueTargets.begin();iunit != UniqueTargets.end();iunit++)
833 reflect(*iunit);
836 if(m_spellState != SPELL_STATE_CASTING)
837 finish(true); // successfully finish spell cast (not last in case autorepeat or channel spell)
840 void Spell::SendSpellCooldown()
842 if(m_caster->GetTypeId() != TYPEID_PLAYER)
843 return;
845 Player* _player = (Player*)m_caster;
847 uint32 cat = m_spellInfo->Category;
848 int32 rec = m_spellInfo->RecoveryTime;
849 int32 catrec = m_spellInfo->CategoryRecoveryTime;
851 // shoot spells used equiped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
852 if (!rec && !catrec && (cat == 76 || cat == 351))
853 rec = _player->GetAttackTime(RANGED_ATTACK);
855 // some special item spells without correct cooldown in SpellInfo
856 // cooldown information stored in item prototype
857 // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client.
858 if( rec == 0 && catrec == 0 && m_CastItem)
860 ItemPrototype const* proto = m_CastItem->GetProto();
861 if(proto)
863 for(int idx = 0; idx < 5; ++idx)
865 if(proto->Spells[idx].SpellId == m_spellInfo->Id)
867 cat = proto->Spells[idx].SpellCategory;
868 rec = proto->Spells[idx].SpellCooldown;
869 catrec = proto->Spells[idx].SpellCategoryCooldown;
870 break;
876 if(rec > 0)
877 _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, rec);
879 if(catrec > 0)
880 _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, catrec);
882 if (rec < 0) rec = 0;
883 if (catrec < 0) catrec = 0;
885 // no cooldown after applying spell mods
886 if( rec == 0 && catrec == 0)
887 return;
889 time_t curTime = time(NULL);
891 time_t recTime = curTime+rec/1000; // in secs
892 time_t catrecTime = curTime+catrec/1000; // in secs
894 WorldPacket data(SMSG_SPELL_COOLDOWN, (8+4+4+4+4));
895 data << m_caster->GetGUID();
897 // self spell cooldown
898 if (rec > 0)
900 data << uint32(m_spellInfo->Id);
901 data << uint32(rec);
902 _player->AddSpellCooldown(m_spellInfo->Id,recTime);
904 else
906 data << uint32(m_spellInfo->Id);
907 data << uint32(catrec);
908 _player->AddSpellCooldown(m_spellInfo->Id,catrecTime);
911 if (catrec > 0)
913 PlayerSpellMap const& player_spells = _player->GetSpellMap();
914 for (PlayerSpellMap::const_iterator itr = player_spells.begin(); itr != player_spells.end(); ++itr)
916 if(m_spellInfo->Id==itr->first)
917 continue;
919 if(itr->second->state == PLAYERSPELL_REMOVED || !itr->second->active)
920 continue;
922 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
923 if( spellInfo->Category == cat)
925 data << uint32(itr->first);
926 data << uint32(catrec);
927 _player->AddSpellCooldown(itr->first,catrecTime);
932 _player->GetSession()->SendPacket(&data);
934 // show cooldown for item
935 if(m_CastItem)
937 data.Initialize(SMSG_ITEM_COOLDOWN, (8+4));
938 data << m_CastItem->GetGUID();
939 data << uint32(m_spellInfo->Id);
940 _player->GetSession()->SendPacket(&data);
944 void Spell::update(uint32 difftime)
946 if(unitTarget && !unitTarget->isAlive())
948 if(m_autoRepeat)
950 m_autoRepeat = false;
951 m_spellState = SPELL_STATE_FINISHED;
952 return;
956 // check if the player caster has moved before the spell finished
957 if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) &&
958 (m_castPositionX != m_caster->GetPositionX() || m_castPositionY != m_caster->GetPositionY() || m_castPositionZ != m_caster->GetPositionZ()))
960 // always cancel for channeled spells
961 if( m_spellState == SPELL_STATE_CASTING )
962 cancel();
963 // don't cancel for instant and melee spells
964 else if(!m_meleeSpell && casttime != 0)
965 cancel();
968 switch(m_spellState)
970 case SPELL_STATE_PREPARING:
972 if(m_timer)
974 if(difftime >= m_timer)
975 m_timer = 0;
976 else
977 m_timer -= difftime;
980 if(m_timer == 0 && !m_meleeSpell)
981 cast();
982 } break;
983 case SPELL_STATE_CASTING:
985 if(m_timer > 0)
987 if( m_caster->GetTypeId() == TYPEID_PLAYER )
989 // check if player has jumped before the channeling finished
990 if( ((Player*)m_caster)->HasMovementFlags(MOVEMENTFLAG_JUMPING) )
991 cancel();
993 // check for incapacitating player states
994 if( m_caster->hasUnitState(UNIT_STAT_STUNDED) ||
995 m_caster->hasUnitState(UNIT_STAT_ROOT) ||
996 m_caster->hasUnitState(UNIT_STAT_CONFUSED) )
997 cancel();
999 // check if player has turned if flag is set
1000 if( m_spellInfo->ChannelInterruptFlags & CHANNEL_FLAG_TURNING && m_castOrientation != m_caster->GetOrientation() )
1001 cancel();
1004 // check if there are alive targets left
1005 for(int i=0;i<3;i++)
1007 if(m_needAliveTarget[i])
1009 bool targetLeft = false;
1010 for(std::list<uint64>::iterator iunit= m_targetUnitGUIDs[i].begin();iunit != m_targetUnitGUIDs[i].end();++iunit)
1012 // check m_caster->GetGUID() let load auras at login and speedup most often case
1013 Unit* unit = m_caster->GetGUID()==*iunit ? m_caster : ObjectAccessor::Instance().GetUnit(*m_caster,*iunit);
1014 if(unit && unit->isAlive())
1016 targetLeft = true;
1017 break;
1019 if(!targetLeft)
1020 cancel();
1025 if(difftime >= m_timer)
1026 m_timer = 0;
1027 else
1028 m_timer -= difftime;
1031 if(m_timer == 0)
1033 SendChannelUpdate(0);
1034 finish();
1036 } break;
1037 default:
1039 }break;
1043 void Spell::finish(bool ok)
1046 if(!m_caster) return;
1048 if(m_spellState == SPELL_STATE_FINISHED)
1049 return;
1051 m_spellState = SPELL_STATE_FINISHED;
1052 m_caster->m_canMove = true;
1054 /*std::vector<DynamicObject*>::iterator i;
1055 for(i = m_dynObjToDel.begin() ; i != m_dynObjToDel.end() ; i++)
1057 data.Initialize(SMSG_GAMEOBJECT_DESPAWN_ANIM);
1058 data << (*i)->GetGUID();
1059 m_caster->SendMessageToSet(&data, true);
1061 data.Initialize(SMSG_DESTROY_OBJECT);
1062 data << (*i)->GetGUID();
1063 m_caster->SendMessageToSet(&data, true);
1064 ObjectAccessor::Instance().AddObjectToRemoveList(*i);
1065 m_AreaAura = false;
1067 m_dynObjToDel.clear();
1069 std::list<GameObject*>::iterator k;
1070 for(k = m_ObjToDel.begin() ; k != m_ObjToDel.end() ; k++)
1072 data.Initialize(SMSG_GAMEOBJECT_DESPAWN_ANIM);
1073 data << (*k)->GetGUID();
1074 m_caster->SendMessageToSet(&data, true);
1076 data.Initialize(SMSG_DESTROY_OBJECT);
1077 data << (*k)->GetGUID();
1078 m_caster->SendMessageToSet(&data, true);
1079 ObjectAccessor::Instance().AddObjectToRemoveList(*k);
1082 m_ObjToDel.clear();*/
1084 // cast at creature (or GO) quest objectives update at succesful cast finished (+channel finished)
1085 // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... )
1086 if( ok && m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsMeleeSpell() && !IsChannelActive() )
1088 if( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1090 ((Player*)m_caster)->CastedCreatureOrGO(unitTarget->GetEntry(),unitTarget->GetGUID(),m_spellInfo->Id);
1093 if( gameObjTarget )
1095 ((Player*)m_caster)->CastedCreatureOrGO(gameObjTarget->GetEntry(),gameObjTarget->GetGUID(),m_spellInfo->Id);
1099 // call triggered spell only at successful cast
1100 if(ok && m_TriggerSpell.size() > 0)
1101 TriggerSpell();
1104 void Spell::SendCastResult(uint8 result)
1106 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1107 return;
1109 WorldPacket data(SMSG_CAST_RESULT, (4+2));
1110 data << m_spellInfo->Id;
1111 if(result != 0)
1113 data << uint8(2); // status = fail
1114 data << uint8(result); // problem
1115 switch (result)
1117 case CAST_FAIL_REQUIRES_XXX:
1118 data << uint32(m_spellInfo->RequiresSpellFocus);
1119 break;
1122 else
1123 data << uint8(0); // status = ok
1125 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1128 void Spell::SendSpellStart()
1130 sLog.outDebug("Sending SMSG_SPELL_START");
1132 m_castFlags = CAST_FLAG_UNKNOWN1;
1133 if(m_rangedShoot)
1134 m_castFlags = m_castFlags | CAST_FLAG_AMMO;
1136 Unit * target;
1137 if(!unitTarget)
1138 target = m_caster;
1139 else
1140 target = unitTarget;
1142 WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2));
1143 //data.append(target->GetPackGUID());
1144 /* in fact this should be the causer's guid. so if you clicked on a item and
1145 this caused spell it has to be the item's guid
1147 data.append(m_caster->GetPackGUID());
1148 data.append(m_caster->GetPackGUID());
1149 data << m_spellInfo->Id;
1150 data << m_castFlags;
1151 data << uint32(m_timer);
1153 data << m_targets.m_targetMask;
1154 m_targets.write( &data );
1155 if( m_castFlags & CAST_FLAG_AMMO )
1157 writeAmmoToPacket(&data);
1159 m_caster->SendMessageToSet(&data, true);
1162 void Spell::SendSpellGo()
1164 sLog.outDebug("Sending SMSG_SPELL_GO");
1166 Unit * target;
1167 if(!unitTarget)
1168 target = m_caster;
1169 else
1170 target = unitTarget;
1172 m_castFlags = CAST_FLAG_UNKNOWN3;
1173 if(m_rangedShoot)
1174 m_castFlags = m_castFlags | CAST_FLAG_AMMO;
1176 WorldPacket data(SMSG_SPELL_GO, (50)); // guess size
1177 //data.append(target->GetPackGUID());
1178 /* in fact this should be the causer's guid. so if you clicked on a item and
1179 this caused spell it has to be the item's guid
1181 data.append(m_caster->GetPackGUID());
1182 data.append(m_caster->GetPackGUID());
1183 data << m_spellInfo->Id;
1185 data << m_castFlags;
1186 writeSpellGoTargets(&data);
1188 data << (uint8)0; // miss count
1190 data << m_targets.m_targetMask;
1191 m_targets.write( &data, true );
1192 if( m_castFlags & CAST_FLAG_AMMO )
1194 writeAmmoToPacket(&data);
1197 m_caster->SendMessageToSet(&data, true);
1200 void Spell::writeAmmoToPacket( WorldPacket * data )
1202 uint32 ammoInventoryType = 0;
1203 uint32 ammoDisplayID = 0;
1204 Item *pItem = ((Player*)m_caster)->GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED );
1205 if(pItem)
1207 ammoInventoryType = pItem->GetProto()->InventoryType;
1208 if( ammoInventoryType == INVTYPE_THROWN )
1209 ammoDisplayID = pItem->GetProto()->DisplayInfoID;
1210 else
1212 uint32 ammoID = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID);
1213 if(ammoID)
1215 ItemPrototype const *pProto = objmgr.GetItemPrototype( ammoID );
1216 if(pProto)
1218 ammoDisplayID = pProto->DisplayInfoID;
1219 ammoInventoryType = pProto->InventoryType;
1224 *data << ammoDisplayID;
1225 *data << ammoInventoryType;
1228 void Spell::writeSpellGoTargets( WorldPacket * data )
1230 bool add = true;
1232 std::list<GameObject*>::iterator m,n;
1234 for(int k=0;k<3;k++)
1236 for(std::list<uint64>::iterator iunit= m_targetUnitGUIDs[k].begin();iunit != m_targetUnitGUIDs[k].end();++iunit)
1238 for(std::list<Unit*>::iterator junit = UniqueTargets.begin(); junit != UniqueTargets.end(); junit++ )
1240 if((*junit)->GetGUID() == (*iunit))
1242 add = false;
1243 break;
1247 // check m_caster->GetGUID() let load auras at login and speedup most often case
1248 Unit* unit = m_caster->GetGUID()==*iunit ? m_caster : ObjectAccessor::Instance().GetUnit(*m_caster,*iunit);
1249 if(unit && add)
1250 UniqueTargets.push_back(unit);
1251 add = true;
1253 for ( m = m_targetGOs[k].begin(); m != m_targetGOs[k].end(); m++ )
1255 for(n = UniqueGOsTargets.begin(); n != UniqueGOsTargets.end(); n++ )
1257 if((*n) == (*m))
1259 add = false;
1260 break;
1263 if(*m && add)
1264 UniqueGOsTargets.push_back(*m);
1265 add = true;
1269 m_targetCount = UniqueTargets.size() + UniqueGOsTargets.size();
1270 *data << m_targetCount;
1272 for ( std::list<Unit*>::iterator ui = UniqueTargets.begin(); ui != UniqueTargets.end(); ui++ )
1273 *data << (*ui)->GetGUID();
1275 for ( std::list<GameObject*>::iterator uj = UniqueGOsTargets.begin(); uj != UniqueGOsTargets.end(); uj++ )
1276 *data << (*uj)->GetGUID();
1280 void Spell::SendLogExecute()
1282 Unit * target;
1283 if(!unitTarget)
1284 target = m_caster;
1285 else
1286 target = unitTarget;
1287 WorldPacket data(SMSG_SPELLLOGEXECUTE, (8+4+4+4+4+8));
1289 if(m_caster->GetTypeId() == TYPEID_PLAYER)
1290 data.append(m_caster->GetPackGUID());
1291 else
1292 data.append(target->GetPackGUID());
1294 data << m_spellInfo->Id;
1295 data << uint32(1);
1296 data << m_spellInfo->SpellVisual;
1297 data << uint32(1);
1299 if(m_targets.getUnitTarget())
1300 data << m_targets.getUnitTarget()->GetGUID();
1301 else if(m_targets.m_itemTarget)
1302 data << m_targets.m_itemTarget->GetGUID();
1303 else if(m_targets.m_GOTarget)
1304 data << m_targets.m_GOTarget->GetGUID();
1306 m_caster->SendMessageToSet(&data,true);
1309 void Spell::SendInterrupted(uint8 result)
1311 WorldPacket data;
1313 data.Initialize(SMSG_SPELL_FAILURE, (8+4+1));
1314 data.append(m_caster->GetGUID());
1315 data << m_spellInfo->Id;
1316 data << result;
1317 m_caster->SendMessageToSet(&data, true);
1319 data.Initialize(SMSG_SPELL_FAILED_OTHER, (8+4));
1320 data.append(m_caster->GetGUID());
1321 data << m_spellInfo->Id;
1322 m_caster->SendMessageToSet(&data, true);
1325 void Spell::SendChannelUpdate(uint32 time)
1327 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1328 return;
1330 WorldPacket data( MSG_CHANNEL_UPDATE, 4 );
1331 data << time;
1333 ((Player*)m_caster)->GetSession()->SendPacket( &data );
1335 if(time == 0)
1337 m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT,0);
1338 m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT+1,0);
1339 m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL,0);
1343 void Spell::SendChannelStart(uint32 duration)
1345 Unit* target = 0;
1347 if (m_caster->GetTypeId() == TYPEID_PLAYER)
1350 target = ObjectAccessor::Instance().GetUnit(*m_caster, ((Player *)m_caster)->GetSelection());
1352 WorldPacket data( MSG_CHANNEL_START, (4+4) );
1353 data << m_spellInfo->Id;
1354 data << duration;
1356 ((Player*)m_caster)->GetSession()->SendPacket( &data );
1359 m_timer = duration;
1360 if(target)
1362 m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT,target->GetGUIDLow());
1363 m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT+1,target->GetGUIDHigh());
1365 m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL,m_spellInfo->Id);
1368 void Spell::SendResurrectRequest(Player* target)
1370 WorldPacket data(SMSG_RESURRECT_REQUEST, (8+4+1));
1371 data << m_caster->GetGUID();
1372 data << uint32(0) << uint8(0);
1374 target->GetSession()->SendPacket(&data);
1377 void Spell::SendHealSpellOnPlayer(Player* target, uint32 SpellID, uint32 Damage, bool CriticalHeal)
1379 WorldPacket data(SMSG_HEALSPELL_ON_PLAYER_OBSOLETE, (8+8+4+4+1));
1380 data.append(target->GetPackGUID());
1381 data.append(m_caster->GetPackGUID());
1382 data << SpellID;
1383 data << Damage;
1384 data << uint8(CriticalHeal);
1385 target->GetSession()->SendPacket(&data);
1388 void Spell::SendHealSpellOnPlayerPet(Player* target, uint32 SpellID, uint32 Damage, bool CriticalHeal)
1390 Pet* pet = target->GetPet();
1391 if(!pet||!pet->isAlive()) // must revive before heal
1392 return;
1394 WorldPacket data(SMSG_HEALSPELL_ON_PLAYERS_PET_OBSOLETE, (8+8+4+4+1));
1395 data.append(pet->GetPackGUID());
1396 data.append(m_caster->GetPackGUID());
1397 data << SpellID;
1398 data << Damage;
1399 data << uint8(CriticalHeal);
1400 target->GetSession()->SendPacket(&data);
1403 void Spell::SendPlaySpellVisual(uint32 SpellID)
1405 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1406 return;
1408 WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12);
1409 data << m_caster->GetGUID();
1410 data << SpellID;
1411 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1414 void Spell::TakeCastItem()
1416 if(!m_CastItem || m_caster->GetTypeId() != TYPEID_PLAYER)
1417 return;
1419 // not remove cast item at triggered spell (equipping, weapon damage, etc)
1420 if(m_IsTriggeredSpell)
1421 return;
1423 ItemPrototype const *proto = m_CastItem->GetProto();
1424 uint32 ItemClass = proto->Class;
1425 uint32 ItemSubClass = proto->SubClass;
1427 bool expendable = false;
1428 bool withoutCharges = false;
1429 int32 charges;
1431 for (int i = 0; i<5; i++)
1433 if (proto->Spells[i].SpellId)
1435 // item has limited charges
1436 if (proto->Spells[i].SpellCharges)
1438 if (proto->Spells[i].SpellCharges < 0)
1439 expendable = true;
1440 charges = int32(m_CastItem->GetUInt32Value(ITEM_FIELD_SPELL_CHARGES+i));
1442 // item has charges left
1443 if (charges > 0)
1445 --charges;
1446 if (proto->Stackable < 2)
1447 m_CastItem->SetUInt32Value(ITEM_FIELD_SPELL_CHARGES+i, charges);
1448 m_CastItem->SetState(ITEM_CHANGED, (Player*)m_caster);
1451 // all charges used
1452 if (charges == 0)
1453 withoutCharges = true;
1458 if (expendable && withoutCharges)
1460 uint32 count = 1;
1461 ((Player*)m_caster)->DestroyItemCount(m_CastItem, count, true);
1463 m_CastItem = NULL;
1467 void Spell::TakePower(uint32 mana)
1469 if(m_CastItem)
1470 return;
1472 // health as power used
1473 if(m_spellInfo->powerType == -2)
1475 m_caster->ModifyHealth( -(int32)mana );
1476 return;
1479 if(m_spellInfo->powerType <0 || m_spellInfo->powerType > POWER_HAPPINESS)
1481 sLog.outError("Spell::TakePower: Unknown power type '%d'", m_spellInfo->powerType);
1482 return;
1485 Powers powerType = Powers(m_spellInfo->powerType);
1487 m_caster->ModifyPower(powerType, -(int32)mana);
1488 if (powerType == POWER_MANA)
1490 // Set the five second timer
1491 if (m_caster->GetTypeId() == TYPEID_PLAYER && mana > 0)
1493 ((Player *)m_caster)->SetLastManaUse((uint32)getMSTime());
1498 void Spell::TakeReagents()
1500 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1501 return;
1503 Player* p_caster = (Player*)m_caster;
1504 for(uint32 x=0;x<8;x++)
1506 if(m_spellInfo->Reagent[x] == 0)
1507 continue;
1508 uint32 itemid = m_spellInfo->Reagent[x];
1509 uint32 itemcount = m_spellInfo->ReagentCount[x];
1510 if( p_caster->HasItemCount(itemid,itemcount) )
1512 if(m_CastItem && m_CastItem->GetProto()->ItemId == itemid)
1513 m_CastItem = NULL;
1515 p_caster->DestroyItemCount(itemid, itemcount, true);
1518 else
1520 SendCastResult(CAST_FAIL_ITEM_NOT_READY);
1521 return;
1526 void Spell::HandleThreatSpells(uint32 spellId)
1528 if(!unitTarget || !spellId)
1529 return;
1531 if(!unitTarget->CanHaveThreatList())
1532 return;
1534 SpellThreatEntry const *threatSpell = sSpellThreatStore.LookupEntry<SpellThreatEntry>(spellId);
1535 if(!threatSpell)
1536 return;
1538 unitTarget->AddThreat(m_caster, float(threatSpell->threat));
1540 DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, objmgr.GetSpellRank(spellId), threatSpell->threat);
1543 void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i)
1545 unitTarget = pUnitTarget;
1546 itemTarget = pItemTarget;
1547 gameObjTarget = pGOTarget;
1549 damage = CalculateDamage((uint8)i);
1550 uint8 eff = m_spellInfo->Effect[i];
1552 sLog.outDebug( "Spell: Effect : %u", eff);
1553 if(unitTarget && unitTarget->IsImmunedToSpellEffect(eff))
1555 SendCastResult(CAST_FAIL_IMMUNE);
1556 return;
1559 if(eff<TOTAL_SPELL_EFFECTS)
1561 //sLog.outDebug( "WORLD: Spell FX %d < TOTAL_SPELL_EFFECTS ", eff);
1562 (*this.*SpellEffects[eff])(i);
1565 else
1567 sLog.outDebug( "WORLD: Spell FX %d > TOTAL_SPELL_EFFECTS ", eff);
1568 if (m_CastItem)
1569 EffectEnchantItemTmp(i);
1570 else
1572 sLog.outError("SPELL: unknown effect %u spell id %u\n",
1573 eff, m_spellInfo->Id);
1579 /*void Spell::HandleAddAura(Unit* Target)
1581 if(!Target) return;
1583 if(Target->tmpAura != 0)
1585 Target->AddAura(Target->tmpAura);
1586 Target->tmpAura = 0;
1591 void Spell::TriggerSpell()
1593 if(m_TriggerSpell.size() < 1) return;
1595 for(std::list<SpellEntry const*>::iterator si=m_TriggerSpell.begin(); si!=m_TriggerSpell.end(); ++si)
1597 Spell spell(m_caster, (*si), true, 0);
1598 SpellCastTargets targets;
1599 targets.setUnitTarget(m_targets.getUnitTarget());
1600 spell.prepare(&targets);
1605 uint8 Spell::CanCast()
1607 // check cooldowns to prevent cheating
1608 if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HaveSpellCooldown(m_spellInfo->Id))
1609 return CAST_FAIL_SPELL_NOT_READY_YET;
1611 // cancel autorepeat spells if cast start when moving
1612 // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code)
1613 if( ((Player*)m_caster)->GetMovementFlags() && (IsAutoRepeat() || m_rangedShoot) )
1614 return CAST_FAIL_CANT_DO_WHILE_MOVING;
1616 uint8 castResult = 0;
1618 Unit *target = m_targets.getUnitTarget();
1620 if(target)
1622 //check creaturetype
1623 uint32 SpellCreatureType = m_spellInfo->TargetCreatureType;
1625 // not find another way to fix spell target check :/
1626 if(m_spellInfo->Id == 603)
1627 SpellCreatureType = 0x7FF - 0x40; //Curse of Doom
1628 else
1629 if(m_spellInfo->Id == 2641) // Dismiss Pet
1630 SpellCreatureType = 0;
1632 if(SpellCreatureType)
1634 for(int j=0;j<3;j++)
1636 if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_PET)
1638 target = m_caster->GetPet();
1639 break;
1642 uint32 TargetCreatureType = 0;
1643 if(target->GetTypeId() == TYPEID_PLAYER)
1644 TargetCreatureType = 0x40; //1<<(7-1)
1645 else if ( target->GetTypeId() == TYPEID_UNIT )
1647 uint32 CType = ((Creature*)target)->GetCreatureInfo()->type;
1648 if(CType>=1)
1649 TargetCreatureType = 1 << ( ((Creature*)target)->GetCreatureInfo()->type - 1);
1650 else
1651 TargetCreatureType = 0;
1654 if(TargetCreatureType && !(SpellCreatureType & TargetCreatureType))
1656 if(TargetCreatureType == 0x40)
1657 castResult = CAST_FAIL_CANT_TARGET_PLAYERS;
1658 else
1659 castResult = CAST_FAIL_INVALID_TARGET;
1661 return castResult;
1665 if(target->IsImmunedToSpell(m_spellInfo))
1666 return CAST_FAIL_IMMUNE;
1668 if(m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->EquippedItemClass >= 0)
1670 Item *pitem = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0,INVTYPE_WEAPON);
1671 if(!pitem)
1672 castResult = CAST_FAIL_MUST_HAVE_XXXX_IN_MAINHAND;
1673 else if(pitem->GetProto()->Class != m_spellInfo->EquippedItemClass)
1674 castResult = CAST_FAIL_MUST_HAVE_XXXX_IN_MAINHAND;
1675 else if(!(pitem->GetProto()->SubClass & m_spellInfo->EquippedItemSubClass))
1676 castResult = CAST_FAIL_MUST_HAVE_XXXX_IN_MAINHAND;
1678 //Old not working code
1679 //if((m_spellInfo->AttributesExEx & 0x4000000) && !target->HasInArc(M_PI, m_caster) )
1680 // castResult = CAST_FAIL_NOT_BEHIND_TARGET;
1682 //Must be behind the target.
1683 if( m_spellInfo->AttributesEx2 == 0x100000 && (m_spellInfo->AttributesEx & 0x200) == 0x200 && target->HasInArc(M_PI, m_caster) )
1685 SendInterrupted(2);
1686 castResult = CAST_FAIL_NOT_BEHIND_TARGET;
1688 else
1689 //Target must be facing you.
1690 if((m_spellInfo->Attributes == 0x150010) && !target->HasInArc(M_PI, m_caster) )
1692 SendInterrupted(2);
1693 castResult = CAST_FAIL_NOT_IN_FRONT_OF_TARGET;
1695 else
1696 if(m_caster->hasUnitState(UNIT_STAT_CONFUSED))
1697 castResult = CAST_FAIL_CANT_DO_WHILE_CONFUSED;
1699 if(castResult!=0)
1700 return castResult;
1703 if(m_caster->hasUnitState(UNIT_STAT_STUNDED))
1704 return CAST_FAIL_CANT_DO_WHILE_STUNNED;
1706 // not let players cast non-triggered spells at mount (and let do it to creatures)
1707 if(m_caster->IsMounted() && !m_IsTriggeredSpell && m_caster->GetTypeId()==TYPEID_PLAYER)
1708 return CAST_FAIL_CANT_USE_WHEN_MOUNTED;
1710 if(m_caster->m_silenced)
1711 return CAST_FAIL_SILENCED;
1713 castResult = CheckItems(); // always check items (focus object can be required for any type casts)
1715 if(castResult == 0)
1716 castResult = CheckRange();
1718 if(castResult == 0)
1720 uint32 mana = 0;
1721 castResult = CheckMana(&mana);
1724 if( castResult != 0 )
1725 return castResult;
1727 for (int i = 0; i < 3; i++)
1729 // for effects of spells that have only one target
1730 switch(m_spellInfo->Effect[i])
1732 case SPELL_EFFECT_DUMMY:
1734 if (!unitTarget)
1736 castResult = CAST_FAIL_FAILED;
1737 break;
1740 if(m_spellInfo->SpellIconID == 1648)
1742 if(unitTarget->GetHealth() > unitTarget->GetMaxHealth()*0.2)
1744 castResult = CAST_FAIL_INVALID_TARGET;
1745 break;
1748 break;
1750 case SPELL_EFFECT_TAMECREATURE:
1752 if (!unitTarget || unitTarget->GetTypeId() == TYPEID_PLAYER)
1754 castResult = CAST_FAIL_FAILED;
1755 break;
1758 if (unitTarget->getLevel() > m_caster->getLevel())
1760 castResult = CAST_FAIL_TARGET_IS_TOO_HIGH;
1761 break;
1763 CreatureInfo const *cinfo = ((Creature*)unitTarget)->GetCreatureInfo();
1764 CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family);
1765 if( cinfo->type != CREATURE_TYPE_BEAST || !cFamily || !cFamily->tamable )
1767 castResult = CAST_FAIL_INVALID_TARGET;
1768 break;
1770 if(m_caster->GetPetGUID())
1772 castResult = CAST_FAIL_ALREADY_HAVE_SUMMON;
1773 break;
1775 if(m_caster->GetCharmGUID())
1777 castResult = CAST_FAIL_ALREADY_HAVE_CHARMED;
1778 break;
1780 break;
1782 case SPELL_EFFECT_LEARN_PET_SPELL:
1784 if(!unitTarget || unitTarget->GetTypeId() == TYPEID_PLAYER)
1786 castResult = CAST_FAIL_FAILED;
1787 break;
1790 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
1792 if(!learn_spellproto)
1794 castResult = CAST_FAIL_FAILED;
1795 break;
1798 Creature* creatureTarget = (Creature*)unitTarget;
1799 uint8 learn_msg = 1;
1800 for(int8 x=0;x<4;x++)
1802 if((creatureTarget)->m_spells[x] == learn_spellproto->Id)
1804 castResult = CAST_FAIL_ALREADY_LEARNED_THAT_SPELL;
1805 break;
1807 SpellEntry const *has_spellproto = sSpellStore.LookupEntry(creatureTarget ->m_spells[x]);
1808 if (!has_spellproto) learn_msg = 0;
1809 else if (has_spellproto->SpellIconID == learn_spellproto->SpellIconID)
1810 learn_msg = 0;
1812 if(learn_msg)
1813 castResult = CAST_FAIL_SPELL_NOT_LEARNED;
1814 break;
1816 case SPELL_EFFECT_FEED_PET:
1818 if (m_caster->GetTypeId() != TYPEID_PLAYER || !itemTarget )
1820 castResult = CAST_FAIL_FAILED;
1821 break;
1824 Pet* pet = m_caster->GetPet();
1826 if(!pet)
1828 castResult = CAST_FAIL_YOU_DO_NOT_HAVE_PET;
1829 break;
1832 if(!pet->HaveInDiet(itemTarget->GetProto()))
1834 castResult = CAST_FAIL_PET_DOESNT_LIKE_THAT_FOOD;
1835 break;
1838 break;
1840 case SPELL_EFFECT_SKINNING:
1842 if (m_caster->GetTypeId() != TYPEID_PLAYER || !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1844 castResult = CAST_FAIL_FAILED;
1845 break;
1848 if( !(unitTarget->GetUInt32Value(UNIT_FIELD_FLAGS) & UNIT_FLAG_SKINNABLE) )
1850 castResult = CAST_FAIL_NOT_SKINNABLE;
1851 break;
1854 if ( ( ((Creature*)unitTarget)->GetCreatureInfo()->type != CREATURE_TYPE_CRITTER )
1855 && ( !((Creature*)unitTarget)->lootForBody || !((Creature*)unitTarget)->loot.empty() ) )
1857 castResult = CAST_FAIL_CREATURE_MUST_BE_LOOTED_FIRST;
1858 break;
1861 int32 SkinningValue = ((Player*)m_caster)->GetSkillValue(SKILL_SKINNING);
1862 int32 TargetLevel = unitTarget->getLevel();
1863 int32 ReqValue = (SkinningValue < 100 ? (TargetLevel-10)*10 : TargetLevel*5);
1864 if (ReqValue > SkinningValue)
1866 castResult = CAST_FAIL_SKILL_NOT_HIGH_ENOUGH;
1867 break;
1870 // chance for fail at orange skinning attempt
1871 if (m_caster->m_currentSpell == this && (ReqValue < 0 ? 0 : ReqValue) > irand(SkinningValue-25, SkinningValue+37) )
1872 castResult = CAST_FAIL_FAILED_ATTEMPT;
1873 break;
1875 case SPELL_EFFECT_OPEN_LOCK:
1877 if (m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT)
1878 break;
1879 if (m_caster->GetTypeId() != TYPEID_PLAYER || !gameObjTarget)
1880 return CAST_FAIL_FAILED;
1882 // chance for fail at orange mining/herb/LockPicking gathering attempt
1883 if (gameObjTarget->GetGoType() == GAMEOBJECT_TYPE_CHEST && m_caster->m_currentSpell == this)
1885 int32 SkillValue;
1886 if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_HERBALISM)
1887 SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_HERBALISM);
1888 else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_MINING)
1889 SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_MINING);
1890 else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK)
1891 SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_LOCKPICKING);
1892 else
1893 break;
1895 int32 ReqValue;
1896 LockEntry const *lockInfo = sLockStore.LookupEntry(gameObjTarget->GetGOInfo()->sound0);
1897 if (lockInfo)
1899 if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK)
1900 ReqValue = lockInfo->requiredlockskill;
1901 else
1902 ReqValue = lockInfo->requiredskill;
1904 else
1905 break;
1907 if (ReqValue > SkillValue)
1909 castResult = CAST_FAIL_SKILL_NOT_HIGH_ENOUGH;
1910 break;
1913 if (ReqValue > irand(SkillValue-25, SkillValue+37))
1914 castResult = CAST_FAIL_FAILED_ATTEMPT;
1916 break;
1918 case SPELL_EFFECT_SUMMON_DEAD_PET:
1920 Creature *pet = m_caster->GetPet();
1921 if(!pet)
1923 castResult = CAST_FAIL_YOU_DO_NOT_HAVE_PET;
1924 break;
1927 if(pet->isAlive())
1929 castResult = CAST_FAIL_FAILED;
1930 break;
1932 break;
1934 case SPELL_EFFECT_SUMMON:
1935 //case SPELL_EFFECT_SUMMON_WILD: //not store in pet field
1936 //case SPELL_EFFECT_SUMMON_GUARDIAN: //not store in pet field
1937 case SPELL_EFFECT_SUMMON_PET:
1938 case SPELL_EFFECT_SUMMON_POSSESSED:
1939 case SPELL_EFFECT_SUMMON_PHANTASM:
1940 case SPELL_EFFECT_SUMMON_CRITTER: //not store in pet field
1941 case SPELL_EFFECT_SUMMON_DEMON:
1943 if(m_caster->GetPetGUID())
1945 castResult = CAST_FAIL_ALREADY_HAVE_SUMMON;
1946 break;
1948 if(m_caster->GetCharmGUID())
1950 castResult = CAST_FAIL_ALREADY_HAVE_CHARMED;
1951 break;
1953 break;
1955 case SPELL_EFFECT_LEAP:
1956 case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER:
1958 float dis = GetRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
1959 float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation());
1960 float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation());
1961 // teleport a bit above terrainlevel to avoid falling below it
1962 float fz = MapManager::Instance().GetMap(m_caster->GetMapId())->GetHeight(fx,fy) + 1.5;
1964 float caster_pos_z = m_caster->GetPositionZ();
1965 // Control the caster to not climb or drop when +-fz > 8
1966 if(!(fz<=caster_pos_z+8 && fz>=caster_pos_z-8))
1967 castResult = CAST_FAIL_FAILED_ATTEMPT;
1968 break;
1970 default:break;
1973 if(castResult != 0)
1974 return castResult;
1977 // Conflagrate - do only when preparing
1978 if (m_caster->m_currentSpell != this && m_spellInfo->SpellIconID == 12 &&
1979 m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_targets.getUnitTarget())
1981 Unit::AuraMap& t_auras = m_targets.getUnitTarget()->GetAuras();
1982 bool hasImmolate = false;
1983 for(Unit::AuraMap::iterator itr = t_auras.begin(); itr != t_auras.end(); ++itr)
1985 if (itr->second && !IsPassiveSpell(itr->second->GetId()))
1987 SpellEntry const *spellInfo = itr->second->GetSpellProto();
1988 if (!spellInfo) continue;
1989 if (spellInfo->SpellIconID != 31 || spellInfo->SpellFamilyName != SPELLFAMILY_WARLOCK) continue;
1990 hasImmolate = true;
1991 m_targets.getUnitTarget()->RemoveAurasDueToSpell(spellInfo->Id);
1992 break;
1995 if(!hasImmolate)
1996 return CAST_FAIL_CANT_DO_THAT_YET;
1999 for (int i = 0; i < 3; i++)
2001 switch(m_spellInfo->EffectApplyAuraName[i])
2003 case SPELL_AURA_MOD_POSSESS:
2004 case SPELL_AURA_MOD_CHARM:
2006 if(m_caster->GetPetGUID())
2008 castResult = CAST_FAIL_ALREADY_HAVE_SUMMON;
2009 break;
2011 if(m_caster->GetCharmGUID())
2013 castResult = CAST_FAIL_ALREADY_HAVE_CHARMED;
2014 break;
2016 if(unitTarget->getLevel() > CalculateDamage(i))
2018 castResult = CAST_FAIL_TARGET_IS_TOO_HIGH;
2019 break;
2022 case SPELL_AURA_MOD_STEALTH:
2023 case SPELL_AURA_MOD_INVISIBILITY:
2026 //detect if any mod is in x range.if true,can't steath.FIX ME!
2027 if(m_spellInfo->Attributes == 169148432 || m_caster->GetTypeId() != TYPEID_PLAYER)
2028 break;
2030 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
2031 Cell cell = RedZone::GetZone(p);
2032 cell.data.Part.reserved = ALL_DISTRICT;
2034 std::list<Unit*> i_data;
2035 std::list<Unit*>::iterator itr;
2036 MaNGOS::GridUnitListNotifier checker(i_data);
2038 TypeContainerVisitor<MaNGOS::GridUnitListNotifier, TypeMapContainer<AllObjectTypes> > object_checker(checker);
2039 CellLock<GridReadGuard> cell_lock(cell, p);
2040 cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId()));
2041 for(itr = i_data.begin();itr != i_data.end();++itr)
2043 if( !(*itr)->isAlive() )
2044 continue;
2046 if( !(*itr)->IsHostileTo(m_caster) )
2047 continue;
2049 if((*itr)->GetTypeId() != TYPEID_PLAYER)
2051 float attackdis = ((Creature*)(*itr))->GetAttackDistance(m_caster);
2052 if((*itr)->GetDistanceSq(m_caster) < attackdis*attackdis )
2054 castResult = CAST_FAIL_TOO_CLOSE_TO_ENEMY;
2055 break;
2059 };break;
2060 default:break;
2062 if(castResult != 0)
2063 return castResult;
2065 return castResult;
2068 uint8 Spell::CheckRange()
2070 // self cast doesnt need range checking -- also for Starshards fix
2071 if (m_spellInfo->rangeIndex == 1) return 0;
2073 SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
2074 float max_range = GetMaxRange(srange);
2075 float min_range = GetMinRange(srange);
2077 if (m_caster->GetTypeId() == TYPEID_PLAYER)
2078 ((Player *)m_caster)->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, max_range);
2080 Unit *target = m_targets.getUnitTarget();
2082 if(target && target != m_caster)
2084 float dist = m_caster->GetDistanceSq(target);
2085 if(dist > max_range * max_range)
2086 return CAST_FAIL_OUT_OF_RANGE; //0x56;
2087 if(dist < min_range * min_range)
2088 return CAST_FAIL_TOO_CLOSE;
2089 if( !m_IsTriggeredSpell && !m_caster->isInFront( target, max_range) )
2090 if (m_rangedShoot || !IsPositiveSpell(m_spellInfo->Id) && casttime != 0 && !IsSingleTarget(m_spellInfo->Id))
2091 return CAST_FAIL_TARGET_NEED_TO_BE_INFRONT;
2094 if(m_targets.m_targetMask == TARGET_FLAG_DEST_LOCATION && m_targets.m_destX != 0 && m_targets.m_destY != 0 && m_targets.m_destY != 0)
2096 float dist = m_caster->GetDistanceSq(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ);
2097 if(dist > max_range * max_range)
2098 return CAST_FAIL_OUT_OF_RANGE;
2099 if(dist < min_range * min_range)
2100 return CAST_FAIL_TOO_CLOSE;
2103 return 0; // ok
2106 uint8 Spell::CheckMana(uint32 *mana)
2108 // item cast not used power
2109 if(m_CastItem)
2110 return 0;
2112 // health as power used
2113 if(m_spellInfo->powerType == -2)
2115 uint32 currentHealth = m_caster->GetHealth();
2117 uint32 healthCost;
2119 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2121 PlayerLevelInfo info;
2122 objmgr.GetPlayerLevelInfo(m_caster->getRace(),m_caster->getClass(),m_caster->getLevel(),&info);
2123 healthCost = m_spellInfo->manaCost + int32(float(m_spellInfo->ManaCostPercentage)/100.0 * info.health);
2125 else
2126 healthCost = m_spellInfo->manaCost + int32(float(m_spellInfo->ManaCostPercentage)/100.0 * m_caster->GetMaxHealth());
2128 *mana = healthCost;
2129 if(currentHealth <= healthCost)
2130 return CAST_FAIL_CANT_DO_THAT_YET;
2132 return 0;
2135 if(m_spellInfo->powerType <0 || m_spellInfo->powerType > POWER_HAPPINESS)
2137 sLog.outError("Spell::CheckMana: Unknown power type '%d'", m_spellInfo->powerType);
2138 return CAST_FAIL_UNKNOWN_REASON;
2141 Powers powerType = Powers(m_spellInfo->powerType);
2143 int32 currentPower = m_caster->GetPower(powerType);
2144 int32 manaCost = m_spellInfo->manaCost;
2145 if(m_spellInfo->manaCostPerlevel)
2146 manaCost += int32(m_spellInfo->manaCostPerlevel*m_caster->getLevel());
2147 if(m_spellInfo->ManaCostPercentage)
2149 if(m_caster->GetTypeId() == TYPEID_PLAYER && powerType==POWER_MANA)
2151 PlayerLevelInfo info;
2152 objmgr.GetPlayerLevelInfo(m_caster->getRace(),m_caster->getClass(),m_caster->getLevel(),&info);
2153 manaCost += int32(float(m_spellInfo->ManaCostPercentage)/100.0 * info.mana);
2155 else
2156 manaCost += int32(float(m_spellInfo->ManaCostPercentage)/100.0*m_caster->GetMaxPower(powerType));
2159 Unit::AuraList& mPowerCostSchool = m_caster->GetAurasByType(SPELL_AURA_MOD_POWER_COST_SCHOOL);
2160 for(Unit::AuraList::iterator i = mPowerCostSchool.begin(); i != mPowerCostSchool.end(); ++i)
2161 if((*i)->GetModifier()->m_miscvalue & int32(1 << m_spellInfo->School))
2162 manaCost += (*i)->GetModifier()->m_amount;
2164 if (m_caster->GetTypeId() == TYPEID_PLAYER)
2165 ((Player *)m_caster)->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, manaCost);
2167 manaCost += m_caster->GetUInt32Value(UNIT_FIELD_POWER_COST_MODIFIER);
2169 if (manaCost < 0)
2170 manaCost = 0;
2172 *mana = manaCost;
2174 if(currentPower < manaCost)
2175 return CAST_FAIL_NOT_ENOUGH_MANA;
2176 else return 0;
2179 uint8 Spell::CheckItems()
2181 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2182 return 0;
2184 uint32 itemid, itemcount;
2185 Player* p_caster = (Player*)m_caster;
2187 if(m_CastItem)
2189 itemid = m_CastItem->GetEntry();
2190 if( !p_caster->HasItemCount(itemid,1) )
2191 return CAST_FAIL_ITEM_NOT_READY;
2192 else
2194 ItemPrototype const *proto = m_CastItem->GetProto();
2195 if(!proto)
2196 return CAST_FAIL_ITEM_NOT_READY;
2198 uint32 charges;
2199 for (int i = 0; i<5; i++)
2200 if (proto->Spells[i].SpellCharges)
2202 charges = m_CastItem->GetUInt32Value(ITEM_FIELD_SPELL_CHARGES+i);
2203 if (charges == 0)
2204 return CAST_FAIL_NO_CHARGES_REMAIN;
2207 uint32 ItemClass = proto->Class;
2208 if (ItemClass == ITEM_CLASS_CONSUMABLE && unitTarget)
2210 for (int i = 0; i < 3; i++)
2212 if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL)
2213 if (unitTarget->GetHealth() == unitTarget->GetMaxHealth())
2214 return (uint8)CAST_FAIL_ALREADY_FULL_HEALTH;
2216 // Mana Potion, Rage Potion, Thistle Tea(Rogue), ...
2217 if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE)
2219 //Check if the Caster Has Rage For Power
2220 if (m_caster->GetMaxPower(POWER_RAGE))
2222 if (unitTarget->GetPower(POWER_RAGE) == unitTarget->GetMaxPower(POWER_RAGE))
2223 return (uint8)CAST_FAIL_ALREADY_FULL_MANA;
2225 //Check if the Caster Has Energy For Power
2226 else if (m_caster->GetMaxPower(POWER_ENERGY))
2228 if (unitTarget->GetPower(POWER_ENERGY) == unitTarget->GetMaxPower(POWER_ENERGY))
2229 return (uint8)CAST_FAIL_ALREADY_FULL_MANA;
2231 //So The Player Has Mana
2232 else if (unitTarget->GetPower(POWER_MANA) == unitTarget->GetMaxPower(POWER_MANA))
2234 return (uint8)CAST_FAIL_ALREADY_FULL_MANA;
2242 if(itemTarget)
2244 if(m_caster->GetTypeId() == TYPEID_PLAYER && !itemTarget->IsFitToSpellRequirements(m_spellInfo))
2245 return CAST_FAIL_INVALID_TARGET;
2248 if(m_spellInfo->RequiresSpellFocus)
2250 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
2251 Cell cell = RedZone::GetZone(p);
2252 cell.data.Part.reserved = ALL_DISTRICT;
2254 GameObject* ok = NULL;
2255 MaNGOS::GameObjectFocusCheck go_check(m_caster,m_spellInfo->RequiresSpellFocus);
2256 MaNGOS::GameObjectSearcher<MaNGOS::GameObjectFocusCheck> checker(ok,go_check);
2258 TypeContainerVisitor<MaNGOS::GameObjectSearcher<MaNGOS::GameObjectFocusCheck>, TypeMapContainer<AllObjectTypes> > object_checker(checker);
2259 CellLock<GridReadGuard> cell_lock(cell, p);
2260 cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId()));
2262 if(!ok) return (uint8)CAST_FAIL_REQUIRES_XXX;
2264 focusObject = ok;
2266 // game object found in range
2269 for(uint32 i=0;i<8;i++)
2271 if((itemid = m_spellInfo->Reagent[i]) == 0)
2272 continue;
2273 itemcount = m_spellInfo->ReagentCount[i];
2274 // CastItem is also spell reagent
2275 if( m_CastItem && m_CastItem->GetEntry() == itemid )
2277 ItemPrototype const *proto = m_CastItem->GetProto();
2278 if(!proto)
2279 return CAST_FAIL_ITEM_NOT_READY;
2280 for(int s=0;s<5;s++)
2282 // CastItem will be used up and does not count as reagent
2283 if(proto->Spells[s].SpellCharges < 0 && m_CastItem->GetUInt32Value(ITEM_FIELD_SPELL_CHARGES+s) < 2)
2285 itemcount++;
2286 break;
2290 if( !p_caster->HasItemCount(itemid,itemcount) )
2291 return (uint8)CAST_FAIL_ITEM_NOT_READY; //0x54
2294 uint32 totems = 2;
2295 for(int i=0;i<2;i++)
2297 if(m_spellInfo->Totem[i] != 0)
2299 if( p_caster->HasItemCount(m_spellInfo->Totem[i],1) )
2301 totems -= 1;
2302 continue;
2304 }else
2305 totems -= 1;
2307 if(totems != 0)
2308 return uint8(0x70);
2310 for(int i = 0; i < 3; i++)
2312 switch (m_spellInfo->Effect[i])
2314 case SPELL_EFFECT_CREATE_ITEM:
2316 if (m_spellInfo->EffectItemType[i])
2318 uint16 dest;
2319 uint8 msg = p_caster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->EffectItemType[i], 1, false );
2320 if (msg != EQUIP_ERR_OK )
2322 p_caster->SendEquipError( msg, NULL, NULL );
2323 return uint8(CAST_FAIL_FAILED); // TODO: don't show two errors
2326 break;
2328 case SPELL_EFFECT_ENCHANT_ITEM:
2329 case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY:
2330 if(!itemTarget)
2331 return CAST_FAIL_ENCHANT_NOT_EXISTING_ITEM;
2332 break;
2333 case SPELL_EFFECT_ENCHANT_HELD_ITEM:
2335 if(!itemTarget)
2336 return CAST_FAIL_ENCHANT_NOT_EXISTING_ITEM;
2337 if (!itemTarget->IsEquipped())
2338 return CAST_FAIL_MUST_HAVE_ITEM_EQUIPPED;
2339 break;
2341 case SPELL_EFFECT_DISENCHANT:
2343 if(!itemTarget)
2344 return CAST_FAIL_CANT_BE_DISENCHANTED;
2346 // prevent disenchanting in trade slot
2347 if( itemTarget->GetOwnerGUID() != m_caster->GetGUID() )
2348 return (uint8)CAST_FAIL_CANT_BE_DISENCHANTED;
2350 if (!itemTarget->GetProto()->DisenchantID)
2351 return CAST_FAIL_CANT_BE_DISENCHANTED;
2353 case SPELL_EFFECT_WEAPON_DAMAGE:
2354 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
2356 if(m_caster->GetTypeId() != TYPEID_PLAYER) return CAST_FAIL_FAILED;
2357 if(m_spellInfo->rangeIndex == 1 || m_spellInfo->rangeIndex == 2 || m_spellInfo->rangeIndex == 7)
2358 break;
2359 Item *pItem = ((Player*)m_caster)->GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED );
2360 if(!pItem || pItem->IsBroken() || pItem->GetProto()->Class != ITEM_CLASS_WEAPON )
2361 return CAST_FAIL_MUST_HAVE_ITEM_EQUIPPED;
2363 switch(pItem->GetProto()->SubClass)
2365 case ITEM_SUBCLASS_WEAPON_THROWN:
2367 uint32 ammo = pItem->GetEntry();
2368 if( !((Player*)m_caster)->HasItemCount( ammo, 1 ) )
2369 return CAST_FAIL_NO_AMMO;
2370 }; break;
2371 case ITEM_SUBCLASS_WEAPON_GUN:
2372 case ITEM_SUBCLASS_WEAPON_BOW:
2374 uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID);
2375 if(!ammo)
2376 return CAST_FAIL_NO_AMMO;
2378 ItemPrototype const *ammoProto = objmgr.GetItemPrototype( ammo );
2379 if(!ammoProto)
2380 return CAST_FAIL_NO_AMMO;
2382 if(ammoProto->Class != ITEM_CLASS_PROJECTILE)
2383 return CAST_FAIL_NO_AMMO;
2385 if(pItem->GetProto()->SubClass != ammoProto->SubClass)
2386 return CAST_FAIL_NO_AMMO;
2388 if( !((Player*)m_caster)->HasItemCount( ammo, 1 ) )
2389 return CAST_FAIL_NO_AMMO;
2390 }; break;
2391 case ITEM_SUBCLASS_WEAPON_WAND:
2392 default:
2393 break;
2395 break;
2397 default:break;
2401 return uint8(0);
2404 uint32 Spell::CalculateDamage(uint8 i)
2406 uint32 value = 0;
2407 uint32 level = 0;
2408 // currently the damage should not be increased by level
2409 /*uint32 level = m_caster->getLevel();
2410 if( level > m_spellInfo->maxLevel && m_spellInfo->maxLevel > 0)
2411 level = m_spellInfo->maxLevel;*/
2412 float basePointsPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2413 float randomPointsPerLevel = m_spellInfo->EffectDicePerLevel[i];
2414 uint32 basePoints = uint32(m_spellInfo->EffectBasePoints[i]+level*basePointsPerLevel);
2415 uint32 randomPoints = uint32(m_spellInfo->EffectDieSides[i]+level*randomPointsPerLevel);
2416 float comboDamage = m_spellInfo->EffectPointsPerComboPoint[i];
2417 uint8 comboPoints=0;
2418 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2419 comboPoints = (uint8)((m_caster->GetUInt32Value(PLAYER_FIELD_BYTES) & 0xFF00) >> 8);
2420 value += m_spellInfo->EffectBaseDice[i];
2421 if(randomPoints <= 1)
2422 value = basePoints+1;
2423 else
2424 value = basePoints+rand()%randomPoints;
2426 if(comboDamage > 0)
2428 value += (uint32)(comboDamage * comboPoints);
2429 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2430 m_caster->SetUInt32Value(PLAYER_FIELD_BYTES,((m_caster->GetUInt32Value(PLAYER_FIELD_BYTES) & ~(0xFF << 8)) | (0x00 << 8)));
2433 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2434 ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DAMAGE, value);
2436 return value;
2439 void Spell::HandleTeleport(uint32 id, Unit* Target)
2442 if(!Target || Target->GetTypeId() != TYPEID_PLAYER)
2443 return;
2445 if(Target->isInFlight())
2446 return;
2448 if(m_spellInfo->Id == 8690 || m_spellInfo->Id == 556 )
2450 Field *fields;
2451 QueryResult *result = sDatabase.PQuery("SELECT `map`,`zone`,`position_x`,`position_y`,`position_z` FROM `character_homebind` WHERE `guid` = '%u'", m_caster->GetGUIDLow());
2452 if(!result)
2454 sLog.outError( "SPELL: No homebind location set for %i\n", m_caster->GetGUIDLow());
2455 return;
2457 fields = result->Fetch();
2459 TeleportCoords* TC = new TeleportCoords();
2460 TC->mapId = fields[0].GetUInt32();
2461 TC->x = fields[2].GetFloat();
2462 TC->y = fields[3].GetFloat();
2463 TC->z = fields[4].GetFloat();
2465 delete result;
2467 ((Player*)Target)->TeleportTo(TC->mapId,TC->x,TC->y,TC->z,Target->GetOrientation());
2468 delete TC;
2470 else
2472 TeleportCoords const* TC = objmgr.GetTeleportCoords(id);
2473 if(!TC)
2475 sLog.outError( "SPELL: unknown Teleport Coords ID %i\n", id );
2476 return;
2478 ((Player*)Target)->TeleportTo(TC->mapId,TC->x,TC->y,TC->z,Target->GetOrientation());
2482 void Spell::Delayed(int32 delaytime)
2484 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2485 return;
2487 m_timer += delaytime;
2489 if(m_timer > casttime)
2490 m_timer = (casttime > 0 ? casttime : 0);
2492 WorldPacket data(SMSG_SPELL_DELAYED, 12);
2493 data << m_caster->GetGUID();
2494 data << uint32(delaytime);
2496 ((Player*)m_caster)->GetSession()->SendPacket(&data);
2499 void Spell::DelayedChannel(int32 delaytime)
2501 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER || getState() != SPELL_STATE_CASTING)
2502 return;
2504 int32 appliedDelayTime = delaytime;
2506 if(int32(m_timer) < delaytime)
2508 appliedDelayTime = m_timer;
2509 m_timer = 0;
2510 } else
2511 m_timer -= delaytime;
2513 sLog.outDebug("Spell %u partially interrupted for %i ms, new duration: %u ms", m_spellInfo->Id, appliedDelayTime, m_timer);
2515 for(int j = 0; j < 3; j++)
2517 // partially interrupt auras with fixed targets
2518 for(std::list<uint64>::iterator iunit= m_targetUnitGUIDs[j].begin();iunit != m_targetUnitGUIDs[j].end();++iunit)
2520 // check m_caster->GetGUID() let load auras at login and speedup most often case
2521 Unit* unit = m_caster->GetGUID()==*iunit ? m_caster : ObjectAccessor::Instance().GetUnit(*m_caster,*iunit);
2522 if (unit)
2523 unit->DelayAura(m_spellInfo->Id, j, appliedDelayTime);
2526 // partially interrupt persistent area auras
2527 DynamicObject* dynObj = m_caster->GetDynObject(m_spellInfo->Id, j);
2528 if(dynObj)
2529 dynObj->Delay(appliedDelayTime);
2532 SendChannelUpdate(m_timer);
2535 void Spell::reflect(Unit *refunit)
2537 if (m_caster == refunit)
2538 return;
2540 SpellEntry *refspell = NULL;
2542 // if the spell to reflect is a reflect spell, do nothing.
2543 for(int i=0; i<3; i++)
2544 if(m_spellInfo->Effect[i] == 6 && (m_spellInfo->EffectApplyAuraName[i] == 74 || m_spellInfo->EffectApplyAuraName[i] == 28))
2545 return;
2547 int32 reflectchance = 0; // proper base reflect chance is ?
2549 Unit::AuraList& mReflectSpells = refunit->GetAurasByType(SPELL_AURA_REFLECT_SPELLS);
2550 for(Unit::AuraList::iterator i = mReflectSpells.begin(); i != mReflectSpells.end(); ++i)
2551 reflectchance += (*i)->GetModifier()->m_amount;
2553 Unit::AuraList& mReflectSpellsSchool = refunit->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
2554 for(Unit::AuraList::iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
2555 if((*i)->GetModifier()->m_miscvalue & int32(1 << m_spellInfo->School))
2556 reflectchance += (*i)->GetModifier()->m_amount;
2558 if (reflectchance > 0 && uint32(reflectchance) >= urand(0,100))
2560 Spell spell(refunit, refspell, true, 0);
2562 SpellCastTargets targets;
2563 targets.setUnitTarget( m_caster );
2564 spell.prepare(&targets);