[1130] Database Query Audit is now at 90 percent with this commit.
[mangos-git.git] / src / game / Spell.cpp
blobb8a27ccaef95e5e931f0152d935ab357a2211e51
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 "Opcodes.h"
24 #include "Log.h"
25 #include "UpdateMask.h"
26 #include "World.h"
27 #include "ObjectMgr.h"
28 #include "Player.h"
29 #include "Unit.h"
30 #include "Spell.h"
31 #include "DynamicObject.h"
32 #include "SpellAuras.h"
33 #include "Group.h"
34 #include "UpdateData.h"
35 #include "MapManager.h"
36 #include "ObjectAccessor.h"
37 #include "RedZoneDistrict.h"
38 #include "CellImpl.h"
39 #include "Policies/SingletonImp.h"
40 #include "SharedDefines.h"
41 #include "Tools.h"
43 #define SPELL_CHANNEL_UPDATE_INTERVAL 1000
45 extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
47 SpellCastTargets::SpellCastTargets()
49 m_unitTarget = NULL;
50 m_itemTarget = NULL;
51 m_GOTarget = NULL;
52 m_srcX = m_srcY = m_srcZ = m_destX = m_destY = m_destZ = 0;
53 m_strTarget = "";
56 SpellCastTargets::~SpellCastTargets()
59 void SpellCastTargets::read ( WorldPacket * data,Unit *caster )
62 *data >> m_targetMask;
64 if(m_targetMask & TARGET_FLAG_SELF)
65 m_unitTarget = caster;
67 if(m_targetMask & TARGET_FLAG_UNIT)
68 m_unitTarget = ObjectAccessor::Instance().GetUnit(*caster, readGUID(data));
70 if(m_targetMask & TARGET_FLAG_OBJECT)
71 m_GOTarget = ObjectAccessor::Instance().GetGameObject(*caster, readGUID(data));
73 if(m_targetMask & TARGET_FLAG_ITEM)
74 m_itemTarget = ((Player*)caster)->GetItemByGUID(readGUID(data));
76 if(m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
77 *data >> m_srcX >> m_srcY >> m_srcZ;
79 if(m_targetMask & TARGET_FLAG_DEST_LOCATION)
80 *data >> m_destX >> m_destY >> m_destZ;
82 if(m_targetMask & TARGET_FLAG_STRING)
83 *data >> m_strTarget;
87 void SpellCastTargets::write ( WorldPacket * data)
90 *data << m_targetMask;
92 if(m_targetMask & TARGET_FLAG_SELF)
93 *data << (m_unitTarget ? m_unitTarget->GetGUID(): (uint64)0);
95 if(m_targetMask & TARGET_FLAG_UNIT)
96 *data << (m_unitTarget ? m_unitTarget->GetGUID(): (uint64)0);
98 if(m_targetMask & TARGET_FLAG_OBJECT)
99 *data << (m_GOTarget ? m_GOTarget->GetGUID(): (uint64)0);
101 if(m_targetMask & TARGET_FLAG_ITEM)
102 *data << (m_itemTarget ? m_itemTarget->GetGUID(): (uint64)0);
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;
115 Spell::Spell( Unit* Caster, SpellEntry *info, bool triggered, Aura* Aur )
117 ASSERT( Caster != NULL && info != NULL );
119 SpellEntry *spellInfo;
120 Player* p_caster;
121 std::list<Playerspell*>::iterator itr;
123 std::list<Playerspell*> player_spells;
125 m_spellInfo = info;
126 m_caster = Caster;
128 m_spellState = SPELL_STATE_NULL;
130 m_castPositionX = m_castPositionY = m_castPositionZ;
131 m_TriggerSpell = NULL;
132 m_targetCount = 0;
133 m_Istriggeredpell = triggered;
134 m_AreaAura = false;
135 m_CastItem = NULL;
137 m_triggeredByAura = Aur;
139 casttime = GetCastTime(sCastTime.LookupEntry(m_spellInfo->CastingTimeIndex));
141 if( Caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo )
143 p_caster = (Player*)m_caster;
144 player_spells = p_caster->getSpellList();
145 for (itr = player_spells.begin(); itr != player_spells.end(); ++itr)
147 if ((*itr)->spellId != m_spellInfo->Id)
149 spellInfo = sSpellStore.LookupEntry((*itr)->spellId);
150 if(spellInfo && spellInfo->SpellIconID == m_spellInfo->SpellIconID && spellInfo->EffectMiscValue[0] ==10)
152 casttime=casttime+(spellInfo->EffectBasePoints[0]+1);
158 m_timer = casttime<0?0:casttime;
162 void Spell::FillTargetMap()
165 std::list<Unit*> tmpUnitMap;
166 std::list<Item*> tmpItemMap;
167 std::list<GameObject*> tmpGOMap;
169 for(uint32 i=0;i<3;i++)
172 SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap,tmpItemMap,tmpGOMap);
173 SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap,tmpItemMap,tmpGOMap);
175 if(!m_spellInfo->EffectImplicitTargetA[i] || m_spellInfo->EffectImplicitTargetB[i] )
177 // add where custom effects that need default target.
178 // Apply Aura
179 if(m_spellInfo->Effect[i] == 27) tmpUnitMap.push_back(m_caster);
180 // Learn Spell
181 else if(m_spellInfo->Effect[i] == 36) tmpUnitMap.push_back(m_targets.getUnitTarget());
182 // Learn Skill
183 else if(m_spellInfo->Effect[i] == 44) tmpUnitMap.push_back(m_targets.getUnitTarget());
184 // Execute Skill
185 else if(m_spellInfo->Effect[i] == 118) tmpUnitMap.push_back(m_caster);
188 m_targetUnits[i] = tmpUnitMap;
189 m_targetItems[i] = tmpItemMap;
190 m_targetGOs[i] = tmpGOMap;
192 tmpUnitMap.clear();
193 tmpItemMap.clear();
194 tmpGOMap.clear();
198 void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap,std::list<Item*> &TagItemMap,std::list<GameObject*> &TagGOMap)
200 float radius = GetRadius(sSpellRadius.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
201 switch(cur)
203 case TARGET_SELF:
204 case TARGET_DY_OBJ: //add by vendy
206 TagUnitMap.push_back(m_caster);
207 }break;
208 case TARGET_PET:
210 Unit* tmpUnit = ObjectAccessor::Instance().GetUnit(*m_caster,m_caster->GetUInt32Value(UNIT_FIELD_PETNUMBER));
211 TagUnitMap.push_back(tmpUnit);
212 }break;
213 case TARGET_S_E:
215 TagUnitMap.push_back(m_targets.getUnitTarget());
216 }break;
217 case TARGET_AE_E:
219 }break;
220 case TARGET_AE_E_INSTANT:
222 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
223 Cell cell = RedZone::GetZone(p);
224 cell.data.Part.reserved = ALL_DISTRICT;
225 cell.SetNoCreate();
227 MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, i,PUSH_DEST_CENTER);
228 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, TypeMapContainer<AllObjectTypes> > object_notifier(notifier);
229 CellLock<GridReadGuard> cell_lock(cell, p);
230 cell_lock->Visit(cell_lock, object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
231 }break;
232 case TARGET_AC_P:
234 Group* pGroup = objmgr.GetGroupByLeader(((Player*)m_caster)->GetGroupLeader());
235 if(pGroup)
236 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
238 Unit* Target = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(p));
239 if(!Target || Target->GetGUID() == m_caster->GetGUID())
240 continue;
241 if(m_caster->GetDistanceSq(Target) < radius * radius )
242 TagUnitMap.push_back(Target);
244 else
245 TagUnitMap.push_back(m_caster);
246 }break;
247 case TARGET_S_F_2:
249 TagUnitMap.push_back(m_targets.getUnitTarget());
250 }break;
251 case TARGET_AC_E:
253 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
254 Cell cell = RedZone::GetZone(p);
255 cell.data.Part.reserved = ALL_DISTRICT;
256 cell.SetNoCreate();
258 MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, i,PUSH_SELF_CENTER);
259 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, TypeMapContainer<AllObjectTypes> > object_notifier(notifier);
260 CellLock<GridReadGuard> cell_lock(cell, p);
261 cell_lock->Visit(cell_lock, object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
263 }break;
264 case TARGET_S_GO:
266 TagGOMap.push_back(m_targets.m_GOTarget);
267 }break;
268 case TARGET_INFRONT:
270 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
271 Cell cell = RedZone::GetZone(p);
272 cell.data.Part.reserved = ALL_DISTRICT;
273 cell.SetNoCreate();
274 MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, i,PUSH_IN_FRONT);
276 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, TypeMapContainer<AllObjectTypes> > object_notifier(notifier);
277 CellLock<GridReadGuard> cell_lock(cell, p);
279 cell_lock->Visit(cell_lock, object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
280 }break;
281 case TARGET_DUELVSPLAYER:
283 TagUnitMap.push_back(m_targets.getUnitTarget());
284 }break;
285 case TARGET_GOITEM:
287 if(m_targets.getUnitTarget())
288 TagUnitMap.push_back(m_targets.getUnitTarget());
289 if(m_targets.m_itemTarget)
290 TagItemMap.push_back(m_targets.m_itemTarget);
291 }break;
292 case TARGET_AE_E_CHANNEL:
294 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
295 Cell cell = RedZone::GetZone(p);
296 cell.data.Part.reserved = ALL_DISTRICT;
297 cell.SetNoCreate();
299 MaNGOS::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, i,PUSH_DEST_CENTER);
300 TypeContainerVisitor<MaNGOS::SpellNotifierCreatureAndPlayer, TypeMapContainer<AllObjectTypes> > object_notifier(notifier);
301 CellLock<GridReadGuard> cell_lock(cell, p);
302 cell_lock->Visit(cell_lock, object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
303 }break;
304 case TARGET_MINION:
306 if(m_spellInfo->Effect[i] != 83) TagUnitMap.push_back(m_caster);
307 }break;
308 case TARGET_S_P:
310 TagUnitMap.push_back(m_targets.getUnitTarget());
311 }break;
312 case TARGET_SELF_FISHING:
314 TagUnitMap.push_back(m_caster);
315 }break;
316 case TARGET_CHAIN:
318 bool onlyParty = false;
320 if(!m_targets.getUnitTarget())
321 break;
323 Group* pGroup = objmgr.GetGroupByLeader(((Player*)m_caster)->GetGroupLeader());
324 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
326 if(m_targets.getUnitTarget()->GetGUID() == pGroup->GetMemberGUID(p))
328 onlyParty = true;
329 break;
332 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
334 Unit* Target = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(p));
336 if(!Target || Target->GetGUID() == m_caster->GetGUID())
337 continue;
338 if(m_caster->GetDistanceSq(Target) < radius * radius && Target->GetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE) == m_caster->GetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE))
339 TagUnitMap.push_back(Target);
341 }break;
342 case TARGET_AE_SELECTED:
344 CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
345 Cell cell = RedZone::GetZone(p);
346 cell.data.Part.reserved = ALL_DISTRICT;
347 cell.SetNoCreate();
348 MaNGOS::SpellNotifierPlayer notifier(*this, TagUnitMap, i);
349 TypeContainerVisitor<MaNGOS::SpellNotifierPlayer, ContainerMapList<Player> > player_notifier(notifier);
350 CellLock<GridReadGuard> cell_lock(cell, p);
351 cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId()));
352 }break;
353 default:
355 }break;
359 void Spell::prepare(SpellCastTargets * targets)
361 uint8 result;
363 WorldPacket data;
365 m_targets = *targets;
367 SendSpellStart();
369 m_spellState = SPELL_STATE_PREPARING;
371 m_castPositionX = m_caster->GetPositionX();
372 m_castPositionY = m_caster->GetPositionY();
373 m_castPositionZ = m_caster->GetPositionZ();
375 result = CanCast();
376 if(result != 0)
378 if(m_triggeredByAura)
380 SendChannelUpdate(0);
381 m_triggeredByAura->SetDuration(0);
383 finish();
386 if(m_Istriggeredpell)
387 cast();
388 else
389 m_caster->castSpell( this );
392 void Spell::cancel()
394 WorldPacket data;
396 if(m_spellState == SPELL_STATE_PREPARING)
398 SendInterrupted(0);
399 SendCastResult(0x20);
401 else if(m_spellState == SPELL_STATE_CASTING)
403 m_caster->RemoveAura(m_spellInfo->Id);
404 SendChannelUpdate(0);
407 finish();
408 m_spellState = SPELL_STATE_FINISHED;
411 void Spell::cast()
413 WorldPacket data;
415 uint8 castResult = 0;
416 castResult = CanCast();
417 if(castResult == 0)
419 TakePower();
420 //RemoveItems();
421 FillTargetMap();
422 SendCastResult(castResult);
423 SendSpellGo();
425 if(m_spellInfo->ChannelInterruptFlags != 0)
427 m_spellState = SPELL_STATE_CASTING;
428 SendChannelStart(GetDuration(sSpellDuration.LookupEntry(m_spellInfo->DurationIndex)));
431 std::list<Unit*>::iterator iunit;
432 std::list<Item*>::iterator iitem;
433 std::list<GameObject*>::iterator igo;
435 bool needspelllog = false;
437 for(uint32 j = 0;j<3;j++)
439 if(m_spellInfo->Effect[j] != 2) // Dont do spell log, if is school damage spell
440 needspelllog = true;
441 else
442 needspelllog = false;
444 for(iunit= m_targetUnits[j].begin();iunit != m_targetUnits[j].end();iunit++)
445 HandleEffects((*iunit),NULL,NULL,j);
446 for(iitem= m_targetItems[j].begin();iitem != m_targetItems[j].end();iitem++)
447 HandleEffects(NULL,(*iitem),NULL,j);
448 for(igo= m_targetGOs[j].begin();igo != m_targetGOs[j].end();igo++)
449 HandleEffects(NULL,NULL,(*igo),j);
452 if(needspelllog) SendLogExecute();
454 for(iunit= UniqueTargets.begin();iunit != UniqueTargets.end();iunit++)
456 if((*iunit)->m_ReflectSpellSchool) reflect(*iunit);
457 HandleAddAura((*iunit));
461 if(m_spellState != SPELL_STATE_CASTING)
462 finish();
464 if(castResult == 0)
466 TriggerSpell();
472 void Spell::update(uint32 difftime)
475 if( (m_castPositionX != m_caster->GetPositionX() ||
476 m_castPositionY != m_caster->GetPositionY() ||
477 m_castPositionZ != m_caster->GetPositionZ() ) &&
478 ( m_timer != 0 ))
480 SendInterrupted(0);
481 SendCastResult(0x20);
482 if(m_spellState == SPELL_STATE_CASTING)
484 m_caster->RemoveAura(m_spellInfo->Id);
485 SendChannelUpdate(0);
487 finish();
488 m_spellState = SPELL_STATE_FINISHED;
490 switch(m_spellState)
492 case SPELL_STATE_PREPARING:
494 if(m_timer)
496 if(difftime >= m_timer)
497 m_timer = 0;
498 else
499 m_timer -= difftime;
502 if(m_timer == 0)
503 cast();
504 } break;
505 case SPELL_STATE_CASTING:
507 if(m_timer > 0)
509 if(difftime >= m_timer)
510 m_timer = 0;
511 else
512 m_timer -= difftime;
513 m_intervalTimer += difftime;
517 if(m_timer == 0)
519 SendChannelUpdate(0);
520 finish();
522 } break;
523 default:
525 }break;
530 void Spell::finish()
533 if(!m_caster) return;
535 m_spellState = SPELL_STATE_FINISHED;
536 m_caster->m_meleeSpell = false;
537 m_caster->m_canMove = true;
539 std::list<DynamicObject*>::iterator i;
540 std::list<GameObject*>::iterator k;
542 WorldPacket data;
544 for(i = m_dynObjToDel.begin() ; i != m_dynObjToDel.end() ; i++)
546 data.Initialize(SMSG_GAMEOBJECT_DESPAWN_ANIM);
547 data << (*i)->GetGUID();
548 m_caster->SendMessageToSet(&data, true);
550 data.Initialize(SMSG_DESTROY_OBJECT);
551 data << (*i)->GetGUID();
552 m_caster->SendMessageToSet(&data, true);
553 MapManager::Instance().GetMap((*i)->GetMapId())->Remove((*i), true);
556 for(k = m_ObjToDel.begin() ; k != m_ObjToDel.end() ; k++)
558 data.Initialize(SMSG_GAMEOBJECT_DESPAWN_ANIM);
559 data << (*k)->GetGUID();
560 m_caster->SendMessageToSet(&data, true);
562 data.Initialize(SMSG_DESTROY_OBJECT);
563 data << (*k)->GetGUID();
564 m_caster->SendMessageToSet(&data, true);
565 MapManager::Instance().GetMap((*k)->GetMapId())->Remove((*k), true);
568 m_dynObjToDel.clear();
569 m_ObjToDel.clear();
571 ((Player*)m_caster)->setRegenTimer(5000);
574 void Spell::SendCastResult(uint8 result)
576 if (m_caster->GetTypeId() != TYPEID_PLAYER)
577 return;
579 WorldPacket data;
581 data.Initialize(SMSG_CAST_RESULT);
582 data << m_spellInfo->Id;
583 if(result != 0)
584 data << uint8(2);
585 data << result;
587 ((Player*)m_caster)->GetSession()->SendPacket(&data);
590 void Spell::SendSpellStart()
593 WorldPacket data;
594 uint16 cast_flags;
596 cast_flags = 2;
598 data.Initialize(SMSG_SPELL_START);
599 data << uint8(0xFF) << m_caster->GetGUID() << uint8(0xFF) << m_caster->GetGUID();
600 data << m_spellInfo->Id;
601 data << cast_flags;
602 data << uint32(m_timer);
604 m_targets.write( &data );
605 ((Player*)m_caster)->SendMessageToSet(&data, true);
609 void Spell::SendSpellGo()
612 WorldPacket data;
613 uint16 flags;
615 flags = m_targets.m_targetMask;
616 if(flags == 0)
617 flags = 2;
619 data.Initialize(SMSG_SPELL_GO);
620 data << uint8(0xFF)<< m_caster->GetGUID() << uint8(0xFF) << m_caster->GetGUID();
621 data << m_spellInfo->Id;
623 data << uint16(0x0500);
624 writeSpellGoTargets(&data);
626 data << (uint8)0;
628 m_targets.write( &data );
629 m_caster->SendMessageToSet(&data, true);
633 void Spell::writeSpellGoTargets( WorldPacket * data )
635 bool add = true;
637 std::list<Unit*>::iterator i,j;
638 std::list<GameObject*>::iterator m,n;
640 for(int k=0;k<3;k++)
642 for ( i = m_targetUnits[k].begin(); i != m_targetUnits[k].end(); i++ )
644 for(j = UniqueTargets.begin(); j != UniqueTargets.end(); j++ )
646 if((*j) == (*i))
648 add = false;
649 break;
652 if(*i && add)
653 UniqueTargets.push_back(*i);
654 add = true;
656 for ( m = m_targetGOs[k].begin(); m != m_targetGOs[k].end(); m++ )
658 for(n = UniqueGOsTargets.begin(); n != UniqueGOsTargets.end(); n++ )
660 if((*n) == (*m))
662 add = false;
663 break;
666 if(*m && add)
667 UniqueGOsTargets.push_back(*m);
668 add = true;
672 m_targetCount = UniqueTargets.size() + UniqueGOsTargets.size();
673 *data << m_targetCount;
675 for ( std::list<Unit*>::iterator ui = UniqueTargets.begin(); ui != UniqueTargets.end(); ui++ )
676 *data << (*ui)->GetGUID();
678 for ( std::list<GameObject*>::iterator uj = UniqueGOsTargets.begin(); uj != UniqueGOsTargets.end(); uj++ )
679 *data << (*uj)->GetGUID();
683 void Spell::SendLogExecute()
685 WorldPacket data;
686 data.Initialize(SMSG_SPELLLOGEXECUTE);
688 if(m_caster->GetTypeId() == TYPEID_PLAYER)
689 data << uint8(0xFF) << m_caster->GetGUID();
690 else
691 data << m_caster->GetGUID();
693 data << m_spellInfo->Id;
694 data << uint32(1);
695 data << m_spellInfo->SpellVisual;
696 data << uint32(1);
698 if(m_targets.getUnitTarget())
699 data << m_targets.getUnitTarget()->GetGUID();
700 else if(m_targets.m_itemTarget)
701 data << m_targets.m_itemTarget->GetGUID();
702 else if(m_targets.m_GOTarget)
703 data << m_targets.m_GOTarget->GetGUID();
705 m_caster->SendMessageToSet(&data,true);
708 void Spell::SendInterrupted(uint8 result)
710 WorldPacket data;
712 data.Initialize(SMSG_SPELL_FAILURE);
713 data << uint8(0xFF) << m_caster->GetGUID();
714 data << m_spellInfo->Id;
715 data << result;
716 m_caster->SendMessageToSet(&data, true);
719 void Spell::SendChannelUpdate(uint32 time)
721 if (m_caster->GetTypeId() != TYPEID_PLAYER)
722 return;
724 WorldPacket data;
726 data.Initialize( MSG_CHANNEL_UPDATE );
727 data << time;
729 ((Player*)m_caster)->GetSession()->SendPacket( &data );
731 if(time == 0)
733 m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT,0);
734 m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT+1,0);
735 m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL,0);
739 void Spell::SendChannelStart(uint32 duration)
741 Unit* target = ObjectAccessor::Instance().GetCreature(*m_caster, ((Player *)m_caster)->GetSelection());
743 if (m_caster->GetTypeId() == TYPEID_PLAYER)
746 WorldPacket data;
747 data.Initialize( MSG_CHANNEL_START );
748 data << m_spellInfo->Id;
749 data << duration;
751 ((Player*)m_caster)->GetSession()->SendPacket( &data );
754 m_timer = duration;
755 if(target)
757 m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT,target->GetGUIDLow());
758 m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT+1,target->GetGUIDHigh());
760 m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL,m_spellInfo->Id);
763 void Spell::SendResurrectRequest(Player* target)
765 WorldPacket data;
766 data.Initialize(SMSG_RESURRECT_REQUEST);
767 data << uint8(0xFF) << m_caster->GetGUID();
768 data << uint32(0) << uint8(0);
770 target->GetSession()->SendPacket(&data);
773 void Spell::TakePower()
775 uint16 powerField;
776 uint32 currentPower;
778 uint8 powerType = (uint8)(m_caster->GetUInt32Value(UNIT_FIELD_BYTES_0) >> 24);
779 if(powerType == 0)
780 powerField = UNIT_FIELD_POWER1;
781 else if(powerType == 1)
782 powerField = UNIT_FIELD_POWER2;
783 else if(powerType == 3)
784 powerField = UNIT_FIELD_POWER4;
786 currentPower = m_caster->GetUInt32Value(powerField);
788 if(currentPower < m_spellInfo->manaCost)
789 m_caster->SetUInt32Value(powerField, 0);
790 else
791 m_caster->SetUInt32Value(powerField, currentPower - m_spellInfo->manaCost);
794 void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i)
797 unitTarget = pUnitTarget;
798 itemTarget = pItemTarget;
799 gameObjTarget = pGOTarget;
801 damage = CalculateDamage((uint8)i);
802 uint8 eff = m_spellInfo->Effect[i];
804 sLog.outDebug( "WORLD: Spell FX id is %u", eff);
806 if(eff<TOTAL_SPELL_EFFECTS)
807 (*this.*SpellEffects[eff])(i);
808 else
810 if (m_CastItem)
811 EffectEnchantItemTmp(i);
812 else
814 sLog.outError("SPELL: unknown effect %d spell id %i\n",
815 eff, m_spellInfo->Id);
820 void Spell::HandleAddAura(Unit* Target)
822 if(!Target) return;
824 if(Target->tmpAura != 0)
826 Target->AddAura(Target->tmpAura);
827 Target->tmpAura = 0;
831 void Spell::TriggerSpell()
833 if(!m_TriggerSpell) return;
835 Spell spell(m_caster, m_TriggerSpell,false, 0);
836 SpellCastTargets targets;
837 targets.setUnitTarget( m_targets.getUnitTarget());
838 spell.prepare(&targets);
842 uint8 Spell::CanCast()
844 uint8 castResult = 0;
846 if (m_CastItem)
848 castResult = CheckItems();
850 if(castResult != 0)
851 SendCastResult(castResult);
853 return castResult;
856 Unit *target = NULL;
857 target = m_targets.getUnitTarget();
858 float range = GetMaxRange(sSpellRange.LookupEntry(m_spellInfo->rangeIndex));
860 if(target)
862 if(!m_caster->isInFront( target, range ))
863 castResult = 0x76;
864 if(m_caster->GetDistanceSq(target) > range * range )
865 castResult = 0x56;
868 if(m_targets.m_destX != 0 && m_targets.m_destY != 0 && m_targets.m_destZ != 0 )
870 if(m_caster->GetDistanceSq( m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ) > range * range )
871 castResult = 0x56;
874 if(m_caster->m_silenced)
875 castResult = 0x5A;
876 if( castResult != 0 )
878 SendCastResult(castResult);
879 return castResult;
882 castResult = CheckItems();
884 if(castResult != 0)
885 SendCastResult(castResult);
887 return castResult;
890 uint8 Spell::CheckItems()
892 //update by Ant009,need more test.
893 if (m_caster->GetTypeId() != TYPEID_PLAYER)
894 return uint8(0);
896 Player* p_caster = (Player*)m_caster;
897 Item* itm;
898 Bag* pBag;
899 uint32 tmpReagentCount[8];
900 uint8 curSlot;
901 uint8 bagIndex;
903 for(uint32 i=0;i<8;i++)
904 tmpReagentCount[i] = m_spellInfo->ReagentCount[i];
906 for(uint32 i=0;i<8;i++)
908 if(m_spellInfo->Reagent[i] == 0)
909 continue;
911 for(uint32 j=0;j<INVENTORY_SLOT_ITEM_END;j++)
913 itm = p_caster->GetItemBySlot(j);
914 if(!itm)
915 continue;
916 if(itm->GetProto()->ItemId == m_spellInfo->Reagent[i] && tmpReagentCount[i] > 0)
917 if(itm->GetUInt32Value(ITEM_FIELD_STACK_COUNT) > tmpReagentCount[i])
918 tmpReagentCount[i] = 0;
919 else
920 tmpReagentCount[i] -= itm->GetUInt32Value(ITEM_FIELD_STACK_COUNT);
922 for(bagIndex=CLIENT_SLOT_01;bagIndex<=CLIENT_SLOT_04;bagIndex++)
924 pBag = p_caster->GetBagBySlot(bagIndex);
925 if (pBag)
926 for(uint8 pSlot=0; pSlot < pBag->GetProto()->ContainerSlots; pSlot++)
928 itm = p_caster->GetItemBySlot(bagIndex,pSlot);
929 if(!itm)
930 continue;
931 if(itm->GetProto()->ItemId == m_spellInfo->Reagent[i] && tmpReagentCount[i] > 0)
932 if(itm->GetUInt32Value(ITEM_FIELD_STACK_COUNT) > tmpReagentCount[i])
933 tmpReagentCount[i] = 0;
934 else
935 tmpReagentCount[i] -= itm->GetUInt32Value(ITEM_FIELD_STACK_COUNT);
938 pBag = NULL;
939 if(tmpReagentCount[i] != 0)
940 return uint8(0x54);
943 uint32 totems = 2;
944 for(uint32 i=0;i<2;i++)
946 if(m_spellInfo->Totem[i] != 0)
948 if(p_caster->GetSlotByItemID(m_spellInfo->Totem[i], bagIndex, curSlot,true,false))
950 itm = p_caster->GetItemBySlot(bagIndex,curSlot);
951 if(!itm)continue;
952 if(itm->GetProto()->ItemId == m_spellInfo->Totem[i])
954 totems -= 1;
955 continue;
958 }else
959 totems -= 1;
961 itm = NULL;
962 if(totems != 0)
963 return uint8(0x70);
965 return uint8(0);
968 void Spell::RemoveItems()
970 if (m_caster->GetTypeId() != TYPEID_PLAYER)
971 return;
973 Player* p_caster = (Player*)m_caster;
974 Item* itm;
976 for(uint32 i=0;i<8;i++)
978 if(m_spellInfo->Reagent[i] == 0)
979 continue;
980 for(uint8 j=0;j<INVENTORY_SLOT_ITEM_END;j++)
982 itm = p_caster->GetItemBySlot(j);
983 if(!itm)
984 continue;
985 if(itm->GetProto()->ItemId == m_spellInfo->Reagent[i])
986 //p_caster->RemoveItemFromSlot(j);
987 p_caster->RemoveItemFromSlot(0,j,true);
988 itm = NULL;
993 uint32 Spell::CalculateDamage(uint8 i)
995 uint32 value = 0;
996 float basePointsPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
997 float randomPointsPerLevel = m_spellInfo->EffectDicePerLevel[i];
998 uint32 basePoints = uint32(m_spellInfo->EffectBasePoints[i]+m_caster->getLevel()*basePointsPerLevel);
999 uint32 randomPoints = uint32(m_spellInfo->EffectDieSides[i]+m_caster->getLevel()*randomPointsPerLevel);
1000 uint32 comboDamage = uint32(m_spellInfo->EffectPointsPerComboPoint[i]);
1001 uint8 comboPoints=0;
1002 if(m_caster->GetTypeId() == TYPEID_PLAYER)
1003 comboPoints = ((m_caster->GetUInt32Value(PLAYER_FIELD_BYTES) & 0xFF00) >> 8);
1005 if(randomPoints <= 1)
1006 value = basePoints+1;
1007 else
1008 value = basePoints+rand()%randomPoints;
1010 if(comboDamage > 0)
1012 for(uint32 j=0;j<comboPoints;j++)
1013 value += comboDamage;
1014 if(m_caster->GetTypeId() == TYPEID_PLAYER)
1015 m_caster->SetUInt32Value(PLAYER_FIELD_BYTES,((m_caster->GetUInt32Value(PLAYER_FIELD_BYTES) & ~(0xFF << 8)) | (0x00 << 8)));
1018 return value;
1021 void Spell::HandleTeleport(uint32 id, Unit* Target)
1024 if(!Target) return;
1026 TeleportCoords* TC = new TeleportCoords();
1028 if(m_spellInfo->Id == 8690 )
1030 Field *fields;
1031 QueryResult *result4 = sDatabase.PQuery("SELECT `map`,`zone`,`position_x`,`position_y`,`position_z` FROM `characters_homebind` WHERE `guid` = '%d';", m_caster->GetGUID());
1032 fields = result4->Fetch();
1033 TC->mapId = fields[0].GetUInt32();
1034 TC->x = fields[2].GetFloat();
1035 TC->y = fields[3].GetFloat();
1036 TC->z = fields[4].GetFloat();
1037 delete result4;
1039 else
1041 TC = objmgr.GetTeleportCoords(id);
1042 if(!TC)
1044 sLog.outString( "SPELL: unknown Teleport Coords ID %i\n", id );
1045 return;
1049 ((Player*)Target)->smsg_NewWorld(TC->mapId,TC->x,TC->y,TC->z,0.0f);
1053 void Spell::Delayed(int32 delaytime)
1055 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) return;
1057 m_timer += delaytime;
1059 if(m_timer > casttime)
1060 m_timer = casttime;
1062 WorldPacket data;
1064 data.Initialize(SMSG_SPELL_DELAYED);
1065 data << m_caster->GetGUID();
1066 data << uint32(delaytime);
1068 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1071 void Spell::reflect(Unit *refunit)
1073 SpellEntry *refspell = NULL;
1075 // if the spell to reflect is a reflect spell, do nothing.
1076 for(int i=0; i<3; i++)
1077 if(m_spellInfo->Effect[i] == 6 && m_spellInfo->EffectApplyAuraName[i] == 74)
1078 return;
1080 switch(refunit->m_ReflectSpellSchool)
1082 case 126: // All
1083 refspell = m_spellInfo;
1084 break;
1085 case 4: // Fire
1086 refspell = (m_spellInfo->School == 2 ? m_spellInfo : NULL);
1087 break;
1088 case 16: // Frost
1089 refspell = (m_spellInfo->School == 4 ? m_spellInfo : NULL);
1090 break;
1091 case 32: // Shadow
1092 refspell = (m_spellInfo->School == 5 ? m_spellInfo : NULL);
1093 break;
1094 case 64: // Arcane
1095 refspell = (m_spellInfo->School == 6 ? m_spellInfo : NULL);
1096 break;
1099 if(!refspell || m_caster == refunit) return;
1101 Spell *spell = new Spell(refunit, refspell, true, 0);
1103 SpellCastTargets targets;
1104 targets.setUnitTarget( m_caster );
1105 spell->prepare(&targets);