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"
25 #include "UpdateMask.h"
27 #include "ObjectMgr.h"
31 #include "DynamicObject.h"
32 #include "SpellAuras.h"
34 #include "UpdateData.h"
35 #include "MapManager.h"
36 #include "ObjectAccessor.h"
37 #include "RedZoneDistrict.h"
39 #include "Policies/SingletonImp.h"
40 #include "SharedDefines.h"
43 #define SPELL_CHANNEL_UPDATE_INTERVAL 1000
45 extern pEffect SpellEffects
[TOTAL_SPELL_EFFECTS
];
47 SpellCastTargets::SpellCastTargets()
52 m_srcX
= m_srcY
= m_srcZ
= m_destX
= m_destY
= m_destZ
= 0;
56 SpellCastTargets::~SpellCastTargets()
59 void SpellCastTargets::read ( WorldPacket
* data
,Unit
*caster
)
62 *data
>> m_targetMask
;
64 if(m_targetMask
& TARGET_FLAG_SELF
)
65 m_unitTarget
= caster
;
67 if(m_targetMask
& TARGET_FLAG_UNIT
)
68 m_unitTarget
= ObjectAccessor::Instance().GetUnit(*caster
, readGUID(data
));
70 if(m_targetMask
& TARGET_FLAG_OBJECT
)
71 m_GOTarget
= ObjectAccessor::Instance().GetGameObject(*caster
, readGUID(data
));
73 if(m_targetMask
& TARGET_FLAG_ITEM
)
74 m_itemTarget
= ((Player
*)caster
)->GetItemByGUID(readGUID(data
));
76 if(m_targetMask
& TARGET_FLAG_SOURCE_LOCATION
)
77 *data
>> m_srcX
>> m_srcY
>> m_srcZ
;
79 if(m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
80 *data
>> m_destX
>> m_destY
>> m_destZ
;
82 if(m_targetMask
& TARGET_FLAG_STRING
)
87 void SpellCastTargets::write ( WorldPacket
* data
)
90 *data
<< m_targetMask
;
92 if(m_targetMask
& TARGET_FLAG_SELF
)
93 *data
<< (m_unitTarget
? m_unitTarget
->GetGUID(): (uint64
)0);
95 if(m_targetMask
& TARGET_FLAG_UNIT
)
96 *data
<< (m_unitTarget
? m_unitTarget
->GetGUID(): (uint64
)0);
98 if(m_targetMask
& TARGET_FLAG_OBJECT
)
99 *data
<< (m_GOTarget
? m_GOTarget
->GetGUID(): (uint64
)0);
101 if(m_targetMask
& TARGET_FLAG_ITEM
)
102 *data
<< (m_itemTarget
? m_itemTarget
->GetGUID(): (uint64
)0);
104 if(m_targetMask
& TARGET_FLAG_SOURCE_LOCATION
)
105 *data
<< m_srcX
<< m_srcY
<< m_srcZ
;
107 if(m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
108 *data
<< m_destX
<< m_destY
<< m_destZ
;
110 if(m_targetMask
& TARGET_FLAG_STRING
)
111 *data
<< m_strTarget
;
115 Spell::Spell( Unit
* Caster
, SpellEntry
*info
, bool triggered
, Aura
* Aur
)
117 ASSERT( Caster
!= NULL
&& info
!= NULL
);
119 SpellEntry
*spellInfo
;
121 std::list
<Playerspell
*>::iterator itr
;
123 std::list
<Playerspell
*> player_spells
;
128 m_spellState
= SPELL_STATE_NULL
;
130 m_castPositionX
= m_castPositionY
= m_castPositionZ
;
131 m_TriggerSpell
= NULL
;
133 m_Istriggeredpell
= triggered
;
137 m_triggeredByAura
= Aur
;
139 casttime
= GetCastTime(sCastTime
.LookupEntry(m_spellInfo
->CastingTimeIndex
));
141 if( Caster
->GetTypeId() == TYPEID_PLAYER
&& m_spellInfo
)
143 p_caster
= (Player
*)m_caster
;
144 player_spells
= p_caster
->getSpellList();
145 for (itr
= player_spells
.begin(); itr
!= player_spells
.end(); ++itr
)
147 if ((*itr
)->spellId
!= m_spellInfo
->Id
)
149 spellInfo
= sSpellStore
.LookupEntry((*itr
)->spellId
);
150 if(spellInfo
&& spellInfo
->SpellIconID
== m_spellInfo
->SpellIconID
&& spellInfo
->EffectMiscValue
[0] ==10)
152 casttime
=casttime
+(spellInfo
->EffectBasePoints
[0]+1);
158 m_timer
= casttime
<0?0:casttime
;
162 void Spell::FillTargetMap()
165 std::list
<Unit
*> tmpUnitMap
;
166 std::list
<Item
*> tmpItemMap
;
167 std::list
<GameObject
*> tmpGOMap
;
169 for(uint32 i
=0;i
<3;i
++)
172 SetTargetMap(i
,m_spellInfo
->EffectImplicitTargetA
[i
],tmpUnitMap
,tmpItemMap
,tmpGOMap
);
173 SetTargetMap(i
,m_spellInfo
->EffectImplicitTargetB
[i
],tmpUnitMap
,tmpItemMap
,tmpGOMap
);
175 if(!m_spellInfo
->EffectImplicitTargetA
[i
] || m_spellInfo
->EffectImplicitTargetB
[i
] )
177 // add where custom effects that need default target.
179 if(m_spellInfo
->Effect
[i
] == 27) tmpUnitMap
.push_back(m_caster
);
181 else if(m_spellInfo
->Effect
[i
] == 36) tmpUnitMap
.push_back(m_targets
.getUnitTarget());
183 else if(m_spellInfo
->Effect
[i
] == 44) tmpUnitMap
.push_back(m_targets
.getUnitTarget());
185 else if(m_spellInfo
->Effect
[i
] == 118) tmpUnitMap
.push_back(m_caster
);
188 m_targetUnits
[i
] = tmpUnitMap
;
189 m_targetItems
[i
] = tmpItemMap
;
190 m_targetGOs
[i
] = tmpGOMap
;
198 void Spell::SetTargetMap(uint32 i
,uint32 cur
,std::list
<Unit
*> &TagUnitMap
,std::list
<Item
*> &TagItemMap
,std::list
<GameObject
*> &TagGOMap
)
200 float radius
= GetRadius(sSpellRadius
.LookupEntry(m_spellInfo
->EffectRadiusIndex
[i
]));
204 case TARGET_DY_OBJ
: //add by vendy
206 TagUnitMap
.push_back(m_caster
);
210 Unit
* tmpUnit
= ObjectAccessor::Instance().GetUnit(*m_caster
,m_caster
->GetUInt32Value(UNIT_FIELD_PETNUMBER
));
211 TagUnitMap
.push_back(tmpUnit
);
215 TagUnitMap
.push_back(m_targets
.getUnitTarget());
220 case TARGET_AE_E_INSTANT
:
222 CellPair
p(MaNGOS::ComputeCellPair(m_caster
->GetPositionX(), m_caster
->GetPositionY()));
223 Cell cell
= RedZone::GetZone(p
);
224 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
227 MaNGOS::SpellNotifierCreatureAndPlayer
notifier(*this, TagUnitMap
, i
,PUSH_DEST_CENTER
);
228 TypeContainerVisitor
<MaNGOS::SpellNotifierCreatureAndPlayer
, TypeMapContainer
<AllObjectTypes
> > object_notifier(notifier
);
229 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
230 cell_lock
->Visit(cell_lock
, object_notifier
, *MapManager::Instance().GetMap(m_caster
->GetMapId()));
234 Group
* pGroup
= objmgr
.GetGroupByLeader(((Player
*)m_caster
)->GetGroupLeader());
236 for(uint32 p
=0;p
<pGroup
->GetMembersCount();p
++)
238 Unit
* Target
= ObjectAccessor::Instance().FindPlayer(pGroup
->GetMemberGUID(p
));
239 if(!Target
|| Target
->GetGUID() == m_caster
->GetGUID())
241 if(m_caster
->GetDistanceSq(Target
) < radius
* radius
)
242 TagUnitMap
.push_back(Target
);
245 TagUnitMap
.push_back(m_caster
);
249 TagUnitMap
.push_back(m_targets
.getUnitTarget());
253 CellPair
p(MaNGOS::ComputeCellPair(m_caster
->GetPositionX(), m_caster
->GetPositionY()));
254 Cell cell
= RedZone::GetZone(p
);
255 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
258 MaNGOS::SpellNotifierCreatureAndPlayer
notifier(*this, TagUnitMap
, i
,PUSH_SELF_CENTER
);
259 TypeContainerVisitor
<MaNGOS::SpellNotifierCreatureAndPlayer
, TypeMapContainer
<AllObjectTypes
> > object_notifier(notifier
);
260 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
261 cell_lock
->Visit(cell_lock
, object_notifier
, *MapManager::Instance().GetMap(m_caster
->GetMapId()));
266 TagGOMap
.push_back(m_targets
.m_GOTarget
);
270 CellPair
p(MaNGOS::ComputeCellPair(m_caster
->GetPositionX(), m_caster
->GetPositionY()));
271 Cell cell
= RedZone::GetZone(p
);
272 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
274 MaNGOS::SpellNotifierCreatureAndPlayer
notifier(*this, TagUnitMap
, i
,PUSH_IN_FRONT
);
276 TypeContainerVisitor
<MaNGOS::SpellNotifierCreatureAndPlayer
, TypeMapContainer
<AllObjectTypes
> > object_notifier(notifier
);
277 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
279 cell_lock
->Visit(cell_lock
, object_notifier
, *MapManager::Instance().GetMap(m_caster
->GetMapId()));
281 case TARGET_DUELVSPLAYER
:
283 TagUnitMap
.push_back(m_targets
.getUnitTarget());
287 if(m_targets
.getUnitTarget())
288 TagUnitMap
.push_back(m_targets
.getUnitTarget());
289 if(m_targets
.m_itemTarget
)
290 TagItemMap
.push_back(m_targets
.m_itemTarget
);
292 case TARGET_AE_E_CHANNEL
:
294 CellPair
p(MaNGOS::ComputeCellPair(m_caster
->GetPositionX(), m_caster
->GetPositionY()));
295 Cell cell
= RedZone::GetZone(p
);
296 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
299 MaNGOS::SpellNotifierCreatureAndPlayer
notifier(*this, TagUnitMap
, i
,PUSH_DEST_CENTER
);
300 TypeContainerVisitor
<MaNGOS::SpellNotifierCreatureAndPlayer
, TypeMapContainer
<AllObjectTypes
> > object_notifier(notifier
);
301 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
302 cell_lock
->Visit(cell_lock
, object_notifier
, *MapManager::Instance().GetMap(m_caster
->GetMapId()));
306 if(m_spellInfo
->Effect
[i
] != 83) TagUnitMap
.push_back(m_caster
);
310 TagUnitMap
.push_back(m_targets
.getUnitTarget());
312 case TARGET_SELF_FISHING
:
314 TagUnitMap
.push_back(m_caster
);
318 bool onlyParty
= false;
320 if(!m_targets
.getUnitTarget())
323 Group
* pGroup
= objmgr
.GetGroupByLeader(((Player
*)m_caster
)->GetGroupLeader());
324 for(uint32 p
=0;p
<pGroup
->GetMembersCount();p
++)
326 if(m_targets
.getUnitTarget()->GetGUID() == pGroup
->GetMemberGUID(p
))
332 for(uint32 p
=0;p
<pGroup
->GetMembersCount();p
++)
334 Unit
* Target
= ObjectAccessor::Instance().FindPlayer(pGroup
->GetMemberGUID(p
));
336 if(!Target
|| Target
->GetGUID() == m_caster
->GetGUID())
338 if(m_caster
->GetDistanceSq(Target
) < radius
* radius
&& Target
->GetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
) == m_caster
->GetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
))
339 TagUnitMap
.push_back(Target
);
342 case TARGET_AE_SELECTED
:
344 CellPair
p(MaNGOS::ComputeCellPair(m_caster
->GetPositionX(), m_caster
->GetPositionY()));
345 Cell cell
= RedZone::GetZone(p
);
346 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
348 MaNGOS::SpellNotifierPlayer
notifier(*this, TagUnitMap
, i
);
349 TypeContainerVisitor
<MaNGOS::SpellNotifierPlayer
, ContainerMapList
<Player
> > player_notifier(notifier
);
350 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
351 cell_lock
->Visit(cell_lock
, player_notifier
, *MapManager::Instance().GetMap(m_caster
->GetMapId()));
359 void Spell::prepare(SpellCastTargets
* targets
)
365 m_targets
= *targets
;
369 m_spellState
= SPELL_STATE_PREPARING
;
371 m_castPositionX
= m_caster
->GetPositionX();
372 m_castPositionY
= m_caster
->GetPositionY();
373 m_castPositionZ
= m_caster
->GetPositionZ();
378 if(m_triggeredByAura
)
380 SendChannelUpdate(0);
381 m_triggeredByAura
->SetDuration(0);
386 if(m_Istriggeredpell
)
389 m_caster
->castSpell( this );
396 if(m_spellState
== SPELL_STATE_PREPARING
)
399 SendCastResult(0x20);
401 else if(m_spellState
== SPELL_STATE_CASTING
)
403 m_caster
->RemoveAura(m_spellInfo
->Id
);
404 SendChannelUpdate(0);
408 m_spellState
= SPELL_STATE_FINISHED
;
415 uint8 castResult
= 0;
416 castResult
= CanCast();
422 SendCastResult(castResult
);
425 if(m_spellInfo
->ChannelInterruptFlags
!= 0)
427 m_spellState
= SPELL_STATE_CASTING
;
428 SendChannelStart(GetDuration(sSpellDuration
.LookupEntry(m_spellInfo
->DurationIndex
)));
431 std::list
<Unit
*>::iterator iunit
;
432 std::list
<Item
*>::iterator iitem
;
433 std::list
<GameObject
*>::iterator igo
;
435 bool needspelllog
= false;
437 for(uint32 j
= 0;j
<3;j
++)
439 if(m_spellInfo
->Effect
[j
] != 2) // Dont do spell log, if is school damage spell
442 needspelllog
= false;
444 for(iunit
= m_targetUnits
[j
].begin();iunit
!= m_targetUnits
[j
].end();iunit
++)
445 HandleEffects((*iunit
),NULL
,NULL
,j
);
446 for(iitem
= m_targetItems
[j
].begin();iitem
!= m_targetItems
[j
].end();iitem
++)
447 HandleEffects(NULL
,(*iitem
),NULL
,j
);
448 for(igo
= m_targetGOs
[j
].begin();igo
!= m_targetGOs
[j
].end();igo
++)
449 HandleEffects(NULL
,NULL
,(*igo
),j
);
452 if(needspelllog
) SendLogExecute();
454 for(iunit
= UniqueTargets
.begin();iunit
!= UniqueTargets
.end();iunit
++)
456 if((*iunit
)->m_ReflectSpellSchool
) reflect(*iunit
);
457 HandleAddAura((*iunit
));
461 if(m_spellState
!= SPELL_STATE_CASTING
)
472 void Spell::update(uint32 difftime
)
475 if( (m_castPositionX
!= m_caster
->GetPositionX() ||
476 m_castPositionY
!= m_caster
->GetPositionY() ||
477 m_castPositionZ
!= m_caster
->GetPositionZ() ) &&
481 SendCastResult(0x20);
482 if(m_spellState
== SPELL_STATE_CASTING
)
484 m_caster
->RemoveAura(m_spellInfo
->Id
);
485 SendChannelUpdate(0);
488 m_spellState
= SPELL_STATE_FINISHED
;
492 case SPELL_STATE_PREPARING
:
496 if(difftime
>= m_timer
)
505 case SPELL_STATE_CASTING
:
509 if(difftime
>= m_timer
)
513 m_intervalTimer
+= difftime
;
519 SendChannelUpdate(0);
533 if(!m_caster
) return;
535 m_spellState
= SPELL_STATE_FINISHED
;
536 m_caster
->m_meleeSpell
= false;
537 m_caster
->m_canMove
= true;
539 std::list
<DynamicObject
*>::iterator i
;
540 std::list
<GameObject
*>::iterator k
;
544 for(i
= m_dynObjToDel
.begin() ; i
!= m_dynObjToDel
.end() ; i
++)
546 data
.Initialize(SMSG_GAMEOBJECT_DESPAWN_ANIM
);
547 data
<< (*i
)->GetGUID();
548 m_caster
->SendMessageToSet(&data
, true);
550 data
.Initialize(SMSG_DESTROY_OBJECT
);
551 data
<< (*i
)->GetGUID();
552 m_caster
->SendMessageToSet(&data
, true);
553 MapManager::Instance().GetMap((*i
)->GetMapId())->Remove((*i
), true);
556 for(k
= m_ObjToDel
.begin() ; k
!= m_ObjToDel
.end() ; k
++)
558 data
.Initialize(SMSG_GAMEOBJECT_DESPAWN_ANIM
);
559 data
<< (*k
)->GetGUID();
560 m_caster
->SendMessageToSet(&data
, true);
562 data
.Initialize(SMSG_DESTROY_OBJECT
);
563 data
<< (*k
)->GetGUID();
564 m_caster
->SendMessageToSet(&data
, true);
565 MapManager::Instance().GetMap((*k
)->GetMapId())->Remove((*k
), true);
568 m_dynObjToDel
.clear();
571 ((Player
*)m_caster
)->setRegenTimer(5000);
574 void Spell::SendCastResult(uint8 result
)
576 if (m_caster
->GetTypeId() != TYPEID_PLAYER
)
581 data
.Initialize(SMSG_CAST_RESULT
);
582 data
<< m_spellInfo
->Id
;
587 ((Player
*)m_caster
)->GetSession()->SendPacket(&data
);
590 void Spell::SendSpellStart()
598 data
.Initialize(SMSG_SPELL_START
);
599 data
<< uint8(0xFF) << m_caster
->GetGUID() << uint8(0xFF) << m_caster
->GetGUID();
600 data
<< m_spellInfo
->Id
;
602 data
<< uint32(m_timer
);
604 m_targets
.write( &data
);
605 ((Player
*)m_caster
)->SendMessageToSet(&data
, true);
609 void Spell::SendSpellGo()
615 flags
= m_targets
.m_targetMask
;
619 data
.Initialize(SMSG_SPELL_GO
);
620 data
<< uint8(0xFF)<< m_caster
->GetGUID() << uint8(0xFF) << m_caster
->GetGUID();
621 data
<< m_spellInfo
->Id
;
623 data
<< uint16(0x0500);
624 writeSpellGoTargets(&data
);
628 m_targets
.write( &data
);
629 m_caster
->SendMessageToSet(&data
, true);
633 void Spell::writeSpellGoTargets( WorldPacket
* data
)
637 std::list
<Unit
*>::iterator i
,j
;
638 std::list
<GameObject
*>::iterator m
,n
;
642 for ( i
= m_targetUnits
[k
].begin(); i
!= m_targetUnits
[k
].end(); i
++ )
644 for(j
= UniqueTargets
.begin(); j
!= UniqueTargets
.end(); j
++ )
653 UniqueTargets
.push_back(*i
);
656 for ( m
= m_targetGOs
[k
].begin(); m
!= m_targetGOs
[k
].end(); m
++ )
658 for(n
= UniqueGOsTargets
.begin(); n
!= UniqueGOsTargets
.end(); n
++ )
667 UniqueGOsTargets
.push_back(*m
);
672 m_targetCount
= UniqueTargets
.size() + UniqueGOsTargets
.size();
673 *data
<< m_targetCount
;
675 for ( std::list
<Unit
*>::iterator ui
= UniqueTargets
.begin(); ui
!= UniqueTargets
.end(); ui
++ )
676 *data
<< (*ui
)->GetGUID();
678 for ( std::list
<GameObject
*>::iterator uj
= UniqueGOsTargets
.begin(); uj
!= UniqueGOsTargets
.end(); uj
++ )
679 *data
<< (*uj
)->GetGUID();
683 void Spell::SendLogExecute()
686 data
.Initialize(SMSG_SPELLLOGEXECUTE
);
688 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
689 data
<< uint8(0xFF) << m_caster
->GetGUID();
691 data
<< m_caster
->GetGUID();
693 data
<< m_spellInfo
->Id
;
695 data
<< m_spellInfo
->SpellVisual
;
698 if(m_targets
.getUnitTarget())
699 data
<< m_targets
.getUnitTarget()->GetGUID();
700 else if(m_targets
.m_itemTarget
)
701 data
<< m_targets
.m_itemTarget
->GetGUID();
702 else if(m_targets
.m_GOTarget
)
703 data
<< m_targets
.m_GOTarget
->GetGUID();
705 m_caster
->SendMessageToSet(&data
,true);
708 void Spell::SendInterrupted(uint8 result
)
712 data
.Initialize(SMSG_SPELL_FAILURE
);
713 data
<< uint8(0xFF) << m_caster
->GetGUID();
714 data
<< m_spellInfo
->Id
;
716 m_caster
->SendMessageToSet(&data
, true);
719 void Spell::SendChannelUpdate(uint32 time
)
721 if (m_caster
->GetTypeId() != TYPEID_PLAYER
)
726 data
.Initialize( MSG_CHANNEL_UPDATE
);
729 ((Player
*)m_caster
)->GetSession()->SendPacket( &data
);
733 m_caster
->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT
,0);
734 m_caster
->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT
+1,0);
735 m_caster
->SetUInt32Value(UNIT_CHANNEL_SPELL
,0);
739 void Spell::SendChannelStart(uint32 duration
)
741 Unit
* target
= ObjectAccessor::Instance().GetCreature(*m_caster
, ((Player
*)m_caster
)->GetSelection());
743 if (m_caster
->GetTypeId() == TYPEID_PLAYER
)
747 data
.Initialize( MSG_CHANNEL_START
);
748 data
<< m_spellInfo
->Id
;
751 ((Player
*)m_caster
)->GetSession()->SendPacket( &data
);
757 m_caster
->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT
,target
->GetGUIDLow());
758 m_caster
->SetUInt32Value(UNIT_FIELD_CHANNEL_OBJECT
+1,target
->GetGUIDHigh());
760 m_caster
->SetUInt32Value(UNIT_CHANNEL_SPELL
,m_spellInfo
->Id
);
763 void Spell::SendResurrectRequest(Player
* target
)
766 data
.Initialize(SMSG_RESURRECT_REQUEST
);
767 data
<< uint8(0xFF) << m_caster
->GetGUID();
768 data
<< uint32(0) << uint8(0);
770 target
->GetSession()->SendPacket(&data
);
773 void Spell::TakePower()
778 uint8 powerType
= (uint8
)(m_caster
->GetUInt32Value(UNIT_FIELD_BYTES_0
) >> 24);
780 powerField
= UNIT_FIELD_POWER1
;
781 else if(powerType
== 1)
782 powerField
= UNIT_FIELD_POWER2
;
783 else if(powerType
== 3)
784 powerField
= UNIT_FIELD_POWER4
;
786 currentPower
= m_caster
->GetUInt32Value(powerField
);
788 if(currentPower
< m_spellInfo
->manaCost
)
789 m_caster
->SetUInt32Value(powerField
, 0);
791 m_caster
->SetUInt32Value(powerField
, currentPower
- m_spellInfo
->manaCost
);
794 void Spell::HandleEffects(Unit
*pUnitTarget
,Item
*pItemTarget
,GameObject
*pGOTarget
,uint32 i
)
797 unitTarget
= pUnitTarget
;
798 itemTarget
= pItemTarget
;
799 gameObjTarget
= pGOTarget
;
801 damage
= CalculateDamage((uint8
)i
);
802 uint8 eff
= m_spellInfo
->Effect
[i
];
804 sLog
.outDebug( "WORLD: Spell FX id is %u", eff
);
806 if(eff
<TOTAL_SPELL_EFFECTS
)
807 (*this.*SpellEffects
[eff
])(i
);
811 EffectEnchantItemTmp(i
);
814 sLog
.outError("SPELL: unknown effect %d spell id %i\n",
815 eff
, m_spellInfo
->Id
);
820 void Spell::HandleAddAura(Unit
* Target
)
824 if(Target
->tmpAura
!= 0)
826 Target
->AddAura(Target
->tmpAura
);
831 void Spell::TriggerSpell()
833 if(!m_TriggerSpell
) return;
835 Spell
spell(m_caster
, m_TriggerSpell
,false, 0);
836 SpellCastTargets targets
;
837 targets
.setUnitTarget( m_targets
.getUnitTarget());
838 spell
.prepare(&targets
);
842 uint8
Spell::CanCast()
844 uint8 castResult
= 0;
848 castResult
= CheckItems();
851 SendCastResult(castResult
);
857 target
= m_targets
.getUnitTarget();
858 float range
= GetMaxRange(sSpellRange
.LookupEntry(m_spellInfo
->rangeIndex
));
862 if(!m_caster
->isInFront( target
, range
))
864 if(m_caster
->GetDistanceSq(target
) > range
* range
)
868 if(m_targets
.m_destX
!= 0 && m_targets
.m_destY
!= 0 && m_targets
.m_destZ
!= 0 )
870 if(m_caster
->GetDistanceSq( m_targets
.m_destX
,m_targets
.m_destY
,m_targets
.m_destZ
) > range
* range
)
874 if(m_caster
->m_silenced
)
876 if( castResult
!= 0 )
878 SendCastResult(castResult
);
882 castResult
= CheckItems();
885 SendCastResult(castResult
);
890 uint8
Spell::CheckItems()
892 //update by Ant009,need more test.
893 if (m_caster
->GetTypeId() != TYPEID_PLAYER
)
896 Player
* p_caster
= (Player
*)m_caster
;
899 uint32 tmpReagentCount
[8];
903 for(uint32 i
=0;i
<8;i
++)
904 tmpReagentCount
[i
] = m_spellInfo
->ReagentCount
[i
];
906 for(uint32 i
=0;i
<8;i
++)
908 if(m_spellInfo
->Reagent
[i
] == 0)
911 for(uint32 j
=0;j
<INVENTORY_SLOT_ITEM_END
;j
++)
913 itm
= p_caster
->GetItemBySlot(j
);
916 if(itm
->GetProto()->ItemId
== m_spellInfo
->Reagent
[i
] && tmpReagentCount
[i
] > 0)
917 if(itm
->GetUInt32Value(ITEM_FIELD_STACK_COUNT
) > tmpReagentCount
[i
])
918 tmpReagentCount
[i
] = 0;
920 tmpReagentCount
[i
] -= itm
->GetUInt32Value(ITEM_FIELD_STACK_COUNT
);
922 for(bagIndex
=CLIENT_SLOT_01
;bagIndex
<=CLIENT_SLOT_04
;bagIndex
++)
924 pBag
= p_caster
->GetBagBySlot(bagIndex
);
926 for(uint8 pSlot
=0; pSlot
< pBag
->GetProto()->ContainerSlots
; pSlot
++)
928 itm
= p_caster
->GetItemBySlot(bagIndex
,pSlot
);
931 if(itm
->GetProto()->ItemId
== m_spellInfo
->Reagent
[i
] && tmpReagentCount
[i
] > 0)
932 if(itm
->GetUInt32Value(ITEM_FIELD_STACK_COUNT
) > tmpReagentCount
[i
])
933 tmpReagentCount
[i
] = 0;
935 tmpReagentCount
[i
] -= itm
->GetUInt32Value(ITEM_FIELD_STACK_COUNT
);
939 if(tmpReagentCount
[i
] != 0)
944 for(uint32 i
=0;i
<2;i
++)
946 if(m_spellInfo
->Totem
[i
] != 0)
948 if(p_caster
->GetSlotByItemID(m_spellInfo
->Totem
[i
], bagIndex
, curSlot
,true,false))
950 itm
= p_caster
->GetItemBySlot(bagIndex
,curSlot
);
952 if(itm
->GetProto()->ItemId
== m_spellInfo
->Totem
[i
])
968 void Spell::RemoveItems()
970 if (m_caster
->GetTypeId() != TYPEID_PLAYER
)
973 Player
* p_caster
= (Player
*)m_caster
;
976 for(uint32 i
=0;i
<8;i
++)
978 if(m_spellInfo
->Reagent
[i
] == 0)
980 for(uint8 j
=0;j
<INVENTORY_SLOT_ITEM_END
;j
++)
982 itm
= p_caster
->GetItemBySlot(j
);
985 if(itm
->GetProto()->ItemId
== m_spellInfo
->Reagent
[i
])
986 //p_caster->RemoveItemFromSlot(j);
987 p_caster
->RemoveItemFromSlot(0,j
,true);
993 uint32
Spell::CalculateDamage(uint8 i
)
996 float basePointsPerLevel
= m_spellInfo
->EffectRealPointsPerLevel
[i
];
997 float randomPointsPerLevel
= m_spellInfo
->EffectDicePerLevel
[i
];
998 uint32 basePoints
= uint32(m_spellInfo
->EffectBasePoints
[i
]+m_caster
->getLevel()*basePointsPerLevel
);
999 uint32 randomPoints
= uint32(m_spellInfo
->EffectDieSides
[i
]+m_caster
->getLevel()*randomPointsPerLevel
);
1000 uint32 comboDamage
= uint32(m_spellInfo
->EffectPointsPerComboPoint
[i
]);
1001 uint8 comboPoints
=0;
1002 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
1003 comboPoints
= ((m_caster
->GetUInt32Value(PLAYER_FIELD_BYTES
) & 0xFF00) >> 8);
1005 if(randomPoints
<= 1)
1006 value
= basePoints
+1;
1008 value
= basePoints
+rand()%randomPoints
;
1012 for(uint32 j
=0;j
<comboPoints
;j
++)
1013 value
+= comboDamage
;
1014 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
1015 m_caster
->SetUInt32Value(PLAYER_FIELD_BYTES
,((m_caster
->GetUInt32Value(PLAYER_FIELD_BYTES
) & ~(0xFF << 8)) | (0x00 << 8)));
1021 void Spell::HandleTeleport(uint32 id
, Unit
* Target
)
1026 TeleportCoords
* TC
= new TeleportCoords();
1028 if(m_spellInfo
->Id
== 8690 )
1031 QueryResult
*result4
= sDatabase
.PQuery("SELECT `map`,`zone`,`position_x`,`position_y`,`position_z` FROM `characters_homebind` WHERE `guid` = '%d';", m_caster
->GetGUID());
1032 fields
= result4
->Fetch();
1033 TC
->mapId
= fields
[0].GetUInt32();
1034 TC
->x
= fields
[2].GetFloat();
1035 TC
->y
= fields
[3].GetFloat();
1036 TC
->z
= fields
[4].GetFloat();
1041 TC
= objmgr
.GetTeleportCoords(id
);
1044 sLog
.outString( "SPELL: unknown Teleport Coords ID %i\n", id
);
1049 ((Player
*)Target
)->smsg_NewWorld(TC
->mapId
,TC
->x
,TC
->y
,TC
->z
,0.0f
);
1053 void Spell::Delayed(int32 delaytime
)
1055 if(!m_caster
|| m_caster
->GetTypeId() != TYPEID_PLAYER
) return;
1057 m_timer
+= delaytime
;
1059 if(m_timer
> casttime
)
1064 data
.Initialize(SMSG_SPELL_DELAYED
);
1065 data
<< m_caster
->GetGUID();
1066 data
<< uint32(delaytime
);
1068 ((Player
*)m_caster
)->GetSession()->SendPacket(&data
);
1071 void Spell::reflect(Unit
*refunit
)
1073 SpellEntry
*refspell
= NULL
;
1075 // if the spell to reflect is a reflect spell, do nothing.
1076 for(int i
=0; i
<3; i
++)
1077 if(m_spellInfo
->Effect
[i
] == 6 && m_spellInfo
->EffectApplyAuraName
[i
] == 74)
1080 switch(refunit
->m_ReflectSpellSchool
)
1083 refspell
= m_spellInfo
;
1086 refspell
= (m_spellInfo
->School
== 2 ? m_spellInfo
: NULL
);
1089 refspell
= (m_spellInfo
->School
== 4 ? m_spellInfo
: NULL
);
1092 refspell
= (m_spellInfo
->School
== 5 ? m_spellInfo
: NULL
);
1095 refspell
= (m_spellInfo
->School
== 6 ? m_spellInfo
: NULL
);
1099 if(!refspell
|| m_caster
== refunit
) return;
1101 Spell
*spell
= new Spell(refunit
, refspell
, true, 0);
1103 SpellCastTargets targets
;
1104 targets
.setUnitTarget( m_caster
);
1105 spell
->prepare(&targets
);