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