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