[2921] Applied MaNGOS coding style (see trunk/bcpp.cfg).
[mangos-git.git] / src / game / Spell.cpp
blobed06c5004abe6b37d00edc64a94cb3a07d4f7beb
1 /*
2 * Copyright (C) 2005,2006 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 "Opcodes.h"
25 #include "Log.h"
26 #include "UpdateMask.h"
27 #include "World.h"
28 #include "ObjectMgr.h"
29 #include "Player.h"
30 #include "Pet.h"
31 #include "Unit.h"
32 #include "Spell.h"
33 #include "DynamicObject.h"
34 #include "SpellAuras.h"
35 #include "Group.h"
36 #include "UpdateData.h"
37 #include "MapManager.h"
38 #include "ObjectAccessor.h"
39 #include "RedZoneDistrict.h"
40 #include "CellImpl.h"
41 #include "Policies/SingletonImp.h"
42 #include "SharedDefines.h"
43 #include "Tools.h"
45 #define SPELL_CHANNEL_UPDATE_INTERVAL 1000
47 extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
49 SpellCastTargets::SpellCastTargets()
51 m_unitTarget = NULL;
52 m_itemTarget = NULL;
53 m_GOTarget = NULL;
54 m_srcX = m_srcY = m_srcZ = m_destX = m_destY = m_destZ = 0;
55 m_strTarget = "";
56 m_targetMask = 0;
59 SpellCastTargets::~SpellCastTargets()
62 void SpellCastTargets::read ( WorldPacket * data,Unit *caster )
65 *data >> m_targetMask;
67 if(m_targetMask == TARGET_FLAG_SELF)
69 m_destX = caster->GetPositionX();
70 m_destY = caster->GetPositionY();
71 m_destZ = caster->GetPositionZ();
72 m_unitTarget = caster;
73 return;
76 if(m_targetMask & TARGET_FLAG_UNIT)
77 m_unitTarget = ObjectAccessor::Instance().GetUnit(*caster, readGUID(data));
79 if(m_targetMask & TARGET_FLAG_OBJECT)
80 m_GOTarget = ObjectAccessor::Instance().GetGameObject(*caster, readGUID(data));
82 if((m_targetMask & TARGET_FLAG_ITEM) && caster->GetTypeId() == TYPEID_PLAYER)
84 uint64 _guid = readGUID(data);
85 m_itemTarget = ((Player*)caster)->GetItemByPos( ((Player*)caster)->GetPosByGuid(_guid));
86 if (!m_itemTarget)
88 Player* pTrader = ((Player*)caster)->GetTrader();
89 if(pTrader)
90 m_itemTarget = pTrader->GetItemByPos(pTrader->GetPosByGuid(_guid));
94 if(m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
95 *data >> m_srcX >> m_srcY >> m_srcZ;
97 if(m_targetMask & TARGET_FLAG_DEST_LOCATION)
98 *data >> m_destX >> m_destY >> m_destZ;
100 if(m_targetMask & TARGET_FLAG_STRING)
101 *data >> m_strTarget;
102 if(m_targetMask & 0x8000)
104 //0x8000 TARGET_CORPSE NEED TO ADD
108 void SpellCastTargets::write ( WorldPacket * data, bool forceAppend)
110 uint32 len = data->size();
112 // dont append targets when spell's for your own..
113 /*if(m_targetMask == TARGET_FLAG_SELF)
114 *data << (m_unitTarget ? m_unitTarget->GetGUID(): (uint64)0);*/
116 if(m_targetMask & TARGET_FLAG_UNIT)
117 if(m_unitTarget)
118 data->append(m_unitTarget->GetPackGUID());
119 else
120 *data << (uint8)0;
122 if(m_targetMask & TARGET_FLAG_OBJECT)
123 if(m_GOTarget)
124 data->append(m_GOTarget->GetPackGUID());
125 else
126 *data << (uint8)0;
128 if(m_targetMask & TARGET_FLAG_ITEM)
129 if(m_itemTarget)
130 data->append(m_itemTarget->GetPackGUID());
131 else
132 *data << (uint8)0;
134 if(m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
135 *data << m_srcX << m_srcY << m_srcZ;
137 if(m_targetMask & TARGET_FLAG_DEST_LOCATION)
138 *data << m_destX << m_destY << m_destZ;
140 if(m_targetMask & TARGET_FLAG_STRING)
141 *data << m_strTarget;
142 if(m_targetMask & 0x8000)
144 //0x8000 TARGET_CORPSE NEED TO ADD
147 if(forceAppend && data->size() == len)
148 *data << (uint8)0;
151 Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, Aura* Aur )
153 ASSERT( Caster != NULL && info != NULL );
155 //SpellEntry *spellInfo;
156 Player* p_caster;
158 m_spellInfo = info;
159 m_caster = Caster;
161 m_spellState = SPELL_STATE_NULL;
163 m_castPositionX = m_castPositionY = m_castPositionZ = 0;
164 m_TriggerSpell = NULL;
165 m_targetCount = 0;
166 m_IsTriggeredSpell = triggered;
167 //m_AreaAura = false;
168 m_CastItem = NULL;
170 unitTarget = NULL;
171 itemTarget = NULL;
172 gameObjTarget = NULL;
174 m_triggeredByAura = Aur;
175 m_autoRepeat = false;
176 if( m_spellInfo->AttributesEx2 == 0x000020 ) //Auto Shot & Shoot
177 m_autoRepeat = true;
179 casttime = GetCastTime(sCastTimesStore.LookupEntry(m_spellInfo->CastingTimeIndex));
181 if( m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo )
183 p_caster = ((Player*)m_caster);
184 ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id, SPELLMOD_CASTING_TIME, casttime);
185 casttime = int32(casttime/(100+p_caster->m_modCastSpeedPct)*100);
188 m_timer = casttime<0?0:casttime;
189 m_delayedTime = 0;
191 for(int i=0;i<3;i++)
192 m_needAliveTarget[i] = false;
194 m_meleeSpell = false;
196 m_rangedShoot = ((m_spellInfo->Attributes & 18) == 18);
197 if( m_spellInfo->StartRecoveryTime == 0 && !m_autoRepeat && !m_rangedShoot )
199 for (int i = 0; i < 3; i++)
201 if (m_spellInfo->Effect[i]==SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL ||
202 m_spellInfo->Effect[i]==SPELL_EFFECT_WEAPON_DAMAGE)
204 m_meleeSpell = true;
205 break;
211 void Spell::FillTargetMap()
214 std::list<Unit*> tmpUnitMap;
215 std::list<Item*> tmpItemMap;
216 std::list<GameObject*> tmpGOMap;
218 for(uint32 i=0;i<3;i++)
220 SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap,tmpItemMap,tmpGOMap);
221 SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap,tmpItemMap,tmpGOMap);
223 if(!m_spellInfo->EffectImplicitTargetA[i] && !m_spellInfo->EffectImplicitTargetB[i] )
225 // add here custom effects that need default target.
226 switch(m_spellInfo->Effect[i])
228 //case SPELL_EFFECT_PERSISTENT_AREA_AURA:
229 case SPELL_EFFECT_RESURRECT:
230 case SPELL_EFFECT_LEARN_SPELL:
231 case SPELL_EFFECT_SKILL_STEP:
232 case SPELL_EFFECT_SELF_RESURRECT:
233 case SPELL_EFFECT_RESURRECT_NEW:
234 case SPELL_EFFECT_PROFICIENCY:
235 case SPELL_EFFECT_PARRY:
236 case SPELL_EFFECT_DUMMY:
237 if(m_targets.getUnitTarget())
238 tmpUnitMap.push_back(m_targets.getUnitTarget());
239 break;
240 case SPELL_EFFECT_SKILL:
241 case SPELL_EFFECT_FEED_PET:
242 case SPELL_EFFECT_SUMMON_CHANGE_ITEM:
243 tmpUnitMap.push_back(m_caster);
244 break;
245 case SPELL_EFFECT_LEARN_PET_SPELL:
246 if(Pet* pet = m_caster->GetPet())
247 tmpUnitMap.push_back(pet);
248 break;
249 case SPELL_EFFECT_DISENCHANT:
250 case SPELL_EFFECT_ENCHANT_ITEM:
251 case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY:
252 case SPELL_EFFECT_ENCHANT_HELD_ITEM:
253 tmpItemMap.push_back(itemTarget);
254 break;
255 case SPELL_EFFECT_APPLY_AREA_AURA:
256 if(m_spellInfo->Attributes == 0x9050000)// AreaAura
257 SetTargetMap(i,TARGET_AREAEFFECT_PARTY,tmpUnitMap,tmpItemMap,tmpGOMap);
258 break;
259 default:
260 break;
263 if(IsChanneledSpell() && !tmpUnitMap.empty())
264 m_needAliveTarget[i] = true;
266 if(m_caster->GetTypeId() == TYPEID_PLAYER && (!m_caster->IsPvP() || ((Player*)m_caster)->pvpInfo.endTimer != 0))
268 Player *me = (Player*)m_caster;
269 for (std::list<Unit*>::const_iterator itr = tmpUnitMap.begin(); itr != tmpUnitMap.end(); itr++)
271 Unit *owner = (*itr)->GetOwner();
272 Unit *u = owner ? owner : (*itr);
273 if(u->IsPvP() && (!me->duel || me->duel->opponent != u))
274 me->UpdatePvP(true);
278 m_targetUnits[i] = tmpUnitMap;
279 m_targetItems[i] = tmpItemMap;
280 m_targetGOs[i] = tmpGOMap;
282 tmpUnitMap.clear();
283 tmpItemMap.clear();
284 tmpGOMap.clear();
288 void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap,std::list<Item*> &TagItemMap,std::list<GameObject*> &TagGOMap)
290 float radius = GetRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
291 switch(cur)
293 case TARGET_TOTEM_EARTH:
294 case TARGET_TOTEM_WATER:
295 case TARGET_TOTEM_AIR:
296 case TARGET_TOTEM_FIRE:
297 case TARGET_SELF:
298 case TARGET_DYNAMIC_OBJECT:
300 TagUnitMap.push_back(m_caster);
301 }break;
302 case TARGET_PET:
304 Pet* tmpUnit = m_caster->GetPet();
305 if (!tmpUnit) break;
306 TagUnitMap.push_back(tmpUnit);
307 }break;
308 case TARGET_SINGLE_ENEMY:
310 if(m_targets.getUnitTarget())
311 TagUnitMap.push_back(m_targets.getUnitTarget());
312 }break;
313 case TARGET_ALL_ENEMY_IN_AREA:
315 }break;
316 case TARGET_ALL_ENEMY_IN_AREA_INSTANT:
318 // targets the ground, not the units in the area
319 if (m_spellInfo->Effect[i]!=SPELL_EFFECT_PERSISTENT_AREA_AURA)
321 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
322 Cell cell = RedZone::GetZone(p);
323 cell.data.Part.reserved = ALL_DISTRICT;
324 cell.SetNoCreate();
326 MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, i, PUSH_DEST_CENTER);
328 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, ContainerMapList<Player> > player_notifier(notifier);
329 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, TypeMapContainer<AllObjectTypes> > object_notifier(notifier);
331 CellLock<GridReadGuard> cell_lock(cell, p);
332 cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
333 cell_lock->Visit(cell_lock, object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
335 }break;
336 case TARGET_ALL_PARTY_AROUND_CASTER:
338 Group* pGroup = m_caster->GetTypeId() == TYPEID_PLAYER ? ((Player*)m_caster)->groupInfo.group : NULL;
339 if(pGroup)
341 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
343 if(!pGroup->SameSubGroup(m_caster->GetGUID(), pGroup->GetMemberGUID(p)))
344 continue;
346 Unit* Target = objmgr.GetPlayer(pGroup->GetMemberGUID(p));
347 if(!Target)
348 continue;
349 if(m_caster->IsWithinDist(Target, radius))
350 TagUnitMap.push_back(Target);
353 else
354 TagUnitMap.push_back(m_caster);
355 }break;
356 case TARGET_SINGLE_FRIEND:
357 case TARGET_SINGLE_FRIEND_2:
359 if(m_targets.getUnitTarget())
360 TagUnitMap.push_back(m_targets.getUnitTarget());
361 }break;
362 case TARGET_ALL_ENEMIES_AROUND_CASTER:
364 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
365 Cell cell = RedZone::GetZone(p);
366 cell.data.Part.reserved = ALL_DISTRICT;
367 cell.SetNoCreate();
369 MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, i, PUSH_SELF_CENTER);
371 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, ContainerMapList<Player> > player_notifier(notifier);
372 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, TypeMapContainer<AllObjectTypes> > object_notifier(notifier);
374 CellLock<GridReadGuard> cell_lock(cell, p);
375 cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
376 cell_lock->Visit(cell_lock, object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
377 }break;
378 case TARGET_GAMEOBJECT:
380 if(m_targets.m_GOTarget)
381 TagGOMap.push_back(m_targets.m_GOTarget);
382 }break;
383 case TARGET_IN_FRONT_OF_CASTER:
385 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
386 Cell cell = RedZone::GetZone(p);
387 cell.data.Part.reserved = ALL_DISTRICT;
388 cell.SetNoCreate();
390 MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, i, PUSH_IN_FRONT);
392 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, ContainerMapList<Player> > player_notifier(notifier);
393 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, TypeMapContainer<AllObjectTypes> > object_notifier(notifier);
395 CellLock<GridReadGuard> cell_lock(cell, p);
396 cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
397 cell_lock->Visit(cell_lock, object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
398 }break;
399 case TARGET_DUELVSPLAYER:
401 if(m_targets.getUnitTarget())
402 TagUnitMap.push_back(m_targets.getUnitTarget());
403 }break;
404 case TARGET_GAMEOBJECT_ITEM:
406 if(m_targets.getUnitTarget())
407 TagUnitMap.push_back(m_targets.getUnitTarget());
408 if(m_targets.m_itemTarget)
409 TagItemMap.push_back(m_targets.m_itemTarget);
410 }break;
411 case TARGET_ALL_ENEMY_IN_AREA_CHANNELED:
413 // targets the ground, not the units in the area
414 if (m_spellInfo->Effect[i]!=SPELL_EFFECT_PERSISTENT_AREA_AURA)
416 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
417 Cell cell = RedZone::GetZone(p);
418 cell.data.Part.reserved = ALL_DISTRICT;
419 cell.SetNoCreate();
421 MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, i, PUSH_DEST_CENTER);
423 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, ContainerMapList<Player> > player_notifier(notifier);
424 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, TypeMapContainer<AllObjectTypes> > object_notifier(notifier);
426 CellLock<GridReadGuard> cell_lock(cell, p);
427 cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
428 cell_lock->Visit(cell_lock, object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
430 }break;
431 case TARGET_MINION:
433 if(m_spellInfo->Effect[i] != 83) TagUnitMap.push_back(m_caster);
434 }break;
435 case TARGET_SINGLE_PARTY:
437 if(m_targets.getUnitTarget())
438 TagUnitMap.push_back(m_targets.getUnitTarget());
439 }break;
440 case TARGET_AREAEFFECT_PARTY:
442 Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER
443 ? (Player*)m_targets.getUnitTarget() : NULL;
445 Group* pGroup = targetPlayer ? targetPlayer->groupInfo.group : NULL;
446 if(pGroup)
448 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
450 if(!pGroup->SameSubGroup(m_caster->GetGUID(), pGroup->GetMemberGUID(p)))
451 continue;
453 Unit* Target = objmgr.GetPlayer(pGroup->GetMemberGUID(p));
454 if(m_targets.getUnitTarget() && Target && m_targets.getUnitTarget()->IsWithinDist(Target, radius) )
455 TagUnitMap.push_back(Target);
458 else if(m_targets.getUnitTarget())
459 TagUnitMap.push_back(m_targets.getUnitTarget());
460 }break;
461 case TARGET_SELF_FISHING:
463 TagUnitMap.push_back(m_caster);
464 }break;
465 case TARGET_CHAIN:
467 bool onlyParty = false;
469 if(!m_targets.getUnitTarget())
470 break;
472 Group* pGroup = m_caster->GetTypeId() == TYPEID_PLAYER ? ((Player*)m_caster)->groupInfo.group : NULL;
473 if(pGroup)
475 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
477 if(!pGroup->SameSubGroup(m_caster->GetGUID(), pGroup->GetMemberGUID(p)))
478 continue;
480 if(m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetGUID() == pGroup->GetMemberGUID(p))
482 onlyParty = true;
483 break;
486 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
488 if(!pGroup->SameSubGroup(m_caster->GetGUID(), pGroup->GetMemberGUID(p)))
489 continue;
491 Unit* Target = objmgr.GetPlayer(pGroup->GetMemberGUID(p));
493 if(!Target || Target->GetGUID() == m_caster->GetGUID())
494 continue;
495 if(Target->getFaction() == m_caster->getFaction() && m_caster->IsWithinDist(Target, radius))
496 TagUnitMap.push_back(Target);
499 else if(m_targets.getUnitTarget())
500 TagUnitMap.push_back(m_targets.getUnitTarget());
501 }break;
502 case TARGET_CURRENT_SELECTED_ENEMY:
504 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
505 Cell cell = RedZone::GetZone(p);
506 cell.data.Part.reserved = ALL_DISTRICT;
507 cell.SetNoCreate();
508 MaNGOS::SpellNotifierPlayer notifier(*this, TagUnitMap, i);
509 TypeContainerVisitor<MaNGOS::SpellNotifierPlayer, ContainerMapList<Player> > player_notifier(notifier);
510 CellLock<GridReadGuard> cell_lock(cell, p);
511 cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
512 }break;
513 default:
515 }break;
516 case TARGET_AREAEFFECT_PARTY_AND_CLASS:
518 Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER
519 ? (Player*)m_targets.getUnitTarget() : NULL;
521 Group* pGroup = targetPlayer ? targetPlayer->groupInfo.group : NULL;
522 if(pGroup)
524 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
526 if(!pGroup->SameSubGroup(m_caster->GetGUID(), pGroup->GetMemberGUID(p)))
527 continue;
529 Unit* Target = objmgr.GetPlayer(pGroup->GetMemberGUID(p));
530 if(Target && targetPlayer->IsWithinDist(Target, radius) &&
531 targetPlayer->getClass() == Target->getClass())
532 TagUnitMap.push_back(Target);
535 else if(m_targets.getUnitTarget())
536 TagUnitMap.push_back(m_targets.getUnitTarget());
537 }break;
540 if (m_spellInfo->MaxAffectedTargets != 0 && TagUnitMap.size() > m_spellInfo->MaxAffectedTargets)
542 // make sure one unit is always removed per iteration
543 uint32 removed_utarget = 0;
544 for (std::list<Unit*>::iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end(); ++itr)
546 if (!*itr) continue;
547 if ((*itr) == m_targets.getUnitTarget())
549 TagUnitMap.erase(itr);
550 removed_utarget = 1;
551 break;
554 // remove random units from the map
555 while (TagUnitMap.size() > m_spellInfo->MaxAffectedTargets - removed_utarget)
557 uint32 poz = urand(0, TagUnitMap.size()-1);
558 for (std::list<Unit*>::iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end(); ++itr, --poz)
560 if (!*itr) continue;
561 if (!poz)
563 TagUnitMap.erase(itr);
564 break;
568 // the player's target will always be added to the map
569 if (removed_utarget && m_targets.getUnitTarget())
570 TagUnitMap.push_back(m_targets.getUnitTarget());
574 void Spell::prepare(SpellCastTargets * targets)
576 m_targets = *targets;
577 if(!unitTarget)
578 unitTarget = m_targets.getUnitTarget();
579 if(!itemTarget)
580 itemTarget = m_targets.m_itemTarget;
581 if(!gameObjTarget)
582 gameObjTarget = m_targets.m_GOTarget;
584 m_spellState = SPELL_STATE_PREPARING;
586 m_castPositionX = m_caster->GetPositionX();
587 m_castPositionY = m_caster->GetPositionY();
588 m_castPositionZ = m_caster->GetPositionZ();
589 m_castOrientation = m_caster->GetOrientation();
591 uint8 result = CanCast();
592 if(result != 0)
594 if(m_triggeredByAura)
596 SendChannelUpdate(0);
597 m_triggeredByAura->SetAuraDuration(0);
599 finish();
600 return;
603 // do first cast of autorepeat spell with recovery time delay (like after any authocast)
604 if(IsAutoRepeat())
605 m_spellState = SPELL_STATE_FINISHED;
607 if(m_IsTriggeredSpell)
608 cast(true);
609 else
611 m_caster->castSpell( this );
612 SendSpellStart();
616 void Spell::cancel()
618 if(m_spellState == SPELL_STATE_FINISHED)
619 return;
621 m_autoRepeat = false;
622 if(m_spellState == SPELL_STATE_PREPARING)
624 SendInterrupted(0);
625 SendCastResult(CAST_FAIL_INTERRUPTED);
627 else if(m_spellState == SPELL_STATE_CASTING)
629 for (int j = 0; j < 3; j++)
630 for(std::list<Unit*>::iterator iunit= m_targetUnits[j].begin();iunit != m_targetUnits[j].end();++iunit)
631 if (*iunit && (*iunit)->isAlive())
632 (*iunit)->RemoveAurasDueToSpell(m_spellInfo->Id);
634 m_caster->RemoveAurasDueToSpell(m_spellInfo->Id);
635 SendChannelUpdate(0);
636 SendInterrupted(0);
637 SendCastResult(CAST_FAIL_INTERRUPTED);
640 finish();
641 m_caster->RemoveDynObject(m_spellInfo->Id);
642 m_caster->RemoveGameObject(m_spellInfo->Id,true);
645 void Spell::cast(bool skipCheck)
647 uint32 mana = 0;
648 uint8 castResult = 0;
649 if(m_caster->GetTypeId() != TYPEID_PLAYER && unitTarget)
650 m_caster->SetInFront(unitTarget);
652 castResult = CheckMana( &mana);
653 if(castResult != 0)
655 SendCastResult(castResult);
656 finish();
657 return;
660 // triggered cast called from Spell::preper where it already checked
661 if(!skipCheck)
662 castResult = CanCast();
664 if(castResult == 0)
666 SendSpellCooldown();
668 TakePower(mana);
669 TakeCastItem();
670 TakeReagents();
671 FillTargetMap();
672 SendCastResult(castResult);
673 SendSpellGo();
675 if(IsChanneledSpell())
677 m_spellState = SPELL_STATE_CASTING;
678 SendChannelStart(GetDuration(m_spellInfo));
681 std::list<Unit*>::iterator iunit;
682 std::list<Item*>::iterator iitem;
683 std::list<GameObject*>::iterator igo;
685 bool needspelllog = true;
686 for(uint32 j = 0;j<3;j++)
688 // Dont do spell log, if is school damage spell
689 if(m_spellInfo->Effect[j] == 2 || m_spellInfo->Effect[j] == 0)
690 needspelllog = false;
691 for(iunit= m_targetUnits[j].begin();iunit != m_targetUnits[j].end();iunit++)
693 // let the client worry about this
694 /*if((*iunit)->GetTypeId() != TYPEID_PLAYER && m_spellInfo->TargetCreatureType)
696 CreatureInfo const *cinfo = ((Creature*)(*iunit))->GetCreatureInfo();
697 if((m_spellInfo->TargetCreatureType & cinfo->type) == 0)
698 continue;
700 HandleEffects((*iunit),NULL,NULL,j);
702 for(iitem= m_targetItems[j].begin();iitem != m_targetItems[j].end();iitem++)
703 HandleEffects(NULL,(*iitem),NULL,j);
704 for(igo= m_targetGOs[j].begin();igo != m_targetGOs[j].end();igo++)
705 HandleEffects(NULL,NULL,(*igo),j);
707 // persistent area auras target only the ground
708 if(m_spellInfo->Effect[j] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
709 HandleEffects(NULL,NULL,NULL, j);
712 if(needspelllog) SendLogExecute();
714 bool canreflect = false;
715 for(int j=0;j<3;j++)
717 switch(m_spellInfo->EffectImplicitTargetA[j])
719 case TARGET_SINGLE_ENEMY:
720 case TARGET_ALL_ENEMY_IN_AREA:
721 case TARGET_ALL_ENEMY_IN_AREA_INSTANT:
722 case TARGET_ALL_ENEMIES_AROUND_CASTER:
723 case TARGET_IN_FRONT_OF_CASTER:
724 case TARGET_DUELVSPLAYER:
725 case TARGET_ALL_ENEMY_IN_AREA_CHANNELED:
726 //case TARGET_AE_SELECTED:
727 canreflect = true;
728 break;
730 default:
731 canreflect = (m_spellInfo->AttributesEx & (1<<7)) ? true : false;
733 if(canreflect)
734 continue;
735 else break;
737 if(canreflect)
739 for(iunit= UniqueTargets.begin();iunit != UniqueTargets.end();iunit++)
741 reflect(*iunit);
745 //if( ( IsAutoRepeat() || m_rangedShoot ) && m_caster->GetTypeId() == TYPEID_PLAYER )
746 //((Player*)m_caster)->UpdateWeaponSkill(RANGED_ATTACK);
749 if(m_spellState != SPELL_STATE_CASTING)
750 finish();
752 //if(castResult == 0)
754 // TriggerSpell();
758 // cast at creature (or GO) quest objectives update
759 if( m_caster->GetTypeId() == TYPEID_PLAYER)
761 if( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
763 ((Player*)m_caster)->CastedCreatureOrGO(unitTarget->GetEntry(),unitTarget->GetGUID(),m_spellInfo->Id);
766 if( gameObjTarget )
768 ((Player*)m_caster)->CastedCreatureOrGO(gameObjTarget->GetEntry(),gameObjTarget->GetGUID(),m_spellInfo->Id);
773 void Spell::SendSpellCooldown()
775 if(m_caster->GetTypeId() != TYPEID_PLAYER)
776 return;
778 Player* _player = (Player*)m_caster;
780 uint32 cat = m_spellInfo->Category;
781 int32 rec = m_spellInfo->RecoveryTime;
782 int32 catrec = m_spellInfo->CategoryRecoveryTime;
784 // shoot spells used equiped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
785 if (!rec && !catrec && (cat == 76 || cat == 351))
786 rec = _player->GetAttackTime(RANGED_ATTACK);
788 // some special item spells without correct cooldown in SpellInfo
789 // cooldown information stored in item prototype
790 // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client.
791 if( rec == 0 && catrec == 0 && m_CastItem)
793 ItemPrototype const* proto = m_CastItem->GetProto();
794 if(proto)
796 for(int idx = 0; idx < 5; ++idx)
798 if(proto->Spells[idx].SpellId == m_spellInfo->Id)
800 cat = proto->Spells[idx].SpellCategory;
801 rec = proto->Spells[idx].SpellCooldown;
802 catrec = proto->Spells[idx].SpellCategoryCooldown;
803 break;
809 if(rec > 0)
810 _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, rec);
812 if(catrec > 0)
813 _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, catrec);
815 if (rec < 0) rec = 0;
816 if (catrec < 0) catrec = 0;
818 // no cooldown after applying spell mods
819 if( rec == 0 && catrec == 0)
820 return;
822 time_t curTime = time(NULL);
824 time_t recTime = curTime+rec/1000; // in secs
825 time_t catrecTime = curTime+catrec/1000; // in secs
827 WorldPacket data(SMSG_SPELL_COOLDOWN, (8+4+4+4+4));
828 data << m_caster->GetGUID();
830 // self spell cooldown
831 if (rec > 0)
833 data << uint32(m_spellInfo->Id);
834 data << uint32(rec);
835 _player->AddSpellCooldown(m_spellInfo->Id,recTime);
837 else
839 data << uint32(m_spellInfo->Id);
840 data << uint32(catrec);
841 _player->AddSpellCooldown(m_spellInfo->Id,catrecTime);
844 if (catrec > 0)
846 PlayerSpellMap const& player_spells = _player->GetSpellMap();
847 for (PlayerSpellMap::const_iterator itr = player_spells.begin(); itr != player_spells.end(); ++itr)
849 if(m_spellInfo->Id==itr->first)
850 continue;
852 if(itr->second->state == PLAYERSPELL_REMOVED || !itr->second->active)
853 continue;
855 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
856 if( spellInfo->Category == cat)
858 data << uint32(itr->first);
859 data << uint32(catrec);
860 _player->AddSpellCooldown(itr->first,catrecTime);
865 _player->GetSession()->SendPacket(&data);
867 // show cooldown for item
868 if(m_CastItem)
870 data.Initialize(SMSG_ITEM_COOLDOWN, (8+4));
871 data << m_CastItem->GetGUID();
872 data << uint32(m_spellInfo->Id);
873 _player->GetSession()->SendPacket(&data);
877 void Spell::update(uint32 difftime)
879 if(unitTarget && !unitTarget->isAlive())
881 if(m_autoRepeat)
883 m_autoRepeat = false;
884 m_spellState = SPELL_STATE_FINISHED;
885 return;
889 // check if the player caster has moved before the spell finished
890 if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) &&
891 (m_castPositionX != m_caster->GetPositionX() || m_castPositionY != m_caster->GetPositionY() || m_castPositionZ != m_caster->GetPositionZ()))
893 // always cancel for channeled spells
894 if( m_spellState == SPELL_STATE_CASTING )
895 cancel();
896 // don't cancel for instant and melee spells
897 else if(!m_meleeSpell && casttime != 0)
898 cancel();
901 switch(m_spellState)
903 case SPELL_STATE_PREPARING:
905 if(m_timer)
907 if(difftime >= m_timer)
908 m_timer = 0;
909 else
910 m_timer -= difftime;
913 if(m_timer == 0 && !m_meleeSpell)
914 cast();
915 } break;
916 case SPELL_STATE_CASTING:
918 if(m_timer > 0)
920 if( m_caster->GetTypeId() == TYPEID_PLAYER )
922 // check if player has jumped before the channeling finished
923 if( ((Player*)m_caster)->HasMovementFlags(MOVEMENTFLAG_JUMPING) )
924 cancel();
926 // check for incapacitating player states
927 if( m_caster->hasUnitState(UNIT_STAT_STUNDED) ||
928 m_caster->hasUnitState(UNIT_STAT_ROOT) ||
929 m_caster->hasUnitState(UNIT_STAT_CONFUSED) )
930 cancel();
932 // check if player has turned if flag is set
933 if( m_spellInfo->ChannelInterruptFlags & CHANNEL_FLAG_TURNING && m_castOrientation != m_caster->GetOrientation() )
934 cancel();
937 // check if there are alive targets left
938 for(int i=0;i<3;i++)
940 if(m_needAliveTarget[i])
942 bool targetLeft = false;
943 for(std::list<Unit*>::iterator iunit= m_targetUnits[i].begin();iunit != m_targetUnits[i].end();++iunit)
944 if(*iunit && (*iunit)->isAlive())
946 targetLeft = true;
947 break;
949 if(!targetLeft)
950 cancel();
954 if(difftime >= m_timer)
955 m_timer = 0;
956 else
957 m_timer -= difftime;
960 if(m_timer == 0)
962 SendChannelUpdate(0);
963 finish();
965 } break;
966 default:
968 }break;
972 void Spell::finish()
975 if(!m_caster) return;
977 m_spellState = SPELL_STATE_FINISHED;
978 m_caster->m_canMove = true;
980 /*std::list<DynamicObject*>::iterator i;
981 for(i = m_dynObjToDel.begin() ; i != m_dynObjToDel.end() ; i++)
983 data.Initialize(SMSG_GAMEOBJECT_DESPAWN_ANIM);
984 data << (*i)->GetGUID();
985 m_caster->SendMessageToSet(&data, true);
987 data.Initialize(SMSG_DESTROY_OBJECT);
988 data << (*i)->GetGUID();
989 m_caster->SendMessageToSet(&data, true);
990 ObjectAccessor::Instance().AddObjectToRemoveList(*i);
991 m_AreaAura = false;
993 m_dynObjToDel.clear();
995 std::list<GameObject*>::iterator k;
996 for(k = m_ObjToDel.begin() ; k != m_ObjToDel.end() ; k++)
998 data.Initialize(SMSG_GAMEOBJECT_DESPAWN_ANIM);
999 data << (*k)->GetGUID();
1000 m_caster->SendMessageToSet(&data, true);
1002 data.Initialize(SMSG_DESTROY_OBJECT);
1003 data << (*k)->GetGUID();
1004 m_caster->SendMessageToSet(&data, true);
1005 ObjectAccessor::Instance().AddObjectToRemoveList(*k);
1008 m_ObjToDel.clear();*/
1010 if(m_TriggerSpell)
1011 TriggerSpell();
1014 void Spell::SendCastResult(uint8 result)
1016 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1017 return;
1019 WorldPacket data(SMSG_CAST_RESULT, (4+2));
1020 data << m_spellInfo->Id;
1021 if(result != 0)
1023 data << uint8(2); // status = fail
1024 data << uint8(result); // problem
1025 switch (result)
1027 case CAST_FAIL_REQUIRES_XXX:
1028 data << uint32(m_spellInfo->RequiresSpellFocus);
1029 break;
1032 else
1033 data << uint8(0); // status = ok
1035 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1038 void Spell::SendSpellStart()
1040 sLog.outDebug("Sending SMSG_SPELL_START");
1042 m_castFlags = CAST_FLAG_UNKNOWN1;
1043 if(m_rangedShoot)
1044 m_castFlags = m_castFlags | CAST_FLAG_AMMO;
1046 Unit * target;
1047 if(!unitTarget)
1048 target = m_caster;
1049 else
1050 target = unitTarget;
1052 WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2));
1053 //data.append(target->GetPackGUID());
1054 /* in fact this should be the causer's guid. so if you clicked on a item and
1055 this caused spell it has to be the item's guid
1057 data.append(m_caster->GetPackGUID());
1058 data.append(m_caster->GetPackGUID());
1059 data << m_spellInfo->Id;
1060 data << m_castFlags;
1061 data << uint32(m_timer);
1063 data << m_targets.m_targetMask;
1064 m_targets.write( &data );
1065 if( m_castFlags & CAST_FLAG_AMMO )
1067 writeAmmoToPacket(&data);
1069 m_caster->SendMessageToSet(&data, true);
1072 void Spell::SendSpellGo()
1074 sLog.outDebug("Sending SMSG_SPELL_GO");
1076 Unit * target;
1077 if(!unitTarget)
1078 target = m_caster;
1079 else
1080 target = unitTarget;
1082 m_castFlags = CAST_FLAG_UNKNOWN3;
1083 if(m_rangedShoot)
1084 m_castFlags = m_castFlags | CAST_FLAG_AMMO;
1086 WorldPacket data(SMSG_SPELL_GO, (50)); // guess size
1087 //data.append(target->GetPackGUID());
1088 /* in fact this should be the causer's guid. so if you clicked on a item and
1089 this caused spell it has to be the item's guid
1091 data.append(m_caster->GetPackGUID());
1092 data.append(m_caster->GetPackGUID());
1093 data << m_spellInfo->Id;
1095 data << m_castFlags;
1096 writeSpellGoTargets(&data);
1098 data << (uint8)0; // miss count
1100 data << m_targets.m_targetMask;
1101 m_targets.write( &data, true );
1102 if( m_castFlags & CAST_FLAG_AMMO )
1104 writeAmmoToPacket(&data);
1107 m_caster->SendMessageToSet(&data, true);
1110 void Spell::writeAmmoToPacket( WorldPacket * data )
1112 uint32 ammoInventoryType = 0;
1113 uint32 ammoDisplayID = 0;
1114 Item *pItem = ((Player*)m_caster)->GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED );
1115 if(pItem)
1117 ammoInventoryType = pItem->GetProto()->InventoryType;
1118 if( ammoInventoryType == INVTYPE_THROWN )
1119 ammoDisplayID = pItem->GetProto()->DisplayInfoID;
1120 else
1122 uint32 ammoID = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID);
1123 if(ammoID)
1125 ItemPrototype const *pProto = objmgr.GetItemPrototype( ammoID );
1126 if(pProto)
1128 ammoDisplayID = pProto->DisplayInfoID;
1129 ammoInventoryType = pProto->InventoryType;
1134 *data << ammoDisplayID;
1135 *data << ammoInventoryType;
1138 void Spell::writeSpellGoTargets( WorldPacket * data )
1140 bool add = true;
1142 std::list<Unit*>::iterator i,j;
1143 std::list<GameObject*>::iterator m,n;
1145 for(int k=0;k<3;k++)
1147 for ( i = m_targetUnits[k].begin(); i != m_targetUnits[k].end(); i++ )
1149 for(j = UniqueTargets.begin(); j != UniqueTargets.end(); j++ )
1151 if((*j) == (*i))
1153 add = false;
1154 break;
1157 if(*i && add)
1158 UniqueTargets.push_back(*i);
1159 add = true;
1161 for ( m = m_targetGOs[k].begin(); m != m_targetGOs[k].end(); m++ )
1163 for(n = UniqueGOsTargets.begin(); n != UniqueGOsTargets.end(); n++ )
1165 if((*n) == (*m))
1167 add = false;
1168 break;
1171 if(*m && add)
1172 UniqueGOsTargets.push_back(*m);
1173 add = true;
1177 m_targetCount = UniqueTargets.size() + UniqueGOsTargets.size();
1178 *data << m_targetCount;
1180 for ( std::list<Unit*>::iterator ui = UniqueTargets.begin(); ui != UniqueTargets.end(); ui++ )
1181 *data << (*ui)->GetGUID();
1183 for ( std::list<GameObject*>::iterator uj = UniqueGOsTargets.begin(); uj != UniqueGOsTargets.end(); uj++ )
1184 *data << (*uj)->GetGUID();
1188 void Spell::SendLogExecute()
1190 Unit * target;
1191 if(!unitTarget)
1192 target = m_caster;
1193 else
1194 target = unitTarget;
1195 WorldPacket data(SMSG_SPELLLOGEXECUTE, (8+4+4+4+4+8));
1197 if(m_caster->GetTypeId() == TYPEID_PLAYER)
1198 data.append(m_caster->GetPackGUID());
1199 else
1200 data.append(target->GetPackGUID());
1202 data << m_spellInfo->Id;
1203 data << uint32(1);
1204 data << m_spellInfo->SpellVisual;
1205 data << uint32(1);
1207 if(m_targets.getUnitTarget())
1208 data << m_targets.getUnitTarget()->GetGUID();
1209 else if(m_targets.m_itemTarget)
1210 data << m_targets.m_itemTarget->GetGUID();
1211 else if(m_targets.m_GOTarget)
1212 data << m_targets.m_GOTarget->GetGUID();
1214 m_caster->SendMessageToSet(&data,true);
1217 void Spell::SendInterrupted(uint8 result)
1219 WorldPacket data;
1221 data.Initialize(SMSG_SPELL_FAILURE, (8+4+1));
1222 data.append(m_caster->GetGUID());
1223 data << m_spellInfo->Id;
1224 data << result;
1225 m_caster->SendMessageToSet(&data, true);
1227 data.Initialize(SMSG_SPELL_FAILED_OTHER, (8+4));
1228 data.append(m_caster->GetGUID());
1229 data << m_spellInfo->Id;
1230 m_caster->SendMessageToSet(&data, true);
1233 void Spell::SendChannelUpdate(uint32 time)
1235 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1236 return;
1238 WorldPacket data( MSG_CHANNEL_UPDATE, 4 );
1239 data << time;
1241 ((Player*)m_caster)->GetSession()->SendPacket( &data );
1243 if(time == 0)
1245 m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT,0);
1246 m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT+1,0);
1247 m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL,0);
1251 void Spell::SendChannelStart(uint32 duration)
1253 Unit* target = 0;
1255 if (m_caster->GetTypeId() == TYPEID_PLAYER)
1258 target = ObjectAccessor::Instance().GetUnit(*m_caster, ((Player *)m_caster)->GetSelection());
1260 WorldPacket data( MSG_CHANNEL_START, (4+4) );
1261 data << m_spellInfo->Id;
1262 data << duration;
1264 ((Player*)m_caster)->GetSession()->SendPacket( &data );
1267 m_timer = duration;
1268 if(target)
1270 m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT,target->GetGUIDLow());
1271 m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT+1,target->GetGUIDHigh());
1273 m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL,m_spellInfo->Id);
1276 void Spell::SendResurrectRequest(Player* target)
1278 WorldPacket data(SMSG_RESURRECT_REQUEST, (8+4+1));
1279 data << m_caster->GetGUID();
1280 data << uint32(0) << uint8(0);
1282 target->GetSession()->SendPacket(&data);
1285 void Spell::SendHealSpellOnPlayer(Player* target, uint32 SpellID, uint32 Damage, bool CriticalHeal)
1287 WorldPacket data(SMSG_HEALSPELL_ON_PLAYER_OBSOLETE, (8+8+4+4+1));
1288 data.append(target->GetPackGUID());
1289 data.append(m_caster->GetPackGUID());
1290 data << SpellID;
1291 data << Damage;
1292 data << uint8(CriticalHeal);
1293 target->GetSession()->SendPacket(&data);
1296 void Spell::SendHealSpellOnPlayerPet(Player* target, uint32 SpellID, uint32 Damage, bool CriticalHeal)
1298 Pet* pet = target->GetPet();
1299 if(!pet||!pet->isAlive()) // must revive before heal
1300 return;
1302 WorldPacket data(SMSG_HEALSPELL_ON_PLAYERS_PET_OBSOLETE, (8+8+4+4+1));
1303 data.append(pet->GetPackGUID());
1304 data.append(m_caster->GetPackGUID());
1305 data << SpellID;
1306 data << Damage;
1307 data << uint8(CriticalHeal);
1308 target->GetSession()->SendPacket(&data);
1311 void Spell::SendPlaySpellVisual(uint32 SpellID)
1313 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1314 return;
1316 WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12);
1317 data << m_caster->GetGUID();
1318 data << SpellID;
1319 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1322 void Spell::TakeCastItem()
1324 if(!m_CastItem || m_caster->GetTypeId() != TYPEID_PLAYER)
1325 return;
1327 // not remove cast item at triggered spell (equipping, weapon damage, etc)
1328 if(m_IsTriggeredSpell)
1329 return;
1331 ItemPrototype const *proto = m_CastItem->GetProto();
1332 uint32 ItemClass = proto->Class;
1333 uint32 ItemSubClass = proto->SubClass;
1335 bool expendable = false;
1336 bool withoutCharges = false;
1337 int32 charges;
1339 for (int i = 0; i<5; i++)
1341 if (proto->Spells[i].SpellId)
1343 // item has limited charges
1344 if (proto->Spells[i].SpellCharges)
1346 if (proto->Spells[i].SpellCharges < 0)
1347 expendable = true;
1348 charges = int32(m_CastItem->GetUInt32Value(ITEM_FIELD_SPELL_CHARGES+i));
1350 // item has charges left
1351 if (charges > 0)
1353 --charges;
1354 if (proto->Stackable < 2)
1355 m_CastItem->SetUInt32Value(ITEM_FIELD_SPELL_CHARGES+i, charges);
1356 m_CastItem->SetState(ITEM_CHANGED, (Player*)m_caster);
1359 // all charges used
1360 if (charges == 0)
1361 withoutCharges = true;
1366 if (expendable && withoutCharges)
1368 uint32 count = 1;
1369 ((Player*)m_caster)->DestroyItemCount(m_CastItem, count, true);
1371 m_CastItem = NULL;
1375 void Spell::TakePower(uint32 mana)
1377 if(m_CastItem)
1378 return;
1380 // health as power used
1381 if(m_spellInfo->powerType == -2)
1383 m_caster->ModifyHealth( -(int32)mana );
1384 return;
1387 if(m_spellInfo->powerType <0 || m_spellInfo->powerType > POWER_HAPPINESS)
1389 sLog.outError("Spell::TakePower: Unknown power type '%d'", m_spellInfo->powerType);
1390 return;
1393 Powers powerType = Powers(m_spellInfo->powerType);
1395 m_caster->ModifyPower(powerType, -(int32)mana);
1396 if (powerType == POWER_MANA)
1398 // Set the five second timer
1399 if (m_caster->GetTypeId() == TYPEID_PLAYER && mana > 0)
1401 ((Player *)m_caster)->SetLastManaUse((uint32)getMSTime());
1406 void Spell::TakeReagents()
1408 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1409 return;
1411 Player* p_caster = (Player*)m_caster;
1412 for(uint32 x=0;x<8;x++)
1414 if(m_spellInfo->Reagent[x] == 0)
1415 continue;
1416 uint32 itemid = m_spellInfo->Reagent[x];
1417 uint32 itemcount = m_spellInfo->ReagentCount[x];
1418 if( p_caster->HasItemCount(itemid,itemcount) )
1420 if(m_CastItem && m_CastItem->GetProto()->ItemId == itemid)
1421 m_CastItem = NULL;
1423 p_caster->DestroyItemCount(itemid, itemcount, true);
1426 else
1428 SendCastResult(CAST_FAIL_ITEM_NOT_READY);
1429 return;
1434 void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i)
1436 uint8 castResult = 0;
1437 unitTarget = pUnitTarget;
1438 itemTarget = pItemTarget;
1439 gameObjTarget = pGOTarget;
1441 damage = CalculateDamage((uint8)i);
1442 uint8 eff = m_spellInfo->Effect[i];
1444 // DBC already have eff 33 in SpellEffect1 (this lines totaly redundant)
1445 //if(m_spellInfo->Id==1804)
1446 // eff = 33;
1448 sLog.outDebug( "Spell: Effect : %u", eff);
1449 if(unitTarget)
1451 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
1452 for (SpellImmuneList::iterator itr = unitTarget->m_spellImmune[IMMUNITY_EFFECT].begin(), next; itr != unitTarget->m_spellImmune[IMMUNITY_EFFECT].end(); itr = next)
1454 next = itr;
1455 next++;
1456 if((*itr)->type == eff)
1458 castResult = CAST_FAIL_IMMUNE;
1459 break;
1463 if(castResult)
1465 SendCastResult(castResult);
1466 return;
1469 if(eff<TOTAL_SPELL_EFFECTS)
1471 //sLog.outDebug( "WORLD: Spell FX %d < TOTAL_SPELL_EFFECTS ", eff);
1472 (*this.*SpellEffects[eff])(i);
1475 else
1477 sLog.outDebug( "WORLD: Spell FX %d > TOTAL_SPELL_EFFECTS ", eff);
1478 if (m_CastItem)
1479 EffectEnchantItemTmp(i);
1480 else
1482 sLog.outError("SPELL: unknown effect %u spell id %u\n",
1483 eff, m_spellInfo->Id);
1489 /*void Spell::HandleAddAura(Unit* Target)
1491 if(!Target) return;
1493 if(Target->tmpAura != 0)
1495 Target->AddAura(Target->tmpAura);
1496 Target->tmpAura = 0;
1501 void Spell::TriggerSpell()
1503 if(!m_TriggerSpell) return;
1505 Spell spell(m_caster, m_TriggerSpell, true, 0);
1506 SpellCastTargets targets;
1507 targets.setUnitTarget( m_targets.getUnitTarget());
1508 spell.prepare(&targets);
1512 uint8 Spell::CanCast()
1514 // check cooldowns to prevent cheating
1515 if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HaveSpellCooldown(m_spellInfo->Id))
1517 SendCastResult(CAST_FAIL_SPELL_NOT_READY_YET);
1518 return CAST_FAIL_SPELL_NOT_READY_YET;
1521 // cancel autorepeat spells if cast start when moving
1522 // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code)
1523 if( ((Player*)m_caster)->GetMovementFlags() && (IsAutoRepeat() || m_rangedShoot) )
1525 SendCastResult(CAST_FAIL_CANT_DO_WHILE_MOVING);
1526 return CAST_FAIL_CANT_DO_WHILE_MOVING;
1529 uint8 castResult = 0;
1531 Unit *target = m_targets.getUnitTarget();
1532 if(target)
1534 //check creaturetype
1535 uint32 SpellCreatureType = m_spellInfo->TargetCreatureType;
1537 // not find another way to fix spell target check :/
1538 if(m_spellInfo->Id == 603)
1539 SpellCreatureType = 0x7FF - 0x40; //Curse of Doom
1540 else
1541 if(m_spellInfo->Id == 2641) // Dismiss Pet
1542 SpellCreatureType = 0;
1544 if(SpellCreatureType)
1546 uint32 TargetCreatureType = 0;
1547 if(target->GetTypeId() == TYPEID_PLAYER)
1548 TargetCreatureType = 0x40; //1<<(7-1)
1549 else if ( target->GetTypeId() == TYPEID_UNIT )
1551 uint32 CType = ((Creature*)target)->GetCreatureInfo()->type;
1552 if(CType>=1)
1553 TargetCreatureType = 1 << ( ((Creature*)target)->GetCreatureInfo()->type - 1);
1554 else
1555 TargetCreatureType = 0;
1558 if(TargetCreatureType && !(SpellCreatureType & TargetCreatureType))
1560 if(TargetCreatureType == 0x40)
1561 castResult = CAST_FAIL_CANT_TARGET_PLAYERS;
1562 else
1563 castResult = CAST_FAIL_INVALID_TARGET;
1567 //If m_immuneToDispel type contain this spell type, IMMUNE spell.
1568 for (SpellImmuneList::iterator itr = target->m_spellImmune[IMMUNITY_DISPEL].begin(); itr != target->m_spellImmune[IMMUNITY_DISPEL].end(); ++itr)
1570 if((*itr)->type == m_spellInfo->Dispel)
1572 castResult = CAST_FAIL_IMMUNE;
1573 break;
1576 for (SpellImmuneList::iterator itr = target->m_spellImmune[IMMUNITY_MECHANIC].begin(); itr != unitTarget->m_spellImmune[IMMUNITY_MECHANIC].end(); ++itr)
1578 if((*itr)->type == m_spellInfo->Mechanic)
1580 castResult = CAST_FAIL_IMMUNE;
1581 break;
1585 if(m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->EquippedItemClass > 0)
1587 Item *pitem = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0,INVTYPE_WEAPON);
1588 if(!pitem)
1589 castResult = CAST_FAIL_MUST_HAVE_XXXX_IN_MAINHAND;
1590 else if(pitem->GetProto()->Class != m_spellInfo->EquippedItemClass)
1591 castResult = CAST_FAIL_MUST_HAVE_XXXX_IN_MAINHAND;
1592 else if(!(pitem->GetProto()->SubClass & m_spellInfo->EquippedItemSubClass))
1593 castResult = CAST_FAIL_MUST_HAVE_XXXX_IN_MAINHAND;
1595 //Old not working code
1596 //if((m_spellInfo->AttributesExEx & 0x4000000) && !target->HasInArc(M_PI, m_caster) )
1597 // castResult = CAST_FAIL_NOT_BEHIND_TARGET;
1599 //Must be behind the target.
1600 if( m_spellInfo->AttributesEx2 == 0x100000 && (m_spellInfo->AttributesEx & 0x200) == 0x200 && target->HasInArc(M_PI, m_caster) )
1602 SendInterrupted(2);
1603 castResult = CAST_FAIL_NOT_BEHIND_TARGET;
1605 else
1606 //Target must be facing you.
1607 if((m_spellInfo->Attributes == 0x150010) && !target->HasInArc(M_PI, m_caster) )
1609 SendInterrupted(2);
1610 castResult = CAST_FAIL_NOT_IN_FRONT_OF_TARGET;
1612 else
1613 if(m_caster->hasUnitState(UNIT_STAT_CONFUSED))
1614 castResult = CAST_FAIL_CANT_DO_WHILE_CONFUSED;
1617 if(m_caster->hasUnitState(UNIT_STAT_STUNDED))
1618 castResult = CAST_FAIL_CANT_DO_WHILE_STUNNED;
1620 if(m_caster->m_silenced)
1621 castResult = CAST_FAIL_SILENCED; //0x5A;
1623 if(castResult == 0)
1624 castResult = CheckItems(); // always check items (focus object can be required for any type casts)
1626 if(castResult == 0)
1627 castResult = CheckRange();
1629 if(castResult == 0)
1631 uint32 mana = 0;
1632 castResult = CheckMana(&mana);
1635 if( castResult != 0 )
1637 SendCastResult(castResult);
1638 return castResult;
1641 for (int i = 0; i < 3; i++)
1643 // for effects of spells that have only one target
1644 switch(m_spellInfo->Effect[i])
1646 case SPELL_EFFECT_DUMMY:
1648 if (!unitTarget) return CAST_FAIL_FAILED;
1649 if(m_spellInfo->SpellIconID == 1648)
1651 if(unitTarget->GetHealth() > unitTarget->GetMaxHealth()*0.2)
1653 castResult = CAST_FAIL_INVALID_TARGET;
1654 break;
1657 break;
1659 case SPELL_EFFECT_TAMECREATURE:
1661 if (!unitTarget) return CAST_FAIL_FAILED;
1662 if (unitTarget->GetTypeId() == TYPEID_PLAYER) return CAST_FAIL_FAILED;
1663 if (unitTarget->getLevel() > m_caster->getLevel())
1665 castResult = CAST_FAIL_TARGET_IS_TOO_HIGH;
1666 break;
1668 CreatureInfo const *cinfo = ((Creature*)unitTarget)->GetCreatureInfo();
1669 if(cinfo->type != CREATURE_TYPE_BEAST)
1671 castResult = CAST_FAIL_INVALID_TARGET;
1672 break;
1674 if(m_caster->GetPetGUID())
1676 castResult = CAST_FAIL_ALREADY_HAVE_SUMMON;
1677 break;
1679 if(m_caster->GetCharmGUID())
1681 castResult = CAST_FAIL_ALREADY_HAVE_CHARMED;
1682 break;
1684 break;
1686 case SPELL_EFFECT_LEARN_PET_SPELL:
1688 if(!unitTarget) return CAST_FAIL_FAILED;
1689 if(unitTarget->GetTypeId() == TYPEID_PLAYER) return CAST_FAIL_FAILED;
1690 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
1691 if(!learn_spellproto) return CAST_FAIL_FAILED;
1692 Creature* creatureTarget = (Creature*)unitTarget;
1693 uint8 learn_msg = 1;
1694 for(int8 x=0;x<4;x++)
1696 if((creatureTarget)->m_spells[x] == learn_spellproto->Id)
1698 castResult = CAST_FAIL_ALREADY_LEARNED_THAT_SPELL;
1699 break;
1701 SpellEntry const *has_spellproto = sSpellStore.LookupEntry(creatureTarget ->m_spells[x]);
1702 if (!has_spellproto) learn_msg = 0;
1703 else if (has_spellproto->SpellIconID == learn_spellproto->SpellIconID)
1704 learn_msg = 0;
1706 if(learn_msg)
1707 castResult = CAST_FAIL_SPELL_NOT_LEARNED;
1708 break;
1710 case SPELL_EFFECT_SKINNING:
1712 if (m_caster->GetTypeId() != TYPEID_PLAYER || !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1713 return CAST_FAIL_FAILED;
1715 if( !(unitTarget->GetUInt32Value(UNIT_FIELD_FLAGS) & UNIT_FLAG_SKINNABLE) )
1717 castResult = CAST_FAIL_NOT_SKINNABLE;
1718 break;
1721 if ( ( ((Creature*)unitTarget)->GetCreatureInfo()->type != CREATURE_TYPE_CRITTER )
1722 && ( !((Creature*)unitTarget)->lootForBody || !((Creature*)unitTarget)->loot.empty() ) )
1724 castResult = CAST_FAIL_CREATURE_MUST_BE_LOOTED_FIRST;
1725 break;
1728 int32 SkinningValue = ((Player*)m_caster)->GetSkillValue(SKILL_SKINNING);
1729 int32 TargetLevel = unitTarget->getLevel();
1730 int32 ReqValue = (SkinningValue < 100 ? (TargetLevel-10)*10 : TargetLevel*5);
1731 if (ReqValue > SkinningValue)
1733 castResult = CAST_FAIL_SKILL_NOT_HIGH_ENOUGH;
1734 break;
1737 // Fizzle at the skinning attempt finish
1738 if (m_caster->m_currentSpell == this && ReqValue > irand(SkinningValue-25, SkinningValue+5) )
1740 castResult = CAST_FAIL_FIZZLED;
1741 // 10% chance to damage the skin when fizzled
1742 if ( urand(1, 100) <= 10 )
1743 unitTarget->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
1745 break;
1747 case SPELL_EFFECT_SUMMON_DEAD_PET:
1749 Creature *pet = m_caster->GetPet();
1750 if(!pet)
1751 return CAST_FAIL_FAILED;
1752 if(pet->isAlive())
1753 return CAST_FAIL_FAILED;
1754 break;
1756 case SPELL_EFFECT_SUMMON:
1757 //case SPELL_EFFECT_SUMMON_WILD: //not store in pet field
1758 //case SPELL_EFFECT_SUMMON_GUARDIAN: //not store in pet field
1759 case SPELL_EFFECT_SUMMON_PET:
1760 case SPELL_EFFECT_SUMMON_POSSESSED:
1761 case SPELL_EFFECT_SUMMON_PHANTASM:
1762 case SPELL_EFFECT_SUMMON_CRITTER: //not store in pet field
1763 case SPELL_EFFECT_SUMMON_DEMON:
1765 if(m_caster->GetPetGUID())
1767 castResult = CAST_FAIL_ALREADY_HAVE_SUMMON;
1768 break;
1770 if(m_caster->GetCharmGUID())
1772 castResult = CAST_FAIL_ALREADY_HAVE_CHARMED;
1773 break;
1775 break;
1777 case SPELL_EFFECT_LEAP:
1778 case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER:
1780 float dis = GetRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
1781 float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation());
1782 float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation());
1783 // teleport a bit above terrainlevel to avoid falling below it
1784 float fz = MapManager::Instance().GetMap(m_caster->GetMapId())->GetHeight(fx,fy) + 1.5;
1786 float caster_pos_z = m_caster->GetPositionZ();
1787 // Control the caster to not climb or drop when +-fz > 8
1788 if(!(fz<=caster_pos_z+8 && fz>=caster_pos_z-8))
1789 castResult = CAST_FAIL_FAILED_ATTEMPT;
1790 break;
1792 default:break;
1795 if(castResult != 0)
1797 SendCastResult(castResult);
1798 return castResult;
1802 // Conflagrate - do only when preparing
1803 if (m_caster->m_currentSpell != this && m_spellInfo->SpellIconID == 12 &&
1804 m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_targets.getUnitTarget())
1806 Unit::AuraMap& t_auras = m_targets.getUnitTarget()->GetAuras();
1807 bool hasImmolate = false;
1808 for(Unit::AuraMap::iterator itr = t_auras.begin(); itr != t_auras.end(); ++itr)
1810 if (itr->second && !IsPassiveSpell(itr->second->GetId()))
1812 SpellEntry const *spellInfo = itr->second->GetSpellProto();
1813 if (!spellInfo) continue;
1814 if (spellInfo->SpellIconID != 31 || spellInfo->SpellFamilyName != SPELLFAMILY_WARLOCK) continue;
1815 hasImmolate = true;
1816 m_targets.getUnitTarget()->RemoveAurasDueToSpell(spellInfo->Id);
1817 break;
1820 if(!hasImmolate)
1822 SendCastResult(CAST_FAIL_CANT_DO_THAT_YET);
1823 return CAST_FAIL_CANT_DO_THAT_YET;
1827 for (int i = 0; i < 3; i++)
1829 switch(m_spellInfo->EffectApplyAuraName[i])
1831 case SPELL_AURA_MOD_POSSESS:
1832 case SPELL_AURA_MOD_CHARM:
1834 if(m_caster->GetPetGUID())
1836 castResult = CAST_FAIL_ALREADY_HAVE_SUMMON;
1837 break;
1839 if(m_caster->GetCharmGUID())
1841 castResult = CAST_FAIL_ALREADY_HAVE_CHARMED;
1842 break;
1844 if(unitTarget->getLevel() > CalculateDamage(i))
1846 castResult = CAST_FAIL_TARGET_IS_TOO_HIGH;
1847 break;
1850 case SPELL_AURA_MOD_STEALTH:
1851 case SPELL_AURA_MOD_INVISIBILITY:
1854 //detect if any mod is in x range.if true,can't steath.FIX ME!
1855 if(m_spellInfo->Attributes == 169148432 || m_caster->GetTypeId() != TYPEID_PLAYER)
1856 break;
1858 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
1859 Cell cell = RedZone::GetZone(p);
1860 cell.data.Part.reserved = ALL_DISTRICT;
1862 std::list<Unit*> i_data;
1863 std::list<Unit*>::iterator itr;
1864 MaNGOS::GridUnitListNotifier checker(i_data);
1866 TypeContainerVisitor<MaNGOS::GridUnitListNotifier, TypeMapContainer<AllObjectTypes> > object_checker(checker);
1867 CellLock<GridReadGuard> cell_lock(cell, p);
1868 cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId()));
1869 for(itr = i_data.begin();itr != i_data.end();++itr)
1871 if( !(*itr)->isAlive() )
1872 continue;
1874 if( !(*itr)->IsHostileTo(m_caster) )
1875 continue;
1877 if((*itr)->GetTypeId() != TYPEID_PLAYER)
1879 float attackdis = ((Creature*)(*itr))->GetAttackDistance(m_caster);
1880 if((*itr)->GetDistanceSq(m_caster) < attackdis*attackdis )
1882 castResult = CAST_FAIL_TOO_CLOSE_TO_ENEMY;
1883 break;
1888 };break;
1889 default:break;
1891 if(castResult != 0)
1893 SendCastResult(castResult);
1894 return castResult;
1897 return castResult;
1900 uint8 Spell::CheckRange()
1902 // self cast doesnt need range checking -- also for Starshards fix
1903 if (m_spellInfo->rangeIndex == 1) return 0;
1905 SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
1906 float max_range = GetMaxRange(srange);
1907 float min_range = GetMinRange(srange);
1909 if (m_caster->GetTypeId() == TYPEID_PLAYER)
1910 ((Player *)m_caster)->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, max_range);
1912 Unit *target = m_targets.getUnitTarget();
1914 if(target && target != m_caster)
1916 float dist = m_caster->GetDistanceSq(target);
1917 if(dist > max_range * max_range)
1918 return CAST_FAIL_OUT_OF_RANGE; //0x56;
1919 if(dist < min_range * min_range)
1920 return CAST_FAIL_TOO_CLOSE;
1921 if( !m_IsTriggeredSpell && !m_caster->isInFront( target, max_range) )
1922 if (m_rangedShoot || !IsPositiveSpell(m_spellInfo->Id) && casttime != 0 && !IsSingleTarget(m_spellInfo->Id))
1923 return CAST_FAIL_TARGET_NEED_TO_BE_INFRONT;
1926 if(m_targets.m_targetMask == TARGET_FLAG_DEST_LOCATION && m_targets.m_destX != 0 && m_targets.m_destY != 0 && m_targets.m_destY != 0)
1928 float dist = m_caster->GetDistanceSq(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ);
1929 if(dist > max_range * max_range)
1930 return CAST_FAIL_OUT_OF_RANGE;
1931 if(dist < min_range * min_range)
1932 return CAST_FAIL_TOO_CLOSE;
1935 return 0; // ok
1938 uint8 Spell::CheckMana(uint32 *mana)
1940 // item cast not used power
1941 if(m_CastItem)
1942 return 0;
1944 // health as power used
1945 if(m_spellInfo->powerType == -2)
1947 uint32 currentHealth = m_caster->GetHealth();
1949 uint32 healthCost;
1951 if(m_caster->GetTypeId() == TYPEID_PLAYER)
1953 PlayerLevelInfo info;
1954 objmgr.GetPlayerLevelInfo(m_caster->getRace(),m_caster->getClass(),m_caster->getLevel(),&info);
1955 healthCost = m_spellInfo->manaCost + int32(float(m_spellInfo->ManaCostPercentage)/100.0 * info.health);
1957 else
1958 healthCost = m_spellInfo->manaCost + int32(float(m_spellInfo->ManaCostPercentage)/100.0 * m_caster->GetMaxHealth());
1960 *mana = healthCost;
1961 if(currentHealth <= healthCost)
1962 return CAST_FAIL_CANT_DO_THAT_YET;
1964 return 0;
1967 if(m_spellInfo->powerType <0 || m_spellInfo->powerType > POWER_HAPPINESS)
1969 sLog.outError("Spell::CheckMana: Unknown power type '%d'", m_spellInfo->powerType);
1970 return CAST_FAIL_UNKNOWN_REASON;
1973 Powers powerType = Powers(m_spellInfo->powerType);
1975 int32 currentPower = m_caster->GetPower(powerType);
1976 int32 manaCost = m_spellInfo->manaCost;
1977 if(m_spellInfo->manaCostPerlevel)
1978 manaCost += int32(m_spellInfo->manaCostPerlevel*m_caster->getLevel());
1979 if(m_spellInfo->ManaCostPercentage)
1981 if(m_caster->GetTypeId() == TYPEID_PLAYER && powerType==POWER_MANA)
1983 PlayerLevelInfo info;
1984 objmgr.GetPlayerLevelInfo(m_caster->getRace(),m_caster->getClass(),m_caster->getLevel(),&info);
1985 manaCost += int32(float(m_spellInfo->ManaCostPercentage)/100.0 * info.mana);
1987 else
1988 manaCost += int32(float(m_spellInfo->ManaCostPercentage)/100.0*m_caster->GetMaxPower(powerType));
1991 Unit::AuraList& mPowerCostSchool = m_caster->GetAurasByType(SPELL_AURA_MOD_POWER_COST_SCHOOL);
1992 for(Unit::AuraList::iterator i = mPowerCostSchool.begin(); i != mPowerCostSchool.end(); ++i)
1993 if((*i)->GetModifier()->m_miscvalue & int32(1 << m_spellInfo->School))
1994 manaCost += (*i)->GetModifier()->m_amount;
1996 if (m_caster->GetTypeId() == TYPEID_PLAYER)
1997 ((Player *)m_caster)->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, manaCost);
1999 manaCost += m_caster->GetUInt32Value(UNIT_FIELD_POWER_COST_MODIFIER);
2001 if (manaCost < 0)
2002 manaCost = 0;
2004 *mana = manaCost;
2006 if(currentPower < manaCost)
2007 return CAST_FAIL_NOT_ENOUGH_MANA;
2008 else return 0;
2011 uint8 Spell::CheckItems()
2013 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2014 return 0;
2016 uint32 itemid, itemcount;
2017 Player* p_caster = (Player*)m_caster;
2019 if(m_CastItem)
2021 itemid = m_CastItem->GetEntry();
2022 if( !p_caster->HasItemCount(itemid,1) )
2023 return CAST_FAIL_ITEM_NOT_READY;
2024 else
2026 ItemPrototype const *proto = m_CastItem->GetProto();
2027 if(!proto)
2028 return CAST_FAIL_ITEM_NOT_READY;
2030 uint32 charges;
2031 for (int i = 0; i<5; i++)
2032 if (proto->Spells[i].SpellCharges)
2034 charges = m_CastItem->GetUInt32Value(ITEM_FIELD_SPELL_CHARGES+i);
2035 if (charges == 0)
2036 return CAST_FAIL_NO_CHARGES_REMAIN;
2039 uint32 ItemClass = proto->Class;
2040 if (ItemClass == ITEM_CLASS_CONSUMABLE && unitTarget)
2042 for (int i = 0; i < 3; i++)
2044 if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL)
2045 if (unitTarget->GetHealth() == unitTarget->GetMaxHealth())
2046 return (uint8)CAST_FAIL_ALREADY_FULL_HEALTH;
2048 // Mana Potion, Rage Potion, Thistle Tea(Rogue), ...
2049 if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE)
2051 //Check if the Caster Has Rage For Power
2052 if (m_caster->GetMaxPower(POWER_RAGE))
2054 if (unitTarget->GetPower(POWER_RAGE) == unitTarget->GetMaxPower(POWER_RAGE))
2055 return (uint8)CAST_FAIL_ALREADY_FULL_MANA;
2057 //Check if the Caster Has Energy For Power
2058 else if (m_caster->GetMaxPower(POWER_ENERGY))
2060 if (unitTarget->GetPower(POWER_ENERGY) == unitTarget->GetMaxPower(POWER_ENERGY))
2061 return (uint8)CAST_FAIL_ALREADY_FULL_MANA;
2063 //So The Player Has Mana
2064 else if (unitTarget->GetPower(POWER_MANA) == unitTarget->GetMaxPower(POWER_MANA))
2066 return (uint8)CAST_FAIL_ALREADY_FULL_MANA;
2074 if(itemTarget)
2076 if(m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->EquippedItemClass >= 0)
2078 // filter by equiped class (weapon or armor) - raw class value
2079 if(int32(itemTarget->GetProto()->Class) != m_spellInfo->EquippedItemClass)
2080 return CAST_FAIL_ITEM_NOT_READY;
2081 // filter by equiped subclass - bitmask of subclasses
2082 if((( 1 << itemTarget->GetProto()->SubClass ) & m_spellInfo->EquippedItemSubClass) == 0 )
2083 return CAST_FAIL_ITEM_NOT_READY;
2087 if(m_spellInfo->RequiresSpellFocus)
2089 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
2090 Cell cell = RedZone::GetZone(p);
2091 cell.data.Part.reserved = ALL_DISTRICT;
2093 GameObject* ok = NULL;
2094 MaNGOS::GameObjectFocusCheck go_check(m_caster,m_spellInfo->RequiresSpellFocus);
2095 MaNGOS::GameObjectSearcher<MaNGOS::GameObjectFocusCheck> checker(ok,go_check);
2097 TypeContainerVisitor<MaNGOS::GameObjectSearcher<MaNGOS::GameObjectFocusCheck>, TypeMapContainer<AllObjectTypes> > object_checker(checker);
2098 CellLock<GridReadGuard> cell_lock(cell, p);
2099 cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId()));
2101 if(!ok) return (uint8)CAST_FAIL_REQUIRES_XXX;
2103 // game object found in range
2106 for(uint32 i=0;i<8;i++)
2108 if((itemid = m_spellInfo->Reagent[i]) == 0)
2109 continue;
2110 itemcount = m_spellInfo->ReagentCount[i];
2111 if( !p_caster->HasItemCount(itemid,itemcount) )
2112 return (uint8)CAST_FAIL_ITEM_NOT_READY; //0x54
2115 uint32 totems = 2;
2116 for(int i=0;i<2;i++)
2118 if(m_spellInfo->Totem[i] != 0)
2120 if( p_caster->HasItemCount(m_spellInfo->Totem[i],1) )
2122 totems -= 1;
2123 continue;
2125 }else
2126 totems -= 1;
2128 if(totems != 0)
2129 return uint8(0x70);
2131 if (!itemTarget)
2132 return uint8(0);
2134 for(int i = 0; i < 3; i++)
2136 switch (m_spellInfo->Effect[i])
2138 case SPELL_EFFECT_CREATE_ITEM:
2140 if (m_spellInfo->EffectItemType[i])
2142 uint16 dest;
2143 uint8 msg = p_caster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->EffectItemType[i], 1, false );
2144 if (msg != EQUIP_ERR_OK )
2146 p_caster->SendEquipError( msg, NULL, NULL );
2147 return uint8(CAST_FAIL_FAILED); // TODO: don't show two errors
2150 break;
2152 case SPELL_EFFECT_ENCHANT_ITEM:
2153 case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY:
2154 case SPELL_EFFECT_ENCHANT_HELD_ITEM:
2156 if(int32(m_spellInfo->EquippedItemClass) >= 0 && itemTarget->GetProto()->Class != m_spellInfo->EquippedItemClass)
2157 return CAST_FAIL_ENCHANT_NOT_EXISTING_ITEM;
2158 if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENCHANT_HELD_ITEM && !itemTarget->IsEquipped())
2159 return CAST_FAIL_ENCHANT_NOT_EXISTING_ITEM;
2160 break;
2162 case SPELL_EFFECT_DISENCHANT:
2164 uint32 item_quality = itemTarget->GetProto()->Quality;
2165 if(item_quality > 4 || item_quality < 2)
2166 return CAST_FAIL_CANT_BE_DISENCHANTED;
2167 if(itemTarget->GetProto()->Class != ITEM_CLASS_WEAPON && itemTarget->GetProto()->Class != ITEM_CLASS_ARMOR)
2168 return CAST_FAIL_CANT_BE_DISENCHANTED;
2169 break;
2171 case SPELL_EFFECT_WEAPON_DAMAGE:
2172 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
2174 if(m_caster->GetTypeId() != TYPEID_PLAYER) return CAST_FAIL_FAILED;
2175 if(m_spellInfo->rangeIndex == 1 || m_spellInfo->rangeIndex == 2 || m_spellInfo->rangeIndex == 7)
2176 break;
2177 Item *pItem = ((Player*)m_caster)->GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED );
2178 if(!pItem || pItem->IsBroken())
2179 return CAST_FAIL_MUST_HAVE_ITEM_EQUIPPED;
2181 uint32 type = pItem->GetProto()->InventoryType;
2182 uint32 ammo;
2183 if( type == INVTYPE_THROWN )
2184 ammo = pItem->GetEntry();
2185 else
2186 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID);
2188 if( !((Player*)m_caster)->HasItemCount( ammo, 1 ) )
2189 return CAST_FAIL_NO_AMMO;
2190 break;
2192 default:break;
2196 return uint8(0);
2199 uint32 Spell::CalculateDamage(uint8 i)
2201 uint32 value = 0;
2202 uint32 level = 0;
2203 // currently the damage should not be increased by level
2204 /*uint32 level = m_caster->getLevel();
2205 if( level > m_spellInfo->maxLevel && m_spellInfo->maxLevel > 0)
2206 level = m_spellInfo->maxLevel;*/
2207 float basePointsPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2208 float randomPointsPerLevel = m_spellInfo->EffectDicePerLevel[i];
2209 uint32 basePoints = uint32(m_spellInfo->EffectBasePoints[i]+level*basePointsPerLevel);
2210 uint32 randomPoints = uint32(m_spellInfo->EffectDieSides[i]+level*randomPointsPerLevel);
2211 float comboDamage = m_spellInfo->EffectPointsPerComboPoint[i];
2212 uint8 comboPoints=0;
2213 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2214 comboPoints = (uint8)((m_caster->GetUInt32Value(PLAYER_FIELD_BYTES) & 0xFF00) >> 8);
2215 value += m_spellInfo->EffectBaseDice[i];
2216 if(randomPoints <= 1)
2217 value = basePoints+1;
2218 else
2219 value = basePoints+rand()%randomPoints;
2221 if(comboDamage > 0)
2223 value += (uint32)(comboDamage * comboPoints);
2224 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2225 m_caster->SetUInt32Value(PLAYER_FIELD_BYTES,((m_caster->GetUInt32Value(PLAYER_FIELD_BYTES) & ~(0xFF << 8)) | (0x00 << 8)));
2228 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2229 ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DAMAGE, value);
2231 return value;
2234 void Spell::HandleTeleport(uint32 id, Unit* Target)
2237 if(!Target || Target->GetTypeId() != TYPEID_PLAYER)
2238 return;
2240 if(Target->isInFlight())
2241 return;
2243 if(m_spellInfo->Id == 8690 || m_spellInfo->Id == 556 )
2245 Field *fields;
2246 QueryResult *result = sDatabase.PQuery("SELECT `map`,`zone`,`position_x`,`position_y`,`position_z` FROM `character_homebind` WHERE `guid` = '%u'", m_caster->GetGUIDLow());
2247 if(!result)
2249 sLog.outError( "SPELL: No homebind location set for %i\n", m_caster->GetGUIDLow());
2250 return;
2252 fields = result->Fetch();
2254 TeleportCoords* TC = new TeleportCoords();
2255 TC->mapId = fields[0].GetUInt32();
2256 TC->x = fields[2].GetFloat();
2257 TC->y = fields[3].GetFloat();
2258 TC->z = fields[4].GetFloat();
2260 delete result;
2262 ((Player*)Target)->TeleportTo(TC->mapId,TC->x,TC->y,TC->z,Target->GetOrientation());
2263 delete TC;
2265 else
2267 TeleportCoords const* TC = objmgr.GetTeleportCoords(id);
2268 if(!TC)
2270 sLog.outError( "SPELL: unknown Teleport Coords ID %i\n", id );
2271 return;
2273 ((Player*)Target)->TeleportTo(TC->mapId,TC->x,TC->y,TC->z,Target->GetOrientation());
2277 void Spell::Delayed(int32 delaytime)
2279 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2280 return;
2282 m_timer += delaytime;
2284 if(m_timer > casttime)
2285 m_timer = (casttime > 0 ? casttime : 0);
2287 WorldPacket data(SMSG_SPELL_DELAYED, 12);
2288 data << m_caster->GetGUID();
2289 data << uint32(delaytime);
2291 ((Player*)m_caster)->GetSession()->SendPacket(&data);
2294 void Spell::DelayedChannel(int32 delaytime)
2296 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER || getState() != SPELL_STATE_CASTING)
2297 return;
2299 int32 appliedDelayTime = delaytime;
2300 uint32 duration = GetDuration(m_spellInfo);
2302 if(m_timer + delaytime < 0)
2304 appliedDelayTime = m_timer;
2305 m_timer = 0;
2307 else
2308 m_timer += delaytime;
2310 if(m_timer > duration)
2312 appliedDelayTime -= (m_timer - duration);
2313 m_timer = duration;
2316 m_delayedTime += appliedDelayTime;
2318 // Cancel spell if aggregate channeling delay is greater than base channeling duration
2319 if(m_delayedTime >= int32(duration))
2321 sLog.outDebug("Spell %u canceled because of accumulated delay: %i ms", m_spellInfo->Id, m_delayedTime);
2322 cancel();
2323 return;
2326 sLog.outDebug("Spell %u delayed for %i ms, new duration: %u ms", m_spellInfo->Id, appliedDelayTime, m_timer);
2328 for(int j = 0; j < 3; j++)
2330 // Delay auras with fixed targets
2331 for(std::list<Unit*>::iterator iunit= m_targetUnits[j].begin();iunit != m_targetUnits[j].end();++iunit)
2332 if (*iunit)
2333 (*iunit)->DelayAura(m_spellInfo->Id, j, appliedDelayTime);
2335 // Delay persistent area auras
2336 DynamicObject* dynObj = m_caster->GetDynObject(m_spellInfo->Id, j);
2337 if(dynObj)
2338 dynObj->Delay(appliedDelayTime);
2341 SendChannelUpdate(m_timer);
2344 void Spell::reflect(Unit *refunit)
2346 if (m_caster == refunit)
2347 return;
2349 SpellEntry *refspell = NULL;
2351 // if the spell to reflect is a reflect spell, do nothing.
2352 for(int i=0; i<3; i++)
2353 if(m_spellInfo->Effect[i] == 6 && (m_spellInfo->EffectApplyAuraName[i] == 74 || m_spellInfo->EffectApplyAuraName[i] == 28))
2354 return;
2356 int32 reflectchance = 0; // proper base reflect chance is ?
2358 Unit::AuraList& mReflectSpells = refunit->GetAurasByType(SPELL_AURA_REFLECT_SPELLS);
2359 for(Unit::AuraList::iterator i = mReflectSpells.begin(); i != mReflectSpells.end(); ++i)
2360 reflectchance += (*i)->GetModifier()->m_amount;
2362 Unit::AuraList& mReflectSpellsSchool = refunit->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
2363 for(Unit::AuraList::iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
2364 if((*i)->GetModifier()->m_miscvalue & int32(1 << m_spellInfo->School))
2365 reflectchance += (*i)->GetModifier()->m_amount;
2367 if (reflectchance > 0 && uint32(reflectchance) >= urand(0,100))
2369 Spell spell(refunit, refspell, true, 0);
2371 SpellCastTargets targets;
2372 targets.setUnitTarget( m_caster );
2373 spell.prepare(&targets);