2010-10-07 15:35:36 +02:00
/*
2011-01-01 15:01:13 +01:00
* Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
2010-02-20 23:59:05 +01:00
*/
#include "Common.h"
2010-06-08 17:01:03 -06:00
#include "DatabaseEnv.h"
2010-02-20 23:59:05 +01:00
#include "WorldPacket.h"
#include "WorldSession.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "Opcodes.h"
#include "Log.h"
#include "UpdateMask.h"
#include "World.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Player.h"
#include "Pet.h"
#include "Unit.h"
#include "Totem.h"
#include "Spell.h"
#include "DynamicObject.h"
#include "Group.h"
#include "UpdateData.h"
#include "MapManager.h"
#include "ObjectAccessor.h"
#include "CellImpl.h"
#include "SharedDefines.h"
#include "LootMgr.h"
#include "VMapFactory.h"
2010-08-08 04:37:24 +02:00
#include "Battleground.h"
2010-02-20 23:59:05 +01:00
#include "Util.h"
#include "TemporarySummon.h"
#include "Vehicle.h"
#include "SpellAuraEffects.h"
#include "ScriptMgr.h"
2010-06-04 23:24:48 +02:00
#include "ConditionMgr.h"
2010-07-21 12:14:23 +02:00
#include "DisableMgr.h"
2010-07-24 22:41:42 +02:00
#include "SpellScript.h"
2011-02-03 22:20:40 +01:00
#include "InstanceScript.h"
2011-07-26 23:09:28 +02:00
#include "SpellInfo.h"
2010-02-20 23:59:05 +01:00
extern pEffect SpellEffects [ TOTAL_SPELL_EFFECTS ];
SpellCastTargets :: SpellCastTargets () : m_elevation ( 0 ), m_speed ( 0 )
{
2011-08-26 12:05:47 +02:00
m_objectTarget = NULL ;
2010-02-20 23:59:05 +01:00
m_itemTarget = NULL ;
2011-08-26 12:05:47 +02:00
m_objectTargetGUID = 0 ;
2010-02-20 23:59:05 +01:00
m_itemTargetGUID = 0 ;
m_itemTargetEntry = 0 ;
2010-08-08 20:32:14 +02:00
m_srcTransGUID = 0 ;
m_srcTransOffset . Relocate ( 0 , 0 , 0 , 0 );
m_srcPos . Relocate ( 0 , 0 , 0 , 0 );
m_dstTransGUID = 0 ;
m_dstTransOffset . Relocate ( 0 , 0 , 0 , 0 );
m_dstPos . Relocate ( 0 , 0 , 0 , 0 );
2010-02-20 23:59:05 +01:00
m_strTarget = "" ;
m_targetMask = 0 ;
}
SpellCastTargets ::~ SpellCastTargets ()
{
}
2011-06-23 13:28:52 +02:00
void SpellCastTargets :: Read ( ByteBuffer & data , Unit * caster )
{
data >> m_targetMask ;
2011-08-24 08:07:59 +02:00
if ( m_targetMask == TARGET_FLAG_NONE )
2011-06-23 13:28:52 +02:00
return ;
2011-08-26 12:05:47 +02:00
if ( m_targetMask & ( TARGET_FLAG_UNIT | TARGET_FLAG_UNIT_MINIPET | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_CORPSE_ALLY ))
data . readPackGUID ( m_objectTargetGUID );
2011-06-23 13:28:52 +02:00
if ( m_targetMask & ( TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM ))
data . readPackGUID ( m_itemTargetGUID );
if ( m_targetMask & TARGET_FLAG_SOURCE_LOCATION )
{
data . readPackGUID ( m_srcTransGUID );
if ( m_srcTransGUID )
data >> m_srcTransOffset . PositionXYZStream ();
else
data >> m_srcPos . PositionXYZStream ();
}
else
{
m_srcTransGUID = caster -> GetTransGUID ();
if ( m_srcTransGUID )
m_srcTransOffset . Relocate ( caster -> GetTransOffsetX (), caster -> GetTransOffsetY (), caster -> GetTransOffsetZ (), caster -> GetTransOffsetO ());
else
m_srcPos . Relocate ( caster );
}
if ( m_targetMask & TARGET_FLAG_DEST_LOCATION )
{
data . readPackGUID ( m_dstTransGUID );
if ( m_dstTransGUID )
data >> m_dstTransOffset . PositionXYZStream ();
else
data >> m_dstPos . PositionXYZStream ();
}
else
{
m_dstTransGUID = caster -> GetTransGUID ();
if ( m_dstTransGUID )
m_dstTransOffset . Relocate ( caster -> GetTransOffsetX (), caster -> GetTransOffsetY (), caster -> GetTransOffsetZ (), caster -> GetTransOffsetO ());
else
m_dstPos . Relocate ( caster );
}
if ( m_targetMask & TARGET_FLAG_STRING )
data >> m_strTarget ;
Update ( caster );
}
void SpellCastTargets :: Write ( ByteBuffer & data )
{
data << uint32 ( m_targetMask );
2011-07-02 16:12:19 +02:00
if ( m_targetMask & ( TARGET_FLAG_UNIT | TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_MINIPET ))
2011-08-26 12:05:47 +02:00
data . appendPackGUID ( m_objectTargetGUID );
2011-06-23 13:28:52 +02:00
if ( m_targetMask & ( TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM ))
{
if ( m_itemTarget )
data . append ( m_itemTarget -> GetPackGUID ());
else
data << uint8 ( 0 );
}
if ( m_targetMask & TARGET_FLAG_SOURCE_LOCATION )
{
data . appendPackGUID ( m_srcTransGUID ); // relative position guid here - transport for example
if ( m_srcTransGUID )
data << m_srcTransOffset . PositionXYZStream ();
else
data << m_srcPos . PositionXYZStream ();
}
if ( m_targetMask & TARGET_FLAG_DEST_LOCATION )
{
data . appendPackGUID ( m_dstTransGUID ); // relative position guid here - transport for example
if ( m_dstTransGUID )
data << m_dstTransOffset . PositionXYZStream ();
else
data << m_dstPos . PositionXYZStream ();
}
if ( m_targetMask & TARGET_FLAG_STRING )
data << m_strTarget ;
}
2011-08-26 12:05:47 +02:00
uint64 SpellCastTargets :: GetUnitTargetGUID () const
{
switch ( GUID_HIPART ( m_objectTargetGUID ))
{
case HIGHGUID_PLAYER :
case HIGHGUID_VEHICLE :
case HIGHGUID_UNIT :
case HIGHGUID_PET :
return m_objectTargetGUID ;
default :
return 0LL ;
}
}
Unit * SpellCastTargets :: GetUnitTarget () const
{
if ( m_objectTarget )
return m_objectTarget -> ToUnit ();
return NULL ;
}
2011-06-23 13:28:52 +02:00
void SpellCastTargets :: SetUnitTarget ( Unit * target )
2010-02-20 23:59:05 +01:00
{
if ( ! target )
return ;
2011-08-26 12:05:47 +02:00
m_objectTarget = target ;
m_objectTargetGUID = target -> GetGUID ();
2010-08-02 20:05:22 +02:00
m_targetMask |= TARGET_FLAG_UNIT ;
2010-02-20 23:59:05 +01:00
}
2011-08-26 12:05:47 +02:00
uint64 SpellCastTargets :: GetGOTargetGUID () const
{
switch ( GUID_HIPART ( m_objectTargetGUID ))
{
case HIGHGUID_TRANSPORT :
case HIGHGUID_MO_TRANSPORT :
case HIGHGUID_GAMEOBJECT :
return m_objectTargetGUID ;
default :
return 0LL ;
}
}
GameObject * SpellCastTargets :: GetGOTarget () const
2011-08-24 08:07:59 +02:00
{
2011-08-26 12:05:47 +02:00
if ( m_objectTarget )
return m_objectTarget -> ToGameObject ();
return NULL ;
2011-08-24 08:07:59 +02:00
}
2011-08-26 12:05:47 +02:00
2011-08-24 08:07:59 +02:00
void SpellCastTargets :: SetGOTarget ( GameObject * target )
{
if ( ! target )
return ;
2011-08-26 12:05:47 +02:00
m_objectTarget = target ;
m_objectTargetGUID = target -> GetGUID ();
2011-08-24 08:07:59 +02:00
m_targetMask |= TARGET_FLAG_GAMEOBJECT ;
}
2011-08-26 12:05:47 +02:00
uint64 SpellCastTargets :: GetCorpseTargetGUID () const
{
switch ( GUID_HIPART ( m_objectTargetGUID ))
{
case HIGHGUID_CORPSE :
return m_objectTargetGUID ;
default :
return 0LL ;
}
}
Corpse * SpellCastTargets :: GetCorpseTarget () const
{
if ( m_objectTarget )
return m_objectTarget -> ToCorpse ();
return NULL ;
}
WorldObject * SpellCastTargets :: GetObjectTarget () const
{
return m_objectTarget ;
}
uint64 SpellCastTargets :: GetObjectTargetGUID () const
2011-08-24 08:07:59 +02:00
{
2011-08-26 12:05:47 +02:00
return m_objectTargetGUID ;
2011-08-24 08:07:59 +02:00
}
2011-08-26 12:05:47 +02:00
void SpellCastTargets :: RemoveObjectTarget ()
2011-08-24 08:07:59 +02:00
{
2011-08-26 12:05:47 +02:00
m_objectTarget = NULL ;
m_objectTargetGUID = 0LL ;
m_targetMask &= ~ ( TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK );
2011-08-24 08:07:59 +02:00
}
void SpellCastTargets :: SetItemTarget ( Item * item )
{
if ( ! item )
return ;
m_itemTarget = item ;
m_itemTargetGUID = item -> GetGUID ();
m_itemTargetEntry = item -> GetEntry ();
m_targetMask |= TARGET_FLAG_ITEM ;
}
void SpellCastTargets :: SetTradeItemTarget ( Player * caster )
{
m_itemTargetGUID = uint64 ( TRADE_SLOT_NONTRADED );
m_itemTargetEntry = 0 ;
m_targetMask |= TARGET_FLAG_TRADE_ITEM ;
Update ( caster );
}
void SpellCastTargets :: UpdateTradeSlotItem ()
{
if ( m_itemTarget && ( m_targetMask & TARGET_FLAG_TRADE_ITEM ))
{
m_itemTargetGUID = m_itemTarget -> GetGUID ();
m_itemTargetEntry = m_itemTarget -> GetEntry ();
}
}
2011-06-23 13:28:52 +02:00
Position const * SpellCastTargets :: GetSrc () const
{
return & m_srcPos ;
}
void SpellCastTargets :: SetSrc ( float x , float y , float z )
2010-02-20 23:59:05 +01:00
{
m_srcPos . Relocate ( x , y , z );
2010-08-08 20:32:14 +02:00
m_srcTransGUID = 0 ;
2010-08-02 20:05:22 +02:00
m_targetMask |= TARGET_FLAG_SOURCE_LOCATION ;
2010-02-20 23:59:05 +01:00
}
2011-06-23 13:28:52 +02:00
void SpellCastTargets :: SetSrc ( Position const & pos )
2010-02-20 23:59:05 +01:00
{
2010-08-08 20:32:14 +02:00
m_srcPos . Relocate ( pos );
m_srcTransGUID = 0 ;
m_targetMask |= TARGET_FLAG_SOURCE_LOCATION ;
}
2011-06-23 13:28:52 +02:00
void SpellCastTargets :: SetSrc ( WorldObject const & wObj )
2010-08-08 20:32:14 +02:00
{
uint64 guid = wObj . GetTransGUID ();
m_srcTransGUID = guid ;
m_srcTransOffset . Relocate ( wObj . GetTransOffsetX (), wObj . GetTransOffsetY (), wObj . GetTransOffsetZ (), wObj . GetTransOffsetO ());
m_srcPos . Relocate ( wObj );
m_targetMask |= TARGET_FLAG_SOURCE_LOCATION ;
}
2011-06-23 13:28:52 +02:00
void SpellCastTargets :: ModSrc ( Position const & pos )
2010-08-08 20:32:14 +02:00
{
ASSERT ( m_targetMask & TARGET_FLAG_SOURCE_LOCATION );
if ( m_srcTransGUID )
2010-02-20 23:59:05 +01:00
{
2010-08-08 20:32:14 +02:00
Position offset ;
m_srcPos . GetPositionOffsetTo ( pos , offset );
m_srcTransOffset . RelocateOffset ( offset );
2010-02-20 23:59:05 +01:00
}
2010-08-08 20:32:14 +02:00
m_srcPos . Relocate ( pos );
2010-02-20 23:59:05 +01:00
}
2011-08-24 08:07:59 +02:00
void SpellCastTargets :: RemoveSrc ()
{
m_targetMask &= ~ ( TARGET_FLAG_SOURCE_LOCATION );
}
2011-06-23 13:28:52 +02:00
WorldLocation const * SpellCastTargets :: GetDst () const
{
return & m_dstPos ;
}
void SpellCastTargets :: SetDst ( float x , float y , float z , float orientation , uint32 mapId )
2010-02-20 23:59:05 +01:00
{
m_dstPos . Relocate ( x , y , z , orientation );
2010-08-08 20:32:14 +02:00
m_dstTransGUID = 0 ;
2010-08-02 20:05:22 +02:00
m_targetMask |= TARGET_FLAG_DEST_LOCATION ;
2010-04-07 19:14:10 +02:00
if ( mapId != MAPID_INVALID )
2010-02-20 23:59:05 +01:00
m_dstPos . m_mapId = mapId ;
}
2011-06-23 13:28:52 +02:00
void SpellCastTargets :: SetDst ( Position const & pos )
2010-08-08 20:32:14 +02:00
{
m_dstPos . Relocate ( pos );
m_dstTransGUID = 0 ;
m_targetMask |= TARGET_FLAG_DEST_LOCATION ;
}
2011-06-23 13:28:52 +02:00
void SpellCastTargets :: SetDst ( WorldObject const & wObj )
2010-08-08 20:32:14 +02:00
{
uint64 guid = wObj . GetTransGUID ();
m_dstTransGUID = guid ;
m_dstTransOffset . Relocate ( wObj . GetTransOffsetX (), wObj . GetTransOffsetY (), wObj . GetTransOffsetZ (), wObj . GetTransOffsetO ());
m_dstPos . Relocate ( wObj );
m_targetMask |= TARGET_FLAG_DEST_LOCATION ;
}
2011-06-23 13:28:52 +02:00
void SpellCastTargets :: SetDst ( SpellCastTargets const & spellTargets )
2010-08-18 15:04:00 +02:00
{
2011-09-05 14:01:50 +02:00
m_dstTransGUID = spellTargets . m_dstTransGUID ;
m_dstTransOffset . Relocate ( spellTargets . m_dstTransOffset );
m_dstPos . Relocate ( spellTargets . m_dstPos );
m_targetMask |= TARGET_FLAG_DEST_LOCATION ;
2010-08-18 15:04:00 +02:00
}
2011-06-23 13:28:52 +02:00
void SpellCastTargets :: ModDst ( Position const & pos )
2010-02-20 23:59:05 +01:00
{
2010-08-08 20:32:14 +02:00
ASSERT ( m_targetMask & TARGET_FLAG_DEST_LOCATION );
if ( m_dstTransGUID )
2010-02-20 23:59:05 +01:00
{
2010-08-08 20:32:14 +02:00
Position offset ;
m_dstPos . GetPositionOffsetTo ( pos , offset );
m_dstTransOffset . RelocateOffset ( offset );
2010-02-20 23:59:05 +01:00
}
2010-08-08 20:32:14 +02:00
m_dstPos . Relocate ( pos );
2010-02-20 23:59:05 +01:00
}
2011-08-24 08:07:59 +02:00
void SpellCastTargets :: RemoveDst ()
2011-07-28 23:44:39 +02:00
{
2011-08-24 08:07:59 +02:00
m_targetMask &= ~ ( TARGET_FLAG_DEST_LOCATION );
2011-07-28 23:44:39 +02:00
}
2010-02-20 23:59:05 +01:00
void SpellCastTargets :: Update ( Unit * caster )
{
2011-08-26 12:05:47 +02:00
m_objectTarget = m_objectTargetGUID ? (( m_objectTargetGUID == caster -> GetGUID ()) ? caster : ObjectAccessor :: GetWorldObject ( * caster , m_objectTargetGUID )) : NULL ;
2010-02-20 23:59:05 +01:00
m_itemTarget = NULL ;
2010-03-09 21:11:54 +01:00
if ( caster -> GetTypeId () == TYPEID_PLAYER )
2010-02-20 23:59:05 +01:00
{
2011-06-12 01:47:45 +02:00
Player * player = caster -> ToPlayer ();
2010-04-07 19:14:10 +02:00
if ( m_targetMask & TARGET_FLAG_ITEM )
2010-06-25 13:15:51 +02:00
m_itemTarget = player -> GetItemByGuid ( m_itemTargetGUID );
2010-03-09 21:11:54 +01:00
else if ( m_targetMask & TARGET_FLAG_TRADE_ITEM )
2010-06-25 13:15:51 +02:00
if ( m_itemTargetGUID == TRADE_SLOT_NONTRADED ) // here it is not guid but slot. Also prevents hacking slots
if ( TradeData * pTrade = player -> GetTradeData ())
m_itemTarget = pTrade -> GetTraderData () -> GetItem ( TRADE_SLOT_NONTRADED );
2010-03-09 21:11:54 +01:00
if ( m_itemTarget )
2010-02-20 23:59:05 +01:00
m_itemTargetEntry = m_itemTarget -> GetEntry ();
}
2011-05-22 16:01:53 -07:00
2010-08-08 20:32:14 +02:00
// update positions by transport move
2010-08-09 02:31:42 +02:00
if ( HasSrc () && m_srcTransGUID )
2010-08-08 20:32:14 +02:00
{
2011-09-15 14:08:17 +02:00
if ( WorldObject * transport = ObjectAccessor :: GetWorldObject ( * caster , m_srcTransGUID ))
2010-08-08 20:32:14 +02:00
{
m_srcPos . Relocate ( transport );
m_srcPos . RelocateOffset ( m_srcTransOffset );
}
}
2011-05-22 16:01:53 -07:00
2010-08-09 02:31:42 +02:00
if ( HasDst () && m_dstTransGUID )
2010-08-08 20:32:14 +02:00
{
2011-09-15 14:08:17 +02:00
if ( WorldObject * transport = ObjectAccessor :: GetWorldObject ( * caster , m_dstTransGUID ))
2010-08-08 20:32:14 +02:00
{
m_dstPos . Relocate ( transport );
m_dstPos . RelocateOffset ( m_dstTransOffset );
}
}
2010-02-20 23:59:05 +01:00
}
2011-06-23 13:28:52 +02:00
void SpellCastTargets :: OutDebug () const
2010-02-20 23:59:05 +01:00
{
2010-08-08 20:32:14 +02:00
if ( ! m_targetMask )
2011-08-26 12:05:47 +02:00
sLog -> outString ( "No targets" );
sLog -> outString ( "target mask: %u" , m_targetMask );
if ( m_targetMask & ( TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK ))
sLog -> outString ( "Object target: " UI64FMTD , m_objectTargetGUID );
2010-08-08 20:32:14 +02:00
if ( m_targetMask & TARGET_FLAG_ITEM )
2011-08-26 12:05:47 +02:00
sLog -> outString ( "Item target: " UI64FMTD , m_itemTargetGUID );
2010-08-08 20:32:14 +02:00
if ( m_targetMask & TARGET_FLAG_TRADE_ITEM )
2011-08-26 12:05:47 +02:00
sLog -> outString ( "Trade item target: " UI64FMTD , m_itemTargetGUID );
2010-08-08 20:32:14 +02:00
if ( m_targetMask & TARGET_FLAG_SOURCE_LOCATION )
2011-08-26 12:05:47 +02:00
sLog -> outString ( "Source location: transport guid:" UI64FMTD " trans offset: %s position: %s" , m_srcTransGUID , m_srcTransOffset . ToString (). c_str (), m_srcPos . ToString (). c_str ());
2010-08-08 20:32:14 +02:00
if ( m_targetMask & TARGET_FLAG_DEST_LOCATION )
2011-08-26 12:05:47 +02:00
sLog -> outString ( "Destination location: transport guid:" UI64FMTD " trans offset: %s position: %s" , m_dstTransGUID , m_dstTransOffset . ToString (). c_str (), m_dstPos . ToString (). c_str ());
2010-08-08 20:32:14 +02:00
if ( m_targetMask & TARGET_FLAG_STRING )
2011-08-26 12:05:47 +02:00
sLog -> outString ( "String: %s" , m_strTarget . c_str ());
2010-12-23 23:25:44 +01:00
sLog -> outString ( "speed: %f" , m_speed );
sLog -> outString ( "elevation: %f" , m_elevation );
2010-08-08 20:32:14 +02:00
}
2011-07-26 23:09:28 +02:00
SpellValue :: SpellValue ( SpellInfo const * proto )
{
for ( uint32 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
EffectBasePoints [ i ] = proto -> Effects [ i ]. BasePoints ;
MaxAffectedTargets = proto -> MaxAffectedTargets ;
RadiusMod = 1.0f ;
AuraStackAmount = 1 ;
}
2011-09-15 14:08:17 +02:00
Spell :: Spell ( Unit * caster , SpellInfo const * info , TriggerCastFlags triggerFlags , uint64 originalCasterGUID , bool skipCheck ) :
2011-07-31 19:03:06 +02:00
m_spellInfo ( sSpellMgr -> GetSpellForDifficultyFromSpell ( info , caster )),
2011-08-20 09:32:19 +02:00
m_caster (( info -> AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster -> GetCharmerOrOwner ()) ? caster -> GetCharmerOrOwner () : caster )
, m_spellValue ( new SpellValue ( m_spellInfo ))
2010-02-20 23:59:05 +01:00
{
2011-03-04 21:18:38 +01:00
m_customError = SPELL_CUSTOM_ERROR_NONE ;
2010-02-20 23:59:05 +01:00
m_skipCheck = skipCheck ;
m_selfContainer = NULL ;
m_referencedFromCurrentSpell = false ;
m_executedCurrently = false ;
2011-07-26 23:09:28 +02:00
m_needComboPoints = m_spellInfo -> NeedsComboPoints ();
2010-02-20 23:59:05 +01:00
m_comboPointGain = 0 ;
m_delayStart = 0 ;
m_delayAtDamageCount = 0 ;
2010-12-04 10:31:14 +01:00
m_applyMultiplierMask = 0 ;
2010-02-20 23:59:05 +01:00
m_auraScaleMask = 0 ;
// Get data for type of attack
switch ( m_spellInfo -> DmgClass )
{
case SPELL_DAMAGE_CLASS_MELEE :
2010-12-19 05:15:47 +01:00
if ( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_REQ_OFFHAND )
2010-02-20 23:59:05 +01:00
m_attackType = OFF_ATTACK ;
else
m_attackType = BASE_ATTACK ;
break ;
case SPELL_DAMAGE_CLASS_RANGED :
2011-07-26 23:09:28 +02:00
m_attackType = m_spellInfo -> IsRangedWeaponSpell () ? RANGED_ATTACK : BASE_ATTACK ;
2010-02-20 23:59:05 +01:00
break ;
default :
// Wands
2010-12-19 05:15:47 +01:00
if ( m_spellInfo -> AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG )
2010-02-20 23:59:05 +01:00
m_attackType = RANGED_ATTACK ;
else
m_attackType = BASE_ATTACK ;
break ;
}
2011-07-26 23:09:28 +02:00
m_spellSchoolMask = info -> GetSchoolMask (); // Can be override for some spell (wand shoot for example)
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( m_attackType == RANGED_ATTACK )
2010-02-20 23:59:05 +01:00
// wand case
2010-04-07 19:14:10 +02:00
if (( m_caster -> getClassMask () & CLASSMASK_WAND_USERS ) != 0 && m_caster -> GetTypeId () == TYPEID_PLAYER )
if ( Item * pItem = m_caster -> ToPlayer () -> GetWeaponForAttack ( RANGED_ATTACK ))
2011-04-28 22:42:33 +02:00
m_spellSchoolMask = SpellSchoolMask ( 1 << pItem -> GetTemplate () -> Damage [ 0 ]. DamageType );
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( originalCasterGUID )
2010-02-20 23:59:05 +01:00
m_originalCasterGUID = originalCasterGUID ;
else
m_originalCasterGUID = m_caster -> GetGUID ();
2010-04-07 19:14:10 +02:00
if ( m_originalCasterGUID == m_caster -> GetGUID ())
2010-02-20 23:59:05 +01:00
m_originalCaster = m_caster ;
else
{
m_originalCaster = ObjectAccessor :: GetUnit ( * m_caster , m_originalCasterGUID );
2011-08-18 20:24:46 +02:00
if ( m_originalCaster && ! m_originalCaster -> IsInWorld ())
m_originalCaster = NULL ;
2010-02-20 23:59:05 +01:00
}
m_spellState = SPELL_STATE_NULL ;
2011-07-31 19:03:06 +02:00
_triggeredCastFlags = triggerFlags ;
if ( info -> AttributesEx4 & SPELL_ATTR4_TRIGGERED )
_triggeredCastFlags = TRIGGERED_FULL_MASK ;
2010-02-20 23:59:05 +01:00
m_CastItem = NULL ;
2011-08-10 15:08:22 +02:00
m_castItemGUID = 0 ;
2010-02-20 23:59:05 +01:00
unitTarget = NULL ;
itemTarget = NULL ;
gameObjTarget = NULL ;
focusObject = NULL ;
m_cast_count = 0 ;
m_glyphIndex = 0 ;
m_preCastSpell = 0 ;
m_triggeredByAuraSpell = NULL ;
m_spellAura = NULL ;
//Auto Shot & Shoot (wand)
2011-07-26 23:09:28 +02:00
m_autoRepeat = m_spellInfo -> IsAutoRepeatRangedSpell ();
2010-02-20 23:59:05 +01:00
m_runesState = 0 ;
2011-08-30 13:46:36 +02:00
m_powerCost = 0 ; // setup to correct value in Spell::prepare, must not be used before.
m_casttime = 0 ; // setup to correct value in Spell::prepare, must not be used before.
2010-02-20 23:59:05 +01:00
m_timer = 0 ; // will set to castime in prepare
2010-08-30 17:32:51 +02:00
m_channelTargetEffectMask = 0 ;
2010-02-20 23:59:05 +01:00
2011-07-13 20:14:55 +02:00
// Determine if spell can be reflected back to the caster
2011-07-12 06:34:57 +02:00
// Patch 1.2 notes: Spell Reflection no longer reflects abilities
2011-07-15 12:33:03 +02:00
m_canReflect = m_spellInfo -> DmgClass == SPELL_DAMAGE_CLASS_MAGIC && ! ( m_spellInfo -> Attributes & SPELL_ATTR0_ABILITY )
2011-07-13 20:14:55 +02:00
&& ! ( m_spellInfo -> AttributesEx & SPELL_ATTR1_CANT_BE_REFLECTED ) && ! ( m_spellInfo -> Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY )
2011-07-26 23:09:28 +02:00
&& ! m_spellInfo -> IsPassive () && ! m_spellInfo -> IsPositive ();
2010-02-20 23:59:05 +01:00
CleanupTargetList ();
2010-08-27 17:49:32 +02:00
CleanupEffectExecuteData ();
2010-02-20 23:59:05 +01:00
}
Spell ::~ Spell ()
{
2010-07-24 22:41:42 +02:00
// unload scripts
2011-09-29 12:43:05 +02:00
while ( ! m_loadedScripts . empty ())
2010-07-24 22:41:42 +02:00
{
2011-09-15 14:08:17 +02:00
std :: list < SpellScript *>:: iterator itr = m_loadedScripts . begin ();
2010-10-04 17:44:49 +02:00
( * itr ) -> _Unload ();
2010-07-24 22:41:42 +02:00
delete ( * itr );
m_loadedScripts . erase ( itr );
}
2010-10-04 17:44:49 +02:00
2010-05-31 19:19:30 +02:00
if ( m_referencedFromCurrentSpell && m_selfContainer && * m_selfContainer == this )
{
// Clean the reference to avoid later crash.
2010-07-30 20:04:28 +02:00
// If this error is repeating, we may have to add an ASSERT to better track down how we get into this case.
2010-12-23 23:25:44 +01:00
sLog -> outError ( "SPELL: deleting spell for spell ID %u. However, spell still referenced." , m_spellInfo -> Id );
2010-05-31 19:19:30 +02:00
* m_selfContainer = NULL ;
}
2010-04-07 19:14:10 +02:00
if ( m_caster && m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-07-30 20:04:28 +02:00
ASSERT ( m_caster -> ToPlayer () -> m_spellModTakingSpell != this );
2010-02-20 23:59:05 +01:00
delete m_spellValue ;
2010-08-27 17:49:32 +02:00
CheckEffectExecuteData ();
2010-02-20 23:59:05 +01:00
}
template < typename T >
WorldObject * Spell :: FindCorpseUsing ()
{
// non-standard target selection
2011-07-26 23:09:28 +02:00
float max_range = m_spellInfo -> GetMaxRange ( false );
2010-02-20 23:59:05 +01:00
2011-10-18 10:53:34 -04:00
CellCoord p ( Trinity :: ComputeCellCoord ( m_caster -> GetPositionX (), m_caster -> GetPositionY ()));
2010-02-20 23:59:05 +01:00
Cell cell ( p );
cell . SetNoCreate ();
WorldObject * result = NULL ;
T u_check ( m_caster , max_range );
Trinity :: WorldObjectSearcher < T > searcher ( m_caster , result , u_check );
TypeContainerVisitor < Trinity :: WorldObjectSearcher < T > , GridTypeMapContainer > grid_searcher ( searcher );
cell . Visit ( p , grid_searcher , * m_caster -> GetMap (), * m_caster , max_range );
if ( ! result )
{
TypeContainerVisitor < Trinity :: WorldObjectSearcher < T > , WorldTypeMapContainer > world_searcher ( searcher );
cell . Visit ( p , world_searcher , * m_caster -> GetMap (), * m_caster , max_range );
}
return result ;
}
2011-08-24 08:07:59 +02:00
void Spell :: InitExplicitTargets ( SpellCastTargets const & targets )
{
m_targets = targets ;
// this function tries to correct spell explicit targets for spell
// client doesn't send explicit targets correctly sometimes - we need to fix such spells serverside
// this also makes sure that we correctly send explicit targets to client (removes redundant data)
uint32 neededTargets = m_spellInfo -> GetExplicitTargetMask ();
2011-08-26 12:05:47 +02:00
if ( WorldObject * target = m_targets . GetObjectTarget ())
2011-08-24 08:07:59 +02:00
{
2011-08-26 12:05:47 +02:00
// check if object target is valid with needed target flags
// for unit case allow corpse target mask because player with not released corpse is a unit target
if (( target -> ToUnit () && ! ( neededTargets & ( TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK )))
|| ( target -> ToGameObject () && ! ( neededTargets & TARGET_FLAG_GAMEOBJECT_MASK ))
|| ( target -> ToCorpse () && ! ( neededTargets & TARGET_FLAG_CORPSE_MASK )))
m_targets . RemoveObjectTarget ();
}
else
{
// try to select correct unit target if not provided by client or by serverside cast
if ( neededTargets & ( TARGET_FLAG_UNIT_MASK ))
2011-08-24 08:07:59 +02:00
{
2011-08-26 12:05:47 +02:00
Unit * target = NULL ;
2011-08-24 08:07:59 +02:00
// try to use player selection as a target
if ( Player * playerCaster = m_caster -> ToPlayer ())
{
// selection has to be found and to be valid target for the spell
if ( Unit * selectedUnit = ObjectAccessor :: GetUnit ( * m_caster , playerCaster -> GetSelection ()))
2011-08-26 12:05:47 +02:00
if ( m_spellInfo -> CheckExplicitTarget ( m_caster , selectedUnit ) == SPELL_CAST_OK )
2011-08-24 08:07:59 +02:00
target = selectedUnit ;
}
// try to use attacked unit as a target
else if (( m_caster -> GetTypeId () == TYPEID_UNIT ) && neededTargets & ( TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT ))
target = m_caster -> getVictim ();
// didn't find anything - let's use self as target
2011-09-23 11:58:01 +02:00
if ( ! target && neededTargets & ( TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_ALLY ))
2011-08-24 08:07:59 +02:00
target = m_caster ;
2011-08-26 12:05:47 +02:00
m_targets . SetUnitTarget ( target );
2011-08-24 08:07:59 +02:00
}
}
// check if spell needs dst target
if ( neededTargets & TARGET_FLAG_DEST_LOCATION )
{
// and target isn't set
2011-08-26 16:30:56 +02:00
if ( ! m_targets . HasDst ())
2011-08-24 08:07:59 +02:00
{
// try to use unit target if provided
2011-08-26 16:30:56 +02:00
if ( WorldObject * target = targets . GetObjectTarget ())
2011-08-24 08:07:59 +02:00
m_targets . SetDst ( * target );
// or use self if not available
else
m_targets . SetDst ( * m_caster );
}
}
else
m_targets . RemoveDst ();
if ( neededTargets & TARGET_FLAG_SOURCE_LOCATION )
{
2011-08-26 16:30:56 +02:00
if ( ! targets . HasSrc ())
2011-08-24 08:07:59 +02:00
m_targets . SetSrc ( * m_caster );
}
else
m_targets . RemoveSrc ();
}
2010-02-20 23:59:05 +01:00
void Spell :: SelectSpellTargets ()
{
2011-09-16 11:40:53 +02:00
uint32 processedTargets = 0 ;
2010-09-28 08:41:24 +03:00
for ( uint32 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2010-02-20 23:59:05 +01:00
{
// not call for empty effect.
// Also some spells use not used effect targets for store targets for dummy effect in triggered spells
2011-09-16 11:40:53 +02:00
if ( ! m_spellInfo -> Effects [ i ]. IsEffect ())
continue ;
if ( processedTargets & ( 1 << i ))
2010-02-20 23:59:05 +01:00
continue ;
2011-08-27 12:59:05 +02:00
// set expected type of implicit targets to be sent to client
uint32 implicitTargetMask = GetTargetFlagMask ( m_spellInfo -> Effects [ i ]. TargetA . GetObjectType ()) | GetTargetFlagMask ( m_spellInfo -> Effects [ i ]. TargetB . GetObjectType ());
if ( implicitTargetMask & TARGET_FLAG_UNIT )
m_targets . SetTargetFlag ( TARGET_FLAG_UNIT );
if ( implicitTargetMask & ( TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_GAMEOBJECT_ITEM ))
m_targets . SetTargetFlag ( TARGET_FLAG_GAMEOBJECT );
2011-07-27 12:35:59 +02:00
uint32 targetA = m_spellInfo -> Effects [ i ]. TargetA . GetTarget ();
uint32 targetB = m_spellInfo -> Effects [ i ]. TargetB . GetTarget ();
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( targetA )
2011-09-16 11:40:53 +02:00
processedTargets |= SelectEffectTargets ( i , m_spellInfo -> Effects [ i ]. TargetA );
2011-09-23 11:58:01 +02:00
if ( targetB )
2011-09-16 11:40:53 +02:00
processedTargets |= SelectEffectTargets ( i , m_spellInfo -> Effects [ i ]. TargetB );
2010-02-20 23:59:05 +01:00
2011-09-23 11:58:01 +02:00
// Select targets of effect based on effect type
// those are used when no valid target could be added for spell effect based on spell target type
// some spell effects use explicit target as a default target added to target map (like SPELL_EFFECT_LEARN_SPELL)
// some spell effects add target to target map only when target type specified (like SPELL_EFFECT_WEAPON)
// some spell effects don't add anything to target map (confirmed with sniffs) (like SPELL_EFFECT_DESTROY_ALL_TOTEMS)
SelectEffectTypeImplicitTargets ( i );
2011-07-28 23:44:39 +02:00
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> IsChanneled ())
2010-02-20 23:59:05 +01:00
{
2011-09-16 11:40:53 +02:00
uint8 mask = ( 1 << i );
2010-02-20 23:59:05 +01:00
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
{
2010-04-07 19:14:10 +02:00
if ( ihit -> effectMask & mask )
2010-02-20 23:59:05 +01:00
{
2010-08-30 17:32:51 +02:00
m_channelTargetEffectMask |= mask ;
2010-02-20 23:59:05 +01:00
break ;
}
}
}
else if ( m_auraScaleMask )
{
bool checkLvl = ! m_UniqueTargetInfo . empty ();
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end ();)
{
// remove targets which did not pass min level check
2010-04-07 19:14:10 +02:00
if ( m_auraScaleMask && ihit -> effectMask == m_auraScaleMask )
2010-02-20 23:59:05 +01:00
{
// Do not check for selfcast
if ( ! ihit -> scaleAura && ihit -> targetGUID != m_caster -> GetGUID ())
{
m_UniqueTargetInfo . erase ( ihit ++ );
continue ;
}
}
++ ihit ;
}
if ( checkLvl && m_UniqueTargetInfo . empty ())
{
SendCastResult ( SPELL_FAILED_LOWLEVEL );
finish ( false );
}
}
}
2010-04-07 19:14:10 +02:00
if ( m_targets . HasDst ())
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( m_targets . HasTraj ())
2010-02-20 23:59:05 +01:00
{
float speed = m_targets . GetSpeedXY ();
2010-04-07 19:14:10 +02:00
if ( speed > 0.0f )
2010-02-20 23:59:05 +01:00
m_delayMoment = ( uint64 ) floor ( m_targets . GetDist2d () / speed * 1000.0f );
}
2011-07-26 23:09:28 +02:00
else if ( m_spellInfo -> Speed > 0.0f )
2010-02-20 23:59:05 +01:00
{
2011-06-23 13:28:52 +02:00
float dist = m_caster -> GetDistance ( * m_targets . GetDst ());
2011-07-26 23:09:28 +02:00
m_delayMoment = ( uint64 ) floor ( dist / m_spellInfo -> Speed * 1000.0f );
2010-02-20 23:59:05 +01:00
}
}
}
2011-09-23 11:58:01 +02:00
void Spell :: SelectEffectTypeImplicitTargets ( uint8 effIndex )
{
// special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER
// TODO: this is a workaround - target shouldn't be stored in target map for those spells
switch ( m_spellInfo -> Effects [ effIndex ]. Effect )
{
case SPELL_EFFECT_SUMMON_RAF_FRIEND :
case SPELL_EFFECT_SUMMON_PLAYER :
if ( m_caster -> GetTypeId () == TYPEID_PLAYER && m_caster -> ToPlayer () -> GetSelection ())
{
Player * target = ObjectAccessor :: FindPlayer ( m_caster -> ToPlayer () -> GetSelection ());
if ( target )
AddUnitTarget ( target , 1 << effIndex , false );
}
return ;
default :
break ;
}
// select spell implicit targets based on effect type
if ( ! m_spellInfo -> Effects [ effIndex ]. GetImplicitTargetType ())
return ;
uint32 targetMask = m_spellInfo -> Effects [ effIndex ]. GetMissingTargetMask ();
if ( ! targetMask )
return ;
switch ( m_spellInfo -> Effects [ effIndex ]. GetImplicitTargetType ())
{
2011-09-24 19:40:57 +02:00
// add explicit object target or self to the target map
2011-09-23 11:58:01 +02:00
case EFFECT_IMPLICIT_TARGET_EXPLICIT :
// player which not released his spirit is Unit, but target flag for it is TARGET_FLAG_CORPSE_MASK
if ( targetMask & ( TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK ))
{
if ( Unit * unitTarget = m_targets . GetUnitTarget ())
AddUnitTarget ( unitTarget , 1 << effIndex , false );
else if ( targetMask & TARGET_FLAG_CORPSE_MASK )
{
if ( Corpse * corpseTarget = m_targets . GetCorpseTarget ())
{
// TODO: this is a workaround - corpses should be added to spell target map too, but we can't do that so we add owner instead
if ( Player * owner = ObjectAccessor :: FindPlayer ( corpseTarget -> GetOwnerGUID ()))
AddUnitTarget ( owner , 1 << effIndex , false );
}
}
else //if (targetMask & TARGET_FLAG_UNIT_MASK)
{
AddUnitTarget ( m_caster , 1 << effIndex , false );
}
}
if ( targetMask & TARGET_FLAG_ITEM_MASK )
{
if ( Item * itemTarget = m_targets . GetItemTarget ())
AddItemTarget ( itemTarget , 1 << effIndex );
}
if ( targetMask & TARGET_FLAG_GAMEOBJECT_MASK )
{
if ( GameObject * gObjTarget = m_targets . GetGOTarget ())
AddGOTarget ( gObjTarget , 1 << effIndex );
}
break ;
2011-09-24 19:40:57 +02:00
// add self to the target map
2011-09-23 11:58:01 +02:00
case EFFECT_IMPLICIT_TARGET_CASTER :
if ( targetMask & TARGET_FLAG_UNIT_MASK )
AddUnitTarget ( m_caster , 1 << effIndex , false );
break ;
2011-09-28 11:11:38 +02:00
default :
break ;
2011-09-23 11:58:01 +02:00
}
}
2011-06-11 22:35:29 +02:00
void Spell :: prepareDataForTriggerSystem ( AuraEffect const * /*triggeredByAura*/ )
2010-02-20 23:59:05 +01:00
{
//==========================================================================================
// Now fill data for trigger system, need know:
2010-04-07 22:59:46 +02:00
// can spell trigger another or not (m_canTrigger)
// Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_procEx)
2010-02-20 23:59:05 +01:00
//==========================================================================================
m_procVictim = m_procAttacker = 0 ;
// Get data for type of attack and fill base info for trigger
switch ( m_spellInfo -> DmgClass )
{
case SPELL_DAMAGE_CLASS_MELEE :
2010-10-08 19:17:49 +02:00
m_procAttacker = PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS ;
2010-07-25 17:06:12 +02:00
if ( m_attackType == OFF_ATTACK )
2010-10-08 19:17:49 +02:00
m_procAttacker |= PROC_FLAG_DONE_OFFHAND_ATTACK ;
else
m_procAttacker |= PROC_FLAG_DONE_MAINHAND_ATTACK ;
2011-06-15 23:16:45 +07:00
m_procVictim = PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS ;
2010-02-20 23:59:05 +01:00
break ;
case SPELL_DAMAGE_CLASS_RANGED :
// Auto attack
2010-12-19 05:15:47 +01:00
if ( m_spellInfo -> AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG )
2010-02-20 23:59:05 +01:00
{
2010-10-08 19:17:49 +02:00
m_procAttacker = PROC_FLAG_DONE_RANGED_AUTO_ATTACK ;
m_procVictim = PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK ;
2010-02-20 23:59:05 +01:00
}
else // Ranged spell attack
{
2010-10-08 19:17:49 +02:00
m_procAttacker = PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS ;
m_procVictim = PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS ;
2010-02-20 23:59:05 +01:00
}
break ;
default :
if ( m_spellInfo -> EquippedItemClass == ITEM_CLASS_WEAPON &&
m_spellInfo -> EquippedItemSubClassMask & ( 1 << ITEM_SUBCLASS_WEAPON_WAND )
2010-12-19 05:15:47 +01:00
&& m_spellInfo -> AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG ) // Wands auto attack
2010-02-20 23:59:05 +01:00
{
2010-10-08 19:17:49 +02:00
m_procAttacker = PROC_FLAG_DONE_RANGED_AUTO_ATTACK ;
m_procVictim = PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK ;
2010-02-20 23:59:05 +01:00
}
// For other spells trigger procflags are set in Spell::DoAllEffectOnTarget
// Because spell positivity is dependant on target
}
2011-06-15 23:16:45 +07:00
m_procEx = PROC_EX_NONE ;
2010-02-20 23:59:05 +01:00
// Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection
2010-04-07 18:09:10 +02:00
if ( m_spellInfo -> SpellFamilyName == SPELLFAMILY_HUNTER &&
2010-02-20 23:59:05 +01:00
( m_spellInfo -> SpellFamilyFlags [ 0 ] & 0x18 || // Freezing and Frost Trap, Freezing Arrow
m_spellInfo -> Id == 57879 || // Snake Trap - done this way to avoid double proc
m_spellInfo -> SpellFamilyFlags [ 2 ] & 0x00024000 )) // Explosive and Immolation Trap
2010-04-07 18:09:10 +02:00
2010-10-08 19:17:49 +02:00
m_procAttacker |= PROC_FLAG_DONE_TRAP_ACTIVATION ;
2010-02-20 23:59:05 +01:00
2011-05-22 16:01:53 -07:00
/* Effects which are result of aura proc from triggered spell cannot proc
to prevent chain proc of these spells */
2010-02-20 23:59:05 +01:00
2010-09-29 01:50:07 +02:00
// Hellfire Effect - trigger as DOT
if ( m_spellInfo -> SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo -> SpellFamilyFlags [ 0 ] & 0x00000040 )
2010-07-21 01:15:27 +02:00
{
2010-10-08 19:17:49 +02:00
m_procAttacker = PROC_FLAG_DONE_PERIODIC ;
m_procVictim = PROC_FLAG_TAKEN_PERIODIC ;
2010-07-21 01:15:27 +02:00
}
2010-02-20 23:59:05 +01:00
// Ranged autorepeat attack is set as triggered spell - ignore it
2010-10-08 19:17:49 +02:00
if ( ! ( m_procAttacker & PROC_FLAG_DONE_RANGED_AUTO_ATTACK ))
2010-02-20 23:59:05 +01:00
{
2011-07-31 23:47:11 +02:00
if ( _triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS &&
2011-07-13 17:18:04 +02:00
( m_spellInfo -> AttributesEx2 & SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC ||
m_spellInfo -> AttributesEx3 & SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2 ))
2010-02-20 23:59:05 +01:00
m_procEx |= PROC_EX_INTERNAL_CANT_PROC ;
2011-07-31 23:47:11 +02:00
else if ( _triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS )
2010-02-20 23:59:05 +01:00
m_procEx |= PROC_EX_INTERNAL_TRIGGERED ;
}
// Totem casts require spellfamilymask defined in spell_proc_event to proc
2010-03-07 18:30:53 +01:00
if ( m_originalCaster && m_caster != m_originalCaster && m_caster -> GetTypeId () == TYPEID_UNIT && m_caster -> ToCreature () -> isTotem () && m_caster -> IsControlledByPlayer ())
2010-02-20 23:59:05 +01:00
m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY ;
}
void Spell :: CleanupTargetList ()
{
m_UniqueTargetInfo . clear ();
m_UniqueGOTargetInfo . clear ();
m_UniqueItemInfo . clear ();
m_delayMoment = 0 ;
}
2011-09-16 11:40:53 +02:00
void Spell :: AddUnitTarget ( Unit * target , uint32 effectMask , bool checkIfValid /*= true*/ )
2010-02-20 23:59:05 +01:00
{
2011-09-16 11:40:53 +02:00
for ( uint32 effIndex = 0 ; effIndex < MAX_SPELL_EFFECTS ; ++ effIndex )
if ( ! m_spellInfo -> Effects [ effIndex ]. IsEffect () || ! CheckEffectTarget ( target , effIndex ))
effectMask &= ~ ( 1 << effIndex );
// no effects left
if ( ! effectMask )
2010-02-20 23:59:05 +01:00
return ;
2011-08-19 14:53:40 +02:00
if ( checkIfValid )
2011-09-16 11:40:53 +02:00
if ( m_spellInfo -> CheckTarget ( m_caster , target , true ) != SPELL_CAST_OK )
2011-08-19 14:53:40 +02:00
return ;
2010-02-20 23:59:05 +01:00
// Check for effect immune skip if immuned
2011-09-16 11:40:53 +02:00
for ( uint32 effIndex = 0 ; effIndex < MAX_SPELL_EFFECTS ; ++ effIndex )
if ( target -> IsImmunedToSpellEffect ( m_spellInfo , effIndex ))
effectMask &= ~ ( 1 << effIndex );
2010-02-20 23:59:05 +01:00
2011-09-16 11:40:53 +02:00
uint64 targetGUID = target -> GetGUID ();
2010-02-20 23:59:05 +01:00
// Lookup target in already in list
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
{
2011-09-16 11:40:53 +02:00
if ( targetGUID == ihit -> targetGUID ) // Found in list
2010-02-20 23:59:05 +01:00
{
2011-09-16 11:40:53 +02:00
ihit -> effectMask |= effectMask ; // Immune effects removed from mask
2010-02-20 23:59:05 +01:00
ihit -> scaleAura = false ;
2011-09-16 11:40:53 +02:00
if ( m_auraScaleMask && ihit -> effectMask == m_auraScaleMask && m_caster != target )
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
SpellInfo const * auraSpell = sSpellMgr -> GetSpellInfo ( sSpellMgr -> GetFirstSpellInChain ( m_spellInfo -> Id ));
2011-09-16 11:40:53 +02:00
if ( uint32 ( target -> getLevel () + 10 ) >= auraSpell -> SpellLevel )
2010-02-20 23:59:05 +01:00
ihit -> scaleAura = true ;
}
return ;
}
}
// This is new target calculate data for him
// Get spell hit result on target
2011-09-16 11:40:53 +02:00
TargetInfo targetInfo ;
targetInfo . targetGUID = targetGUID ; // Store target GUID
targetInfo . effectMask = effectMask ; // Store all effects not immune
targetInfo . processed = false ; // Effects not apply on target
targetInfo . alive = target -> isAlive ();
targetInfo . damage = 0 ;
targetInfo . crit = false ;
targetInfo . scaleAura = false ;
if ( m_auraScaleMask && targetInfo . effectMask == m_auraScaleMask && m_caster != target )
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
SpellInfo const * auraSpell = sSpellMgr -> GetSpellInfo ( sSpellMgr -> GetFirstSpellInChain ( m_spellInfo -> Id ));
2011-09-16 11:40:53 +02:00
if ( uint32 ( target -> getLevel () + 10 ) >= auraSpell -> SpellLevel )
targetInfo . scaleAura = true ;
2010-02-20 23:59:05 +01:00
}
// Calculate hit result
if ( m_originalCaster )
{
2011-09-16 11:40:53 +02:00
targetInfo . missCondition = m_originalCaster -> SpellHitResult ( target , m_spellInfo , m_canReflect );
if ( m_skipCheck && targetInfo . missCondition != SPELL_MISS_IMMUNE )
targetInfo . missCondition = SPELL_MISS_NONE ;
2010-02-20 23:59:05 +01:00
}
else
2011-09-16 11:40:53 +02:00
targetInfo . missCondition = SPELL_MISS_EVADE ; //SPELL_MISS_NONE;
2010-02-20 23:59:05 +01:00
// Spell have speed - need calculate incoming time
// Incoming time is zero for self casts. At least I think so.
2011-09-16 11:40:53 +02:00
if ( m_spellInfo -> Speed > 0.0f && m_caster != target )
2010-02-20 23:59:05 +01:00
{
// calculate spell incoming interval
// TODO: this is a hack
2011-09-16 11:40:53 +02:00
float dist = m_caster -> GetDistance ( target -> GetPositionX (), target -> GetPositionY (), target -> GetPositionZ ());
2010-02-20 23:59:05 +01:00
2011-09-16 11:40:53 +02:00
if ( dist < 5.0f )
dist = 5.0f ;
targetInfo . timeDelay = ( uint64 ) floor ( dist / m_spellInfo -> Speed * 1000.0f );
2010-02-20 23:59:05 +01:00
// Calculate minimum incoming time
2011-09-16 11:40:53 +02:00
if ( m_delayMoment == 0 || m_delayMoment > targetInfo . timeDelay )
m_delayMoment = targetInfo . timeDelay ;
2010-02-20 23:59:05 +01:00
}
else
2011-09-16 11:40:53 +02:00
targetInfo . timeDelay = 0LL ;
2010-02-20 23:59:05 +01:00
// If target reflect spell back to caster
2011-09-16 11:40:53 +02:00
if ( targetInfo . missCondition == SPELL_MISS_REFLECT )
2010-02-20 23:59:05 +01:00
{
// Calculate reflected spell result on caster
2011-09-16 11:40:53 +02:00
targetInfo . reflectResult = m_caster -> SpellHitResult ( m_caster , m_spellInfo , m_canReflect );
2010-02-20 23:59:05 +01:00
2011-09-16 11:40:53 +02:00
if ( targetInfo . reflectResult == SPELL_MISS_REFLECT ) // Impossible reflect again, so simply deflect spell
targetInfo . reflectResult = SPELL_MISS_PARRY ;
2010-02-20 23:59:05 +01:00
// Increase time interval for reflected spells by 1.5
2011-09-16 11:40:53 +02:00
targetInfo . timeDelay += targetInfo . timeDelay >> 1 ;
2010-02-20 23:59:05 +01:00
}
else
2011-09-16 11:40:53 +02:00
targetInfo . reflectResult = SPELL_MISS_NONE ;
2010-02-20 23:59:05 +01:00
// Add target to list
2011-09-16 11:40:53 +02:00
m_UniqueTargetInfo . push_back ( targetInfo );
2010-02-20 23:59:05 +01:00
}
2011-09-16 11:40:53 +02:00
void Spell :: AddGOTarget ( GameObject * go , uint32 effectMask )
2010-02-20 23:59:05 +01:00
{
2011-09-16 11:40:53 +02:00
for ( uint32 effIndex = 0 ; effIndex < MAX_SPELL_EFFECTS ; ++ effIndex )
2011-07-22 21:22:05 +02:00
{
2011-09-16 11:40:53 +02:00
if ( ! m_spellInfo -> Effects [ effIndex ]. IsEffect ())
effectMask &= ~ ( 1 << effIndex );
else
{
switch ( m_spellInfo -> Effects [ effIndex ]. Effect )
{
case SPELL_EFFECT_GAMEOBJECT_DAMAGE :
case SPELL_EFFECT_GAMEOBJECT_REPAIR :
case SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE :
if ( go -> GetGoType () != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING )
effectMask &= ~ ( 1 << effIndex );
break ;
default :
break ;
}
}
2011-07-22 21:22:05 +02:00
}
2011-09-16 11:40:53 +02:00
if ( ! effectMask )
return ;
2011-07-22 21:22:05 +02:00
uint64 targetGUID = go -> GetGUID ();
2010-02-20 23:59:05 +01:00
// Lookup target in already in list
for ( std :: list < GOTargetInfo >:: iterator ihit = m_UniqueGOTargetInfo . begin (); ihit != m_UniqueGOTargetInfo . end (); ++ ihit )
2011-07-22 21:22:05 +02:00
{
2010-02-20 23:59:05 +01:00
if ( targetGUID == ihit -> targetGUID ) // Found in list
{
2011-09-16 11:40:53 +02:00
ihit -> effectMask |= effectMask ; // Add only effect mask
2010-02-20 23:59:05 +01:00
return ;
}
2011-07-22 21:22:05 +02:00
}
2010-02-20 23:59:05 +01:00
// This is new target calculate data for him
GOTargetInfo target ;
target . targetGUID = targetGUID ;
2011-09-16 11:40:53 +02:00
target . effectMask = effectMask ;
2010-02-20 23:59:05 +01:00
target . processed = false ; // Effects not apply on target
// Spell have speed - need calculate incoming time
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Speed > 0.0f )
2010-02-20 23:59:05 +01:00
{
// calculate spell incoming interval
2011-07-22 21:22:05 +02:00
float dist = m_caster -> GetDistance ( go -> GetPositionX (), go -> GetPositionY (), go -> GetPositionZ ());
if ( dist < 5.0f )
dist = 5.0f ;
2011-07-26 23:09:28 +02:00
target . timeDelay = uint64 ( floor ( dist / m_spellInfo -> Speed * 1000.0f ));
2011-07-22 21:22:05 +02:00
if ( m_delayMoment == 0 || m_delayMoment > target . timeDelay )
2010-02-20 23:59:05 +01:00
m_delayMoment = target . timeDelay ;
}
else
target . timeDelay = 0LL ;
// Add target to list
m_UniqueGOTargetInfo . push_back ( target );
}
2011-09-16 11:40:53 +02:00
void Spell :: AddGOTarget ( uint64 goGUID , uint32 effectMask )
2010-02-20 23:59:05 +01:00
{
2011-07-22 21:22:05 +02:00
if ( GameObject * go = m_caster -> GetMap () -> GetGameObject ( goGUID ))
2011-09-16 11:40:53 +02:00
AddGOTarget ( go , effectMask );
2010-02-20 23:59:05 +01:00
}
2011-09-16 11:40:53 +02:00
void Spell :: AddItemTarget ( Item * item , uint32 effectMask )
2010-02-20 23:59:05 +01:00
{
2011-09-16 11:40:53 +02:00
for ( uint32 effIndex = 0 ; effIndex < MAX_SPELL_EFFECTS ; ++ effIndex )
if ( ! m_spellInfo -> Effects [ effIndex ]. IsEffect ())
effectMask &= ~ ( 1 << effIndex );
// no effects left
if ( ! effectMask )
2010-02-20 23:59:05 +01:00
return ;
// Lookup target in already in list
for ( std :: list < ItemTargetInfo >:: iterator ihit = m_UniqueItemInfo . begin (); ihit != m_UniqueItemInfo . end (); ++ ihit )
2011-09-16 11:40:53 +02:00
{
if ( item == ihit -> item ) // Found in list
2010-02-20 23:59:05 +01:00
{
2011-09-16 11:40:53 +02:00
ihit -> effectMask |= effectMask ; // Add only effect mask
2010-02-20 23:59:05 +01:00
return ;
}
2011-09-16 11:40:53 +02:00
}
2010-02-20 23:59:05 +01:00
// This is new target add data
ItemTargetInfo target ;
2011-09-16 11:40:53 +02:00
target . item = item ;
target . effectMask = effectMask ;
2010-02-20 23:59:05 +01:00
m_UniqueItemInfo . push_back ( target );
}
2011-09-15 14:08:17 +02:00
void Spell :: DoAllEffectOnTarget ( TargetInfo * target )
2010-02-20 23:59:05 +01:00
{
2010-03-29 21:47:07 +02:00
if ( ! target || target -> processed )
2010-02-20 23:59:05 +01:00
return ;
2010-03-29 21:47:07 +02:00
2010-02-20 23:59:05 +01:00
target -> processed = true ; // Target checked in apply effects procedure
// Get mask of effects for target
2010-07-29 19:48:40 +02:00
uint8 mask = target -> effectMask ;
2010-02-20 23:59:05 +01:00
2011-04-29 20:47:02 +02:00
Unit * unit = m_caster -> GetGUID () == target -> targetGUID ? m_caster : ObjectAccessor :: GetUnit ( * m_caster , target -> targetGUID );
2010-02-20 23:59:05 +01:00
if ( ! unit )
2010-07-29 19:48:40 +02:00
{
uint8 farMask = 0 ;
// create far target mask
2011-06-12 02:30:32 +02:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ i ]. IsFarUnitTargetEffect ())
2011-05-22 16:01:53 -07:00
if (( 1 << i ) & mask )
farMask |= ( 1 << i );
2010-07-29 19:48:40 +02:00
if ( ! farMask )
return ;
// find unit in world
unit = ObjectAccessor :: FindUnit ( target -> targetGUID );
if ( ! unit )
return ;
2011-05-22 16:01:53 -07:00
2010-07-29 19:48:40 +02:00
// do far effects on the unit
// can't use default call because of threading, do stuff as fast as possible
2011-06-12 02:30:32 +02:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2011-05-22 16:01:53 -07:00
if ( farMask & ( 1 << i ))
2011-09-25 13:29:17 +02:00
HandleEffects ( unit , NULL , NULL , i , SPELL_EFFECT_HANDLE_HIT_TARGET );
2010-02-20 23:59:05 +01:00
return ;
2010-07-29 19:48:40 +02:00
}
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( unit -> isAlive () != target -> alive )
2010-02-20 23:59:05 +01:00
return ;
2011-07-26 23:09:28 +02:00
if ( getState () == SPELL_STATE_DELAYED && ! m_spellInfo -> IsPositive () && ( getMSTime () - target -> timeDelay ) <= unit -> m_lastSanctuaryTime )
2010-11-13 18:04:56 +01:00
return ; // No missinfo in that case
2010-02-20 23:59:05 +01:00
// Get original caster (if exist) and calculate damage/healing from him data
2011-09-15 14:08:17 +02:00
Unit * caster = m_originalCaster ? m_originalCaster : m_caster ;
2010-02-20 23:59:05 +01:00
// Skip if m_originalCaster not avaiable
if ( ! caster )
return ;
SpellMissInfo missInfo = target -> missCondition ;
// Need init unitTarget by default unit (can changed in code on reflect)
2010-04-08 08:20:08 +02:00
// Or on missInfo != SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem)
2010-02-20 23:59:05 +01:00
unitTarget = unit ;
// Reset damage/healing counter
m_damage = target -> damage ;
m_healing = - target -> damage ;
// Fill base trigger info
uint32 procAttacker = m_procAttacker ;
uint32 procVictim = m_procVictim ;
uint32 procEx = m_procEx ;
m_spellAura = NULL ; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
//Spells with this flag cannot trigger if effect is casted on self
2011-07-13 17:31:09 +02:00
bool canEffectTrigger = ! ( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_CANT_TRIGGER_PROC ) && unitTarget -> CanProc () && CanExecuteTriggersOnHit ( mask );
2011-06-11 22:35:29 +02:00
Unit * spellHitTarget = NULL ;
2010-02-20 23:59:05 +01:00
2010-04-07 23:25:02 +02:00
if ( missInfo == SPELL_MISS_NONE ) // In case spell hit target, do all effect on that target
2010-02-20 23:59:05 +01:00
spellHitTarget = unit ;
else if ( missInfo == SPELL_MISS_REFLECT ) // In case spell reflect from target, do all effect on caster (if hit)
{
if ( target -> reflectResult == SPELL_MISS_NONE ) // If reflected spell hit caster -> do all effect on him
{
spellHitTarget = m_caster ;
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () == TYPEID_UNIT )
2010-03-07 18:30:53 +01:00
m_caster -> ToCreature () -> LowerPlayerDamageReq ( target -> damage );
2010-02-20 23:59:05 +01:00
}
}
2010-04-07 19:14:10 +02:00
if ( spellHitTarget )
2010-02-20 23:59:05 +01:00
{
SpellMissInfo missInfo = DoSpellHitOnUnit ( spellHitTarget , mask , target -> scaleAura );
2010-04-07 19:14:10 +02:00
if ( missInfo != SPELL_MISS_NONE )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( missInfo != SPELL_MISS_MISS )
2010-02-20 23:59:05 +01:00
m_caster -> SendSpellMiss ( unit , m_spellInfo -> Id , missInfo );
m_damage = 0 ;
spellHitTarget = NULL ;
}
}
// Do not take combo points on dodge and miss
2011-08-30 13:46:36 +02:00
if ( missInfo != SPELL_MISS_NONE && m_needComboPoints &&
m_targets . GetUnitTargetGUID () == target -> targetGUID )
{
m_needComboPoints = false ;
// Restore spell mods for a miss/dodge/parry Cold Blood
// TODO: check how broad this rule should be
if ( m_caster -> GetTypeId () == TYPEID_PLAYER && ( missInfo == SPELL_MISS_MISS ||
missInfo == SPELL_MISS_DODGE || missInfo == SPELL_MISS_PARRY ))
m_caster -> ToPlayer () -> RestoreSpellMods ( this , 14177 );
}
2010-02-20 23:59:05 +01:00
// Trigger info was not filled in spell::preparedatafortriggersystem - we do it now
if ( canEffectTrigger && ! procAttacker && ! procVictim )
{
bool positive = true ;
if ( m_damage > 0 )
positive = false ;
else if ( ! m_healing )
{
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
// If at least one effect negative spell is negative hit
2011-07-26 23:09:28 +02:00
if ( mask & ( 1 << i ) && ! m_spellInfo -> IsPositiveEffect ( i ))
2010-02-20 23:59:05 +01:00
{
positive = false ;
break ;
}
}
2011-08-20 03:06:15 +07:00
switch ( m_spellInfo -> DmgClass )
2010-02-20 23:59:05 +01:00
{
case SPELL_DAMAGE_CLASS_MAGIC :
if ( positive )
{
2010-10-08 19:17:49 +02:00
procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS ;
procVictim |= PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS ;
2010-02-20 23:59:05 +01:00
}
else
{
2010-10-08 19:17:49 +02:00
procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG ;
procVictim |= PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG ;
2010-02-20 23:59:05 +01:00
}
break ;
case SPELL_DAMAGE_CLASS_NONE :
if ( positive )
{
2010-10-08 19:17:49 +02:00
procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS ;
procVictim |= PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS ;
2010-02-20 23:59:05 +01:00
}
else
{
2010-10-08 19:17:49 +02:00
procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG ;
procVictim |= PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG ;
2010-02-20 23:59:05 +01:00
}
break ;
}
}
2010-08-21 20:18:54 +02:00
CallScriptOnHitHandlers ();
2010-02-20 23:59:05 +01:00
// All calculated do it!
// Do healing and triggers
if ( m_healing > 0 )
{
bool crit = caster -> isSpellCrit ( unitTarget , m_spellInfo , m_spellSchoolMask );
uint32 addhealth = m_healing ;
if ( crit )
{
procEx |= PROC_EX_CRITICAL_HIT ;
addhealth = caster -> SpellCriticalHealingBonus ( m_spellInfo , addhealth , NULL );
}
else
procEx |= PROC_EX_NORMAL_HIT ;
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if ( canEffectTrigger && missInfo != SPELL_MISS_REFLECT )
caster -> ProcDamageAndSpell ( unitTarget , procAttacker , procVictim , procEx , addhealth , m_attackType , m_spellInfo , m_triggeredByAuraSpell );
2010-08-27 01:13:27 +02:00
int32 gain = caster -> HealBySpell ( unitTarget , m_spellInfo , addhealth , crit );
2010-03-09 11:11:10 +01:00
unitTarget -> getHostileRefManager (). threatAssist ( caster , float ( gain ) * 0.5f , m_spellInfo );
2011-08-20 00:45:34 +02:00
m_healing = gain ;
2010-02-20 23:59:05 +01:00
}
// Do damage and triggers
else if ( m_damage > 0 )
{
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo ( caster , unitTarget , m_spellInfo -> Id , m_spellSchoolMask );
// Add bonuses and fill damageInfo struct
caster -> CalculateSpellDamageTaken ( & damageInfo , m_damage , m_spellInfo , m_attackType , target -> crit );
2011-04-29 20:47:02 +02:00
caster -> DealDamageMods ( damageInfo . target , damageInfo . damage , & damageInfo . absorb );
2010-02-20 23:59:05 +01:00
// Send log damage message to client
caster -> SendSpellNonMeleeDamageLog ( & damageInfo );
procEx |= createProcExtendMask ( & damageInfo , missInfo );
2010-10-08 19:17:49 +02:00
procVictim |= PROC_FLAG_TAKEN_DAMAGE ;
2010-02-20 23:59:05 +01:00
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if ( canEffectTrigger && missInfo != SPELL_MISS_REFLECT )
{
caster -> ProcDamageAndSpell ( unitTarget , procAttacker , procVictim , procEx , damageInfo . damage , m_attackType , m_spellInfo , m_triggeredByAuraSpell );
2010-12-19 05:15:47 +01:00
if ( caster -> GetTypeId () == TYPEID_PLAYER && ( m_spellInfo -> Attributes & SPELL_ATTR0_STOP_ATTACK_TARGET ) == 0 &&
2010-02-20 23:59:05 +01:00
( m_spellInfo -> DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo -> DmgClass == SPELL_DAMAGE_CLASS_RANGED ))
2010-03-11 20:51:31 +01:00
caster -> ToPlayer () -> CastItemCombatSpell ( unitTarget , m_attackType , procVictim , procEx );
2010-02-20 23:59:05 +01:00
}
caster -> DealSpellDamage ( & damageInfo , true );
// Haunt
2010-04-07 19:14:10 +02:00
if ( m_spellInfo -> SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo -> SpellFamilyFlags [ 1 ] & 0x40000 && m_spellAura && m_spellAura -> GetEffect ( 1 ))
2010-02-20 23:59:05 +01:00
{
2011-08-20 03:06:15 +07:00
AuraEffect * aurEff = m_spellAura -> GetEffect ( 1 );
2010-12-11 20:37:38 +06:00
aurEff -> SetAmount ( CalculatePctU ( aurEff -> GetAmount (), damageInfo . damage ));
2010-02-20 23:59:05 +01:00
}
2011-08-20 00:45:34 +02:00
m_damage = damageInfo . damage ;
2010-02-20 23:59:05 +01:00
}
// Passive spell hits/misses or active spells only misses (only triggers)
else
{
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo ( caster , unitTarget , m_spellInfo -> Id , m_spellSchoolMask );
procEx |= createProcExtendMask ( & damageInfo , missInfo );
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if ( canEffectTrigger && missInfo != SPELL_MISS_REFLECT )
caster -> ProcDamageAndSpell ( unit , procAttacker , procVictim , procEx , 0 , m_attackType , m_spellInfo , m_triggeredByAuraSpell );
// Failed Pickpocket, reveal rogue
2011-07-26 23:09:28 +02:00
if ( missInfo == SPELL_MISS_RESIST && m_spellInfo -> AttributesCu & SPELL_ATTR0_CU_PICKPOCKET && unitTarget -> GetTypeId () == TYPEID_UNIT )
2010-02-20 23:59:05 +01:00
{
m_caster -> RemoveAurasWithInterruptFlags ( AURA_INTERRUPT_FLAG_TALK );
2010-03-07 18:30:53 +01:00
if ( unitTarget -> ToCreature () -> IsAIEnabled )
unitTarget -> ToCreature () -> AI () -> AttackStart ( m_caster );
2010-02-20 23:59:05 +01:00
}
}
2011-07-26 23:09:28 +02:00
if ( missInfo != SPELL_MISS_EVADE && m_caster && ! m_caster -> IsFriendlyTo ( unit ) && ! m_spellInfo -> IsPositive ())
2010-02-20 23:59:05 +01:00
{
2010-12-19 05:15:47 +01:00
m_caster -> CombatStart ( unit , ! ( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO ));
2010-02-20 23:59:05 +01:00
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> AttributesCu & SPELL_ATTR0_CU_AURA_CC )
2010-04-07 19:14:10 +02:00
if ( ! unit -> IsStandState ())
2010-02-20 23:59:05 +01:00
unit -> SetStandState ( UNIT_STAND_STATE_STAND );
}
2010-04-07 19:14:10 +02:00
if ( spellHitTarget )
2010-02-20 23:59:05 +01:00
{
//AI functions
2010-04-07 19:14:10 +02:00
if ( spellHitTarget -> GetTypeId () == TYPEID_UNIT )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( spellHitTarget -> ToCreature () -> IsAIEnabled )
2010-03-07 18:30:53 +01:00
spellHitTarget -> ToCreature () -> AI () -> SpellHit ( m_caster , m_spellInfo );
2010-02-20 23:59:05 +01:00
// cast at creature (or GO) quest objectives update at successful cast finished (+channel finished)
2010-04-07 22:59:46 +02:00
// ignore pets or autorepeat/melee casts for speed (not exist quest for spells (hm...)
2010-04-07 19:14:10 +02:00
if ( m_originalCaster && m_originalCaster -> IsControlledByPlayer () && ! spellHitTarget -> ToCreature () -> isPet () && ! IsAutoRepeat () && ! IsNextMeleeSwingSpell () && ! IsChannelActive ())
if ( Player * p = m_originalCaster -> GetCharmerOrOwnerPlayerOrPlayerItself ())
2011-04-29 20:47:02 +02:00
p -> CastedCreatureOrGO ( spellHitTarget -> GetEntry (), spellHitTarget -> GetGUID (), m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
}
2011-08-20 03:06:15 +07:00
if ( m_caster -> GetTypeId () == TYPEID_UNIT && m_caster -> ToCreature () -> IsAIEnabled )
2010-03-07 18:30:53 +01:00
m_caster -> ToCreature () -> AI () -> SpellHitTarget ( spellHitTarget , m_spellInfo );
2010-02-20 23:59:05 +01:00
// Needs to be called after dealing damage/healing to not remove breaking on damage auras
2011-06-26 00:29:12 +02:00
DoTriggersOnSpellHit ( spellHitTarget , mask );
2010-02-20 23:59:05 +01:00
// if target is fallged for pvp also flag caster if a player
2011-08-20 03:06:15 +07:00
if ( unit -> IsPvP () && m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> UpdatePvP ( true );
2010-02-20 23:59:05 +01:00
2010-08-21 20:18:54 +02:00
CallScriptAfterHitHandlers ();
2010-02-20 23:59:05 +01:00
}
}
2011-09-15 14:08:17 +02:00
SpellMissInfo Spell :: DoSpellHitOnUnit ( Unit * unit , const uint32 effectMask , bool scaleAura )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( ! unit || ! effectMask )
2010-02-20 23:59:05 +01:00
return SPELL_MISS_EVADE ;
// Recheck immune (only for delayed spells)
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Speed && ( unit -> IsImmunedToDamage ( m_spellInfo ) || unit -> IsImmunedToSpell ( m_spellInfo )))
2010-02-20 23:59:05 +01:00
return SPELL_MISS_IMMUNE ;
2010-08-21 20:18:54 +02:00
PrepareScriptHitHandlers ();
CallScriptBeforeHitHandlers ();
2010-08-19 14:31:31 +02:00
2010-02-20 23:59:05 +01:00
if ( unit -> GetTypeId () == TYPEID_PLAYER )
{
2010-04-27 22:22:13 +02:00
unit -> ToPlayer () -> GetAchievementMgr (). StartTimedAchievement ( ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET , m_spellInfo -> Id );
2010-08-21 20:50:38 +02:00
unit -> ToPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET , m_spellInfo -> Id , 0 , m_caster );
2010-03-07 15:20:19 +01:00
unit -> ToPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 , m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
}
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-02-20 23:59:05 +01:00
{
2010-04-27 22:22:13 +02:00
m_caster -> ToPlayer () -> GetAchievementMgr (). StartTimedAchievement ( ACHIEVEMENT_TIMED_TYPE_SPELL_CASTER , m_spellInfo -> Id );
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 , m_spellInfo -> Id , 0 , unit );
2010-02-20 23:59:05 +01:00
}
2010-04-07 22:59:46 +02:00
if ( m_caster != unit )
2010-02-20 23:59:05 +01:00
{
// Recheck UNIT_FLAG_NON_ATTACKABLE for delayed spells
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Speed > 0.0f && unit -> HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_NON_ATTACKABLE ) && unit -> GetCharmerOrOwnerGUID () != m_caster -> GetGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_MISS_EVADE ;
2011-10-10 12:56:14 -04:00
if ( m_caster -> _IsValidAttackTarget ( unit , m_spellInfo ))
2010-02-20 23:59:05 +01:00
{
unit -> RemoveAurasWithInterruptFlags ( AURA_INTERRUPT_FLAG_HITBYSPELL );
//TODO: This is a hack. But we do not know what types of stealth should be interrupted by CC
2011-07-26 23:09:28 +02:00
if (( m_spellInfo -> AttributesCu & SPELL_ATTR0_CU_AURA_CC ) && unit -> IsControlledByPlayer ())
2010-02-20 23:59:05 +01:00
unit -> RemoveAurasByType ( SPELL_AURA_MOD_STEALTH );
}
2011-06-21 15:55:23 +02:00
else if ( m_caster -> IsFriendlyTo ( unit ))
2010-02-20 23:59:05 +01:00
{
// for delayed spells ignore negative spells (after duel end) for friendly targets
// TODO: this cause soul transfer bugged
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Speed > 0.0f && unit -> GetTypeId () == TYPEID_PLAYER && ! m_spellInfo -> IsPositive ())
2010-02-20 23:59:05 +01:00
return SPELL_MISS_EVADE ;
// assisting case, healing and resurrection
2010-12-17 13:43:24 +01:00
if ( unit -> HasUnitState ( UNIT_STAT_ATTACK_PLAYER ))
2010-02-20 23:59:05 +01:00
{
m_caster -> SetContestedPvP ();
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> UpdatePvP ( true );
2010-02-20 23:59:05 +01:00
}
2010-12-19 05:15:47 +01:00
if ( unit -> isInCombat () && ! ( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO ))
2010-02-20 23:59:05 +01:00
{
m_caster -> SetInCombatState ( unit -> GetCombatTimer () > 0 , unit );
2010-03-09 11:11:10 +01:00
unit -> getHostileRefManager (). threatAssist ( m_caster , 0.0f );
2010-02-20 23:59:05 +01:00
}
}
}
// Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add
2011-04-29 20:47:02 +02:00
m_diminishGroup = GetDiminishingReturnsGroupForSpell ( m_spellInfo , m_triggeredByAuraSpell );
2010-04-19 17:03:10 +02:00
if ( m_diminishGroup )
2010-02-20 23:59:05 +01:00
{
m_diminishLevel = unit -> GetDiminishing ( m_diminishGroup );
DiminishingReturnsType type = GetDiminishingReturnsGroupType ( m_diminishGroup );
// Increase Diminishing on unit, current informations for actually casts will use values above
2011-04-20 15:33:40 +03:00
if (( type == DRTYPE_PLAYER && unit -> GetCharmerOrOwnerPlayerOrPlayerItself ()) || type == DRTYPE_ALL )
2010-02-20 23:59:05 +01:00
unit -> IncrDiminishing ( m_diminishGroup );
}
uint8 aura_effmask = 0 ;
2010-09-28 08:41:24 +03:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2011-08-20 03:06:15 +07:00
if ( effectMask & ( 1 << i ) && m_spellInfo -> Effects [ i ]. IsUnitOwnedAuraEffect ())
2011-05-22 16:01:53 -07:00
aura_effmask |= 1 << i ;
2010-02-20 23:59:05 +01:00
if ( aura_effmask )
{
// Select rank for aura with level requirements only in specific cases
// Unit has to be target only of aura effect, both caster and target have to be players, target has to be other than unit target
2011-07-26 23:09:28 +02:00
SpellInfo const * aurSpellInfo = m_spellInfo ;
2010-02-20 23:59:05 +01:00
int32 basePoints [ 3 ];
if ( scaleAura )
{
2011-07-26 23:09:28 +02:00
aurSpellInfo = m_spellInfo -> GetAuraRankForLevel ( unitTarget -> getLevel ());
2010-08-21 20:18:54 +02:00
ASSERT ( aurSpellInfo );
2010-02-20 23:59:05 +01:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
{
2011-07-26 23:09:28 +02:00
basePoints [ i ] = aurSpellInfo -> Effects [ i ]. BasePoints ;
if ( m_spellInfo -> Effects [ i ]. Effect != aurSpellInfo -> Effects [ i ]. Effect )
2010-02-20 23:59:05 +01:00
{
aurSpellInfo = m_spellInfo ;
break ;
}
}
}
2010-04-07 19:14:10 +02:00
if ( m_originalCaster )
2010-02-20 23:59:05 +01:00
{
2011-08-01 12:05:30 +02:00
bool refresh = false ;
2011-06-07 12:47:32 +02:00
m_spellAura = Aura :: TryRefreshStackOrCreate ( aurSpellInfo , effectMask , unit ,
2011-08-01 15:58:51 +02:00
m_originalCaster , ( aurSpellInfo == m_spellInfo ) ? & m_spellValue -> EffectBasePoints [ 0 ] : & basePoints [ 0 ], m_CastItem , 0 , & refresh );
2010-04-19 17:03:10 +02:00
if ( m_spellAura )
2010-02-20 23:59:05 +01:00
{
2011-05-21 21:36:37 +02:00
// Set aura stack amount to desired value
2011-05-22 06:12:25 +07:00
if ( m_spellValue -> AuraStackAmount > 1 )
2011-08-01 12:05:30 +02:00
{
if ( ! refresh )
m_spellAura -> SetStackAmount ( m_spellValue -> AuraStackAmount );
else
m_spellAura -> ModStackAmount ( m_spellValue -> AuraStackAmount );
}
2011-05-21 21:36:37 +02:00
2010-02-20 23:59:05 +01:00
// Now Reduce spell duration using data received at spell hit
2011-06-09 17:04:52 +02:00
int32 duration = m_spellAura -> GetMaxDuration ();
2011-04-29 20:47:02 +02:00
int32 limitduration = GetDiminishingReturnsLimitDuration ( m_diminishGroup , aurSpellInfo );
float diminishMod = unit -> ApplyDiminishingToDuration ( m_diminishGroup , duration , m_originalCaster , m_diminishLevel , limitduration );
2010-07-16 14:23:03 +02:00
// unit is immune to aura if it was diminished to 0 duration
if ( diminishMod == 0.0f )
{
m_spellAura -> Remove ();
2011-08-17 04:09:12 +07:00
bool found = false ;
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
if ( effectMask & ( 1 << i ) && m_spellInfo -> Effects [ i ]. Effect != SPELL_EFFECT_APPLY_AURA )
found = true ;
if ( ! found )
return SPELL_MISS_IMMUNE ;
2010-07-16 14:23:03 +02:00
}
2011-08-17 04:09:12 +07:00
else
{
(( UnitAura * ) m_spellAura ) -> SetDiminishGroup ( m_diminishGroup );
2010-07-16 14:23:03 +02:00
2011-08-17 04:09:12 +07:00
bool positive = m_spellAura -> GetSpellInfo () -> IsPositive ();
2011-08-30 13:46:36 +02:00
if ( AuraApplication * aurApp = m_spellAura -> GetApplicationOfTarget ( m_originalCaster -> GetGUID ()))
2011-08-17 04:09:12 +07:00
positive = aurApp -> IsPositive ();
2010-02-20 23:59:05 +01:00
2011-08-17 04:09:12 +07:00
duration = m_originalCaster -> ModSpellDuration ( aurSpellInfo , unit , duration , positive );
2010-02-20 23:59:05 +01:00
2011-08-17 04:09:12 +07:00
// Haste modifies duration of channeled spells
if ( m_spellInfo -> IsChanneled ())
{
if ( m_spellInfo -> AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION )
m_originalCaster -> ModSpellCastTime ( aurSpellInfo , duration , this );
}
// and duration of auras affected by SPELL_AURA_PERIODIC_HASTE
else if ( m_originalCaster -> HasAuraTypeWithAffectMask ( SPELL_AURA_PERIODIC_HASTE , aurSpellInfo ) || m_spellInfo -> AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION )
duration = int32 ( duration * m_originalCaster -> GetFloatValue ( UNIT_MOD_CAST_SPEED ));
2010-08-01 01:22:13 +02:00
2011-08-17 04:09:12 +07:00
if ( duration != m_spellAura -> GetMaxDuration ())
{
m_spellAura -> SetMaxDuration ( duration );
m_spellAura -> SetDuration ( duration );
}
m_spellAura -> _RegisterForTargets ();
2010-02-20 23:59:05 +01:00
}
}
}
}
2010-09-28 08:41:24 +03:00
for ( uint32 effectNumber = 0 ; effectNumber < MAX_SPELL_EFFECTS ; ++ effectNumber )
2011-05-22 16:01:53 -07:00
if ( effectMask & ( 1 << effectNumber ))
2011-09-25 13:29:17 +02:00
HandleEffects ( unit , NULL , NULL , effectNumber , SPELL_EFFECT_HANDLE_HIT_TARGET );
2010-02-20 23:59:05 +01:00
return SPELL_MISS_NONE ;
}
2011-09-15 14:08:17 +02:00
void Spell :: DoTriggersOnSpellHit ( Unit * unit , uint8 effMask )
2010-02-20 23:59:05 +01:00
{
// Apply additional spell effects to target
2011-06-26 00:29:12 +02:00
// TODO: move this code to scripts
2010-02-20 23:59:05 +01:00
if ( m_preCastSpell )
{
2010-03-26 22:21:33 +01:00
// Paladin immunity shields
if ( m_preCastSpell == 61988 )
2010-02-20 23:59:05 +01:00
{
2010-03-26 22:21:33 +01:00
// Cast Forbearance
m_caster -> CastSpell ( unit , 25771 , true );
2010-02-20 23:59:05 +01:00
// Cast Avenging Wrath Marker
2010-03-26 22:21:33 +01:00
unit -> CastSpell ( unit , 61987 , true );
2010-02-20 23:59:05 +01:00
}
2010-03-26 22:21:33 +01:00
// Avenging Wrath
if ( m_preCastSpell == 61987 )
// Cast the serverside immunity shield marker
m_caster -> CastSpell ( unit , 61988 , true );
2011-07-26 23:09:28 +02:00
if ( sSpellMgr -> GetSpellInfo ( m_preCastSpell ))
2010-03-25 17:09:05 +01:00
// Blizz seems to just apply aura without bothering to cast
m_caster -> AddAura ( m_preCastSpell , unit );
2010-02-20 23:59:05 +01:00
}
2011-06-26 00:29:12 +02:00
// handle SPELL_AURA_ADD_TARGET_TRIGGER auras
// this is executed after spell proc spells on target hit
// spells are triggered for each hit spell target
// info confirmed with retail sniffs of permafrost and shadow weaving
2011-10-19 22:08:54 +02:00
if ( ! m_hitTriggerSpells . empty ())
2010-02-20 23:59:05 +01:00
{
2011-06-26 00:29:12 +02:00
int _duration = 0 ;
for ( HitTriggerSpells :: const_iterator i = m_hitTriggerSpells . begin (); i != m_hitTriggerSpells . end (); ++ i )
2010-02-20 23:59:05 +01:00
{
2011-10-19 22:08:54 +02:00
if ( CanExecuteTriggersOnHit ( effMask , i -> first ) && roll_chance_i ( i -> second ))
2010-02-20 23:59:05 +01:00
{
m_caster -> CastSpell ( unit , i -> first , true );
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura" , m_spellInfo -> Id , i -> first -> Id );
2011-06-26 00:29:12 +02:00
// SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration
// set duration of current aura to the triggered spell
2011-07-26 23:09:28 +02:00
if ( i -> first -> GetDuration () == - 1 )
2010-02-20 23:59:05 +01:00
{
2011-09-15 14:08:17 +02:00
if ( Aura * triggeredAur = unit -> GetAura ( i -> first -> Id , m_caster -> GetGUID ()))
2010-02-20 23:59:05 +01:00
{
2011-06-26 00:29:12 +02:00
// get duration from aura-only once
if ( ! _duration )
{
2011-09-15 14:08:17 +02:00
Aura * aur = unit -> GetAura ( m_spellInfo -> Id , m_caster -> GetGUID ());
2011-06-26 00:29:12 +02:00
_duration = aur ? aur -> GetDuration () : - 1 ;
}
triggeredAur -> SetDuration ( _duration );
2010-02-20 23:59:05 +01:00
}
}
}
}
}
2011-06-26 00:29:12 +02:00
// trigger linked auras remove/apply
// TODO: remove/cleanup this, as this table is not documented and people are doing stupid things with it
2011-07-26 23:09:28 +02:00
if ( std :: vector < int32 > const * spellTriggered = sSpellMgr -> GetSpellLinked ( m_spellInfo -> Id + SPELL_LINK_HIT ))
for ( std :: vector < int32 >:: const_iterator i = spellTriggered -> begin (); i != spellTriggered -> end (); ++ i )
if ( * i < 0 )
unit -> RemoveAurasDueToSpell ( - ( * i ));
else
unit -> CastSpell ( unit , * i , true , 0 , 0 , m_caster -> GetGUID ());
2010-02-20 23:59:05 +01:00
}
2011-09-15 14:08:17 +02:00
void Spell :: DoAllEffectOnTarget ( GOTargetInfo * target )
2010-02-20 23:59:05 +01:00
{
if ( target -> processed ) // Check target
return ;
target -> processed = true ; // Target checked in apply effects procedure
uint32 effectMask = target -> effectMask ;
2010-04-07 19:14:10 +02:00
if ( ! effectMask )
2010-02-20 23:59:05 +01:00
return ;
GameObject * go = m_caster -> GetMap () -> GetGameObject ( target -> targetGUID );
2010-04-07 19:14:10 +02:00
if ( ! go )
2010-02-20 23:59:05 +01:00
return ;
2010-08-21 20:18:54 +02:00
PrepareScriptHitHandlers ();
CallScriptBeforeHitHandlers ();
2010-08-19 14:31:31 +02:00
2010-09-28 08:41:24 +03:00
for ( uint32 effectNumber = 0 ; effectNumber < MAX_SPELL_EFFECTS ; ++ effectNumber )
2010-02-20 23:59:05 +01:00
if ( effectMask & ( 1 << effectNumber ))
2011-09-25 13:29:17 +02:00
HandleEffects ( NULL , NULL , go , effectNumber , SPELL_EFFECT_HANDLE_HIT_TARGET );
2010-02-20 23:59:05 +01:00
2010-08-21 20:18:54 +02:00
CallScriptOnHitHandlers ();
2010-02-20 23:59:05 +01:00
// cast at creature (or GO) quest objectives update at successful cast finished (+channel finished)
2010-04-07 22:59:46 +02:00
// ignore autorepeat/melee casts for speed (not exist quest for spells (hm...)
if ( m_originalCaster && m_originalCaster -> IsControlledByPlayer () && ! IsAutoRepeat () && ! IsNextMeleeSwingSpell () && ! IsChannelActive ())
if ( Player * p = m_originalCaster -> GetCharmerOrOwnerPlayerOrPlayerItself ())
2011-04-29 20:47:02 +02:00
p -> CastedCreatureOrGO ( go -> GetEntry (), go -> GetGUID (), m_spellInfo -> Id );
2010-08-21 20:18:54 +02:00
CallScriptAfterHitHandlers ();
2010-02-20 23:59:05 +01:00
}
2011-09-15 14:08:17 +02:00
void Spell :: DoAllEffectOnTarget ( ItemTargetInfo * target )
2010-02-20 23:59:05 +01:00
{
uint32 effectMask = target -> effectMask ;
2010-04-07 19:14:10 +02:00
if ( ! target -> item || ! effectMask )
2010-02-20 23:59:05 +01:00
return ;
2010-08-21 20:18:54 +02:00
PrepareScriptHitHandlers ();
CallScriptBeforeHitHandlers ();
2010-08-19 14:31:31 +02:00
2010-09-28 08:41:24 +03:00
for ( uint32 effectNumber = 0 ; effectNumber < MAX_SPELL_EFFECTS ; ++ effectNumber )
2010-02-20 23:59:05 +01:00
if ( effectMask & ( 1 << effectNumber ))
2011-09-25 13:29:17 +02:00
HandleEffects ( NULL , target -> item , NULL , effectNumber , SPELL_EFFECT_HANDLE_HIT_TARGET );
2010-08-21 20:18:54 +02:00
CallScriptOnHitHandlers ();
CallScriptAfterHitHandlers ();
2010-02-20 23:59:05 +01:00
}
bool Spell :: UpdateChanneledTargetList ()
{
// Not need check return true
2010-08-30 17:32:51 +02:00
if ( m_channelTargetEffectMask == 0 )
2010-02-20 23:59:05 +01:00
return true ;
2010-08-30 17:32:51 +02:00
uint8 channelTargetEffectMask = m_channelTargetEffectMask ;
uint8 channelAuraMask = 0 ;
2010-02-20 23:59:05 +01:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ i ]. Effect == SPELL_EFFECT_APPLY_AURA )
2010-08-30 17:32:51 +02:00
channelAuraMask |= 1 << i ;
2010-02-20 23:59:05 +01:00
2010-08-30 17:32:51 +02:00
channelAuraMask &= channelTargetEffectMask ;
2010-02-20 23:59:05 +01:00
2010-04-19 09:26:37 +02:00
float range = 0 ;
2010-08-30 17:32:51 +02:00
if ( channelAuraMask )
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
range = m_spellInfo -> GetMaxRange ( m_spellInfo -> IsPositive ());
2011-06-11 22:35:29 +02:00
if ( Player * modOwner = m_caster -> GetSpellModOwner ())
2010-02-20 23:59:05 +01:00
modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_RANGE , range , this );
}
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
{
2010-08-30 17:32:51 +02:00
if ( ihit -> missCondition == SPELL_MISS_NONE && ( channelTargetEffectMask & ihit -> effectMask ))
2010-02-20 23:59:05 +01:00
{
2011-09-15 14:08:17 +02:00
Unit * unit = m_caster -> GetGUID () == ihit -> targetGUID ? m_caster : ObjectAccessor :: GetUnit ( * m_caster , ihit -> targetGUID );
2010-02-20 23:59:05 +01:00
2010-08-30 17:32:51 +02:00
if ( ! unit )
continue ;
if ( IsValidDeadOrAliveTarget ( unit ))
2010-02-20 23:59:05 +01:00
{
2010-08-30 17:32:51 +02:00
if ( channelAuraMask & ihit -> effectMask )
2011-07-27 11:00:39 +02:00
{
2010-04-07 19:14:10 +02:00
if ( AuraApplication * aurApp = unit -> GetAuraApplication ( m_spellInfo -> Id , m_originalCasterGUID ))
2010-02-20 23:59:05 +01:00
{
2011-04-29 20:47:02 +02:00
if ( m_caster != unit && ! m_caster -> IsWithinDistInMap ( unit , range ))
2010-02-20 23:59:05 +01:00
{
ihit -> effectMask &= ~ aurApp -> GetEffectMask ();
unit -> RemoveAura ( aurApp );
continue ;
}
}
else // aura is dispelled
continue ;
2011-07-27 11:00:39 +02:00
}
2010-02-20 23:59:05 +01:00
2010-08-30 17:32:51 +02:00
channelTargetEffectMask &= ~ ihit -> effectMask ; // remove from need alive mask effect that have alive target
2010-02-20 23:59:05 +01:00
}
}
}
// is all effects from m_needAliveTargetMask have alive targets
2010-08-30 17:32:51 +02:00
return channelTargetEffectMask == 0 ;
2010-02-20 23:59:05 +01:00
}
// Helper for Chain Healing
// Spell target first
// Raidmates then descending by injury suffered (MaxHealth - Health)
// Other players/mobs then descending by injury suffered (MaxHealth - Health)
struct ChainHealingOrder : public std :: binary_function < const Unit * , const Unit * , bool >
{
const Unit * MainTarget ;
ChainHealingOrder ( Unit const * Target ) : MainTarget ( Target ) {};
// functor for operator ">"
bool operator ()( Unit const * _Left , Unit const * _Right ) const
{
return ( ChainHealingHash ( _Left ) < ChainHealingHash ( _Right ));
}
int32 ChainHealingHash ( Unit const * Target ) const
{
2011-05-22 16:01:53 -07:00
if ( Target -> GetTypeId () == TYPEID_PLAYER && MainTarget -> GetTypeId () == TYPEID_PLAYER && Target -> ToPlayer () -> IsInSameRaidWith ( MainTarget -> ToPlayer ()))
2010-02-20 23:59:05 +01:00
{
2010-08-26 01:20:57 +06:00
if ( Target -> IsFullHealth ())
2010-02-20 23:59:05 +01:00
return 40000 ;
else
return 20000 - Target -> GetMaxHealth () + Target -> GetHealth ();
}
else
return 40000 - Target -> GetMaxHealth () + Target -> GetHealth ();
}
};
void Spell :: SearchChainTarget ( std :: list < Unit *> & TagUnitMap , float max_range , uint32 num , SpellTargets TargetType )
{
2011-09-15 14:08:17 +02:00
Unit * cur = m_targets . GetUnitTarget ();
2010-04-07 19:14:10 +02:00
if ( ! cur )
2010-02-20 23:59:05 +01:00
return ;
//FIXME: This very like horrible hack and wrong for most spells
2010-04-07 19:14:10 +02:00
if ( m_spellInfo -> DmgClass != SPELL_DAMAGE_CLASS_MELEE )
2010-02-20 23:59:05 +01:00
max_range += num * CHAIN_SPELL_JUMP_RADIUS ;
std :: list < Unit *> tempUnitMap ;
2010-04-07 19:14:10 +02:00
if ( TargetType == SPELL_TARGETS_CHAINHEAL )
2010-02-20 23:59:05 +01:00
{
SearchAreaTarget ( tempUnitMap , max_range , PUSH_CHAIN , SPELL_TARGETS_ALLY );
tempUnitMap . sort ( ChainHealingOrder ( m_caster ));
}
else
SearchAreaTarget ( tempUnitMap , max_range , PUSH_CHAIN , TargetType );
tempUnitMap . remove ( cur );
2010-04-07 19:13:19 +02:00
while ( num )
2010-02-20 23:59:05 +01:00
{
TagUnitMap . push_back ( cur );
-- num ;
2010-04-07 19:14:10 +02:00
if ( tempUnitMap . empty ())
2010-02-20 23:59:05 +01:00
break ;
std :: list < Unit *>:: iterator next ;
2010-04-07 19:14:10 +02:00
if ( TargetType == SPELL_TARGETS_CHAINHEAL )
2010-02-20 23:59:05 +01:00
{
next = tempUnitMap . begin ();
2011-05-22 16:01:53 -07:00
while ( cur -> GetDistance ( * next ) > CHAIN_SPELL_JUMP_RADIUS || ! cur -> IsWithinLOSInMap ( * next ))
2010-02-20 23:59:05 +01:00
{
++ next ;
2010-04-07 19:14:10 +02:00
if ( next == tempUnitMap . end ())
2010-02-20 23:59:05 +01:00
return ;
}
}
else
{
2010-05-30 04:23:27 +02:00
tempUnitMap . sort ( Trinity :: ObjectDistanceOrderPred ( cur ));
2010-02-20 23:59:05 +01:00
next = tempUnitMap . begin ();
2011-01-15 19:40:06 +01:00
if ( cur -> GetDistance ( * next ) > CHAIN_SPELL_JUMP_RADIUS ) // Don't search beyond the max jump radius
2010-02-20 23:59:05 +01:00
break ;
2011-01-15 19:40:06 +01:00
// Check if (*next) is a valid chain target. If not, don't add to TagUnitMap, and repeat loop.
2011-09-29 12:43:05 +02:00
// If you want to add any conditions to exclude a target from TagUnitMap, add condition in this while () loop.
2011-01-26 01:03:35 +01:00
while (( m_spellInfo -> DmgClass == SPELL_DAMAGE_CLASS_MELEE
2010-08-21 20:08:47 +02:00
&& ! m_caster -> isInFrontInMap ( * next , max_range ))
2010-11-13 17:18:09 +01:00
|| ! m_caster -> canSeeOrDetect ( * next )
2011-01-15 19:40:06 +01:00
|| ! cur -> IsWithinLOSInMap ( * next )
2011-10-07 23:33:08 +03:00
|| ( * next ) -> GetCreatureType () == CREATURE_TYPE_CRITTER
2011-08-16 16:05:24 +02:00
|| (( GetSpellInfo () -> AttributesEx6 & SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED ) && ! ( * next ) -> CanFreeMove ()))
2010-02-20 23:59:05 +01:00
{
++ next ;
2011-01-15 19:40:06 +01:00
if ( next == tempUnitMap . end () || cur -> GetDistance ( * next ) > CHAIN_SPELL_JUMP_RADIUS ) // Don't search beyond the max jump radius
2010-02-20 23:59:05 +01:00
return ;
}
}
cur = * next ;
tempUnitMap . erase ( next );
}
}
void Spell :: SearchAreaTarget ( std :: list < Unit *> & TagUnitMap , float radius , SpellNotifyPushType type , SpellTargets TargetType , uint32 entry )
{
2010-07-30 01:51:33 +02:00
if ( TargetType == SPELL_TARGETS_GO )
return ;
2010-08-08 19:45:53 +02:00
2011-06-23 13:28:52 +02:00
Position const * pos ;
2011-09-05 14:01:50 +02:00
switch ( type )
2010-02-20 23:59:05 +01:00
{
case PUSH_DST_CENTER :
CheckDst ();
2011-06-23 13:28:52 +02:00
pos = m_targets . GetDst ();
2010-02-20 23:59:05 +01:00
break ;
case PUSH_SRC_CENTER :
CheckSrc ();
2011-06-23 13:28:52 +02:00
pos = m_targets . GetSrc ();
2010-02-20 23:59:05 +01:00
break ;
case PUSH_CHAIN :
{
2011-06-23 13:28:52 +02:00
Unit * target = m_targets . GetUnitTarget ();
2010-04-07 19:14:10 +02:00
if ( ! target )
2010-02-20 23:59:05 +01:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "SPELL: cannot find unit target for spell ID %u \n " , m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
return ;
}
pos = target ;
break ;
}
default :
pos = m_caster ;
break ;
}
2011-04-06 17:00:05 +03:00
Trinity :: SpellNotifierCreatureAndPlayer notifier ( m_caster , TagUnitMap , radius , type , TargetType , pos , entry , m_spellInfo );
2011-08-16 16:05:24 +02:00
if (( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS ) || ( TargetType == SPELL_TARGETS_ENTRY && ! entry ))
2010-02-20 23:59:05 +01:00
m_caster -> GetMap () -> VisitWorld ( pos -> m_positionX , pos -> m_positionY , radius , notifier );
else
m_caster -> GetMap () -> VisitAll ( pos -> m_positionX , pos -> m_positionY , radius , notifier );
}
2010-07-30 01:51:33 +02:00
void Spell :: SearchGOAreaTarget ( std :: list < GameObject *> & TagGOMap , float radius , SpellNotifyPushType type , SpellTargets TargetType , uint32 entry )
{
if ( TargetType != SPELL_TARGETS_GO )
return ;
2011-06-23 13:28:52 +02:00
Position const * pos ;
2010-07-30 01:51:33 +02:00
switch ( type )
{
case PUSH_DST_CENTER :
CheckDst ();
2011-06-23 13:28:52 +02:00
pos = m_targets . GetDst ();
2010-07-30 01:51:33 +02:00
break ;
case PUSH_SRC_CENTER :
CheckSrc ();
2011-06-23 13:28:52 +02:00
pos = m_targets . GetSrc ();
2010-07-30 01:51:33 +02:00
break ;
default :
pos = m_caster ;
break ;
}
2010-12-22 23:04:05 +01:00
Trinity :: GameObjectInRangeCheck check ( pos -> m_positionX , pos -> m_positionY , pos -> m_positionZ , radius , entry );
2010-07-30 01:51:33 +02:00
Trinity :: GameObjectListSearcher < Trinity :: GameObjectInRangeCheck > searcher ( m_caster , TagGOMap , check );
m_caster -> GetMap () -> VisitGrid ( pos -> m_positionX , pos -> m_positionY , radius , searcher );
}
2010-10-16 16:34:21 +02:00
WorldObject * Spell :: SearchNearbyTarget ( float range , SpellTargets TargetType , SpellEffIndex effIndex )
2010-02-20 23:59:05 +01:00
{
2011-09-05 14:01:50 +02:00
switch ( TargetType )
2010-02-20 23:59:05 +01:00
{
case SPELL_TARGETS_ENTRY :
{
2010-12-22 21:25:23 +01:00
ConditionList conditions = sConditionMgr -> GetConditionsForNotGroupedEntry ( CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET , m_spellInfo -> Id );
2010-06-04 23:24:48 +02:00
if ( conditions . empty ())
2010-02-20 23:59:05 +01:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell (ID: %u) (caster Entry: %u) does not have record in `conditions` for spell script target (ConditionSourceType 13)" , m_spellInfo -> Id , m_caster -> GetEntry ());
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> IsPositive ())
2010-10-16 16:34:21 +02:00
return SearchNearbyTarget ( range , SPELL_TARGETS_ALLY , effIndex );
2010-02-20 23:59:05 +01:00
else
2010-10-16 16:34:21 +02:00
return SearchNearbyTarget ( range , SPELL_TARGETS_ENEMY , effIndex );
2010-02-20 23:59:05 +01:00
}
Creature * creatureScriptTarget = NULL ;
GameObject * goScriptTarget = NULL ;
2010-06-04 23:24:48 +02:00
for ( ConditionList :: const_iterator i_spellST = conditions . begin (); i_spellST != conditions . end (); ++ i_spellST )
2010-02-20 23:59:05 +01:00
{
2010-06-04 23:24:48 +02:00
if (( * i_spellST ) -> mConditionType != CONDITION_SPELL_SCRIPT_TARGET )
continue ;
2010-10-16 16:34:21 +02:00
if (( * i_spellST ) -> mConditionValue3 && ! (( * i_spellST ) -> mConditionValue3 & ( 1 << uint32 ( effIndex ))))
continue ;
2011-09-05 14:01:50 +02:00
switch (( * i_spellST ) -> mConditionValue1 )
2010-02-20 23:59:05 +01:00
{
case SPELL_TARGET_TYPE_CONTROLLED :
for ( Unit :: ControlList :: iterator itr = m_caster -> m_Controlled . begin (); itr != m_caster -> m_Controlled . end (); ++ itr )
2010-06-04 23:24:48 +02:00
if (( * itr ) -> GetEntry () == ( * i_spellST ) -> mConditionValue2 && ( * itr ) -> IsWithinDistInMap ( m_caster , range ))
2010-02-20 23:59:05 +01:00
{
goScriptTarget = NULL ;
2010-03-11 20:51:31 +01:00
creatureScriptTarget = ( * itr ) -> ToCreature ();
2010-02-20 23:59:05 +01:00
range = m_caster -> GetDistance ( creatureScriptTarget );
}
break ;
case SPELL_TARGET_TYPE_GAMEOBJECT :
2010-06-04 23:24:48 +02:00
if (( * i_spellST ) -> mConditionValue2 )
2010-02-20 23:59:05 +01:00
{
2011-09-15 14:08:17 +02:00
if ( GameObject * go = m_caster -> FindNearestGameObject (( * i_spellST ) -> mConditionValue2 , range ))
2010-02-20 23:59:05 +01:00
{
// remember found target and range, next attempt will find more near target with another entry
goScriptTarget = go ;
creatureScriptTarget = NULL ;
range = m_caster -> GetDistance ( goScriptTarget );
}
}
2010-04-07 22:59:46 +02:00
else if ( focusObject ) //Focus Object
2010-02-20 23:59:05 +01:00
{
float frange = m_caster -> GetDistance ( focusObject );
2010-04-07 19:14:10 +02:00
if ( range >= frange )
2010-02-20 23:59:05 +01:00
{
creatureScriptTarget = NULL ;
goScriptTarget = focusObject ;
range = frange ;
}
}
break ;
case SPELL_TARGET_TYPE_CREATURE :
2011-06-23 13:28:52 +02:00
if ( m_targets . GetUnitTarget () && m_targets . GetUnitTarget () -> GetEntry () == ( * i_spellST ) -> mConditionValue2 )
return m_targets . GetUnitTarget ();
2010-02-20 23:59:05 +01:00
case SPELL_TARGET_TYPE_DEAD :
default :
2011-09-15 14:08:17 +02:00
if ( Creature * cre = m_caster -> FindNearestCreature (( * i_spellST ) -> mConditionValue2 , range , ( * i_spellST ) -> mConditionValue1 != SPELL_TARGET_TYPE_DEAD ))
2010-02-20 23:59:05 +01:00
{
creatureScriptTarget = cre ;
goScriptTarget = NULL ;
range = m_caster -> GetDistance ( creatureScriptTarget );
}
break ;
}
}
2010-04-07 19:14:10 +02:00
if ( creatureScriptTarget )
2010-02-20 23:59:05 +01:00
return creatureScriptTarget ;
else
return goScriptTarget ;
}
default :
case SPELL_TARGETS_ENEMY :
{
2011-06-12 01:47:45 +02:00
Unit * target = NULL ;
2010-02-20 23:59:05 +01:00
Trinity :: AnyUnfriendlyUnitInObjectRangeCheck u_check ( m_caster , m_caster , range );
Trinity :: UnitLastSearcher < Trinity :: AnyUnfriendlyUnitInObjectRangeCheck > searcher ( m_caster , target , u_check );
m_caster -> VisitNearbyObject ( range , searcher );
return target ;
}
case SPELL_TARGETS_ALLY :
{
2011-06-12 01:47:45 +02:00
Unit * target = NULL ;
2010-02-20 23:59:05 +01:00
Trinity :: AnyFriendlyUnitInObjectRangeCheck u_check ( m_caster , m_caster , range );
Trinity :: UnitLastSearcher < Trinity :: AnyFriendlyUnitInObjectRangeCheck > searcher ( m_caster , target , u_check );
m_caster -> VisitNearbyObject ( range , searcher );
return target ;
}
}
}
2011-09-16 11:40:53 +02:00
uint32 Spell :: SelectEffectTargets ( uint32 i , SpellImplicitTargetInfo const & cur )
2010-02-20 23:59:05 +01:00
{
SpellNotifyPushType pushType = PUSH_NONE ;
2011-09-15 14:08:17 +02:00
Player * modOwner = NULL ;
2010-04-07 19:14:10 +02:00
if ( m_originalCaster )
2010-02-20 23:59:05 +01:00
modOwner = m_originalCaster -> GetSpellModOwner ();
2011-09-16 11:40:53 +02:00
uint32 effectMask = 1 << i ;
// ENTRY targets may have different selection lists, skip those for now until we can compare lists easily and quickly
if ( GetSpellInfo () -> Effects [ i ]. TargetA . GetSelectionCheckType () != TARGET_SELECT_CHECK_ENTRY &&
GetSpellInfo () -> Effects [ i ]. TargetB . GetSelectionCheckType () != TARGET_SELECT_CHECK_ENTRY )
for ( uint32 j = i + 1 ; j < MAX_SPELL_EFFECTS ; ++ j )
if ( GetSpellInfo () -> Effects [ i ]. TargetA . GetTarget () == GetSpellInfo () -> Effects [ j ]. TargetA . GetTarget () &&
GetSpellInfo () -> Effects [ i ]. TargetB . GetTarget () == GetSpellInfo () -> Effects [ j ]. TargetB . GetTarget () &&
GetSpellInfo () -> Effects [ i ]. CalcRadius ( m_caster ) == GetSpellInfo () -> Effects [ j ]. CalcRadius ( m_caster ))
effectMask |= 1 << j ;
2011-09-05 14:01:50 +02:00
switch ( cur . GetType ())
2010-02-20 23:59:05 +01:00
{
case TARGET_TYPE_UNIT_CASTER :
{
2011-09-05 14:01:50 +02:00
switch ( cur . GetTarget ())
2010-02-20 23:59:05 +01:00
{
case TARGET_UNIT_CASTER :
2011-09-16 11:40:53 +02:00
AddUnitTarget ( m_caster , effectMask , false );
2010-02-20 23:59:05 +01:00
break ;
2011-08-16 19:44:18 +02:00
case TARGET_DEST_CASTER_FISHING :
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
float min_dis = m_spellInfo -> GetMinRange ( true );
float max_dis = m_spellInfo -> GetMaxRange ( true );
2010-08-22 12:39:39 -07:00
float dis = ( float ) rand_norm () * ( max_dis - min_dis ) + min_dis ;
2011-08-27 14:34:56 +00:00
float x , y , z , angle ;
angle = ( float ) rand_norm () * static_cast < float > ( M_PI * 70.0f / 180.0f ) - static_cast < float > ( M_PI * 35.0f / 180.0f );
m_caster -> GetClosePoint ( x , y , z , DEFAULT_WORLD_OBJECT_SIZE , dis , angle );
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( x , y , z , m_caster -> GetOrientation ());
2010-02-20 23:59:05 +01:00
break ;
}
case TARGET_UNIT_MASTER :
2010-04-07 19:14:10 +02:00
if ( Unit * owner = m_caster -> GetCharmerOrOwner ())
2011-09-16 11:40:53 +02:00
AddUnitTarget ( owner , effectMask );
2010-02-20 23:59:05 +01:00
break ;
case TARGET_UNIT_PET :
2010-04-07 19:14:10 +02:00
if ( Guardian * pet = m_caster -> GetGuardianPet ())
2011-09-16 11:40:53 +02:00
AddUnitTarget ( pet , effectMask );
2010-02-20 23:59:05 +01:00
break ;
2010-08-17 20:19:06 +02:00
case TARGET_UNIT_SUMMONER :
if ( m_caster -> isSummon ())
if ( Unit * unit = m_caster -> ToTempSummon () -> GetSummoner ())
2011-09-16 11:40:53 +02:00
AddUnitTarget ( unit , effectMask );
2010-08-17 20:19:06 +02:00
break ;
2011-08-16 19:44:18 +02:00
case TARGET_UNIT_CASTER_AREA_PARTY :
case TARGET_UNIT_CASTER_AREA_RAID :
2010-02-20 23:59:05 +01:00
pushType = PUSH_CASTER_CENTER ;
break ;
case TARGET_UNIT_VEHICLE :
2011-09-15 14:08:17 +02:00
if ( Unit * vehicle = m_caster -> GetVehicleBase ())
2011-09-16 11:40:53 +02:00
AddUnitTarget ( vehicle , effectMask );
2010-02-20 23:59:05 +01:00
break ;
case TARGET_UNIT_PASSENGER_0 :
case TARGET_UNIT_PASSENGER_1 :
case TARGET_UNIT_PASSENGER_2 :
case TARGET_UNIT_PASSENGER_3 :
case TARGET_UNIT_PASSENGER_4 :
case TARGET_UNIT_PASSENGER_5 :
case TARGET_UNIT_PASSENGER_6 :
case TARGET_UNIT_PASSENGER_7 :
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () == TYPEID_UNIT && m_caster -> ToCreature () -> IsVehicle ())
2011-09-15 14:08:17 +02:00
if ( Unit * unit = m_caster -> GetVehicleKit () -> GetPassenger ( cur . GetTarget () - TARGET_UNIT_PASSENGER_0 ))
2011-09-16 11:40:53 +02:00
AddUnitTarget ( unit , effectMask );
2010-02-20 23:59:05 +01:00
break ;
2011-07-27 11:00:39 +02:00
default :
break ;
2010-02-20 23:59:05 +01:00
}
break ;
}
case TARGET_TYPE_UNIT_TARGET :
{
2011-06-23 13:28:52 +02:00
Unit * target = m_targets . GetUnitTarget ();
2010-04-07 19:14:10 +02:00
if ( ! target )
2010-02-20 23:59:05 +01:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "SPELL: no unit target for spell ID %u" , m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
break ;
}
2011-09-05 14:01:50 +02:00
switch ( cur . GetTarget ())
2010-02-20 23:59:05 +01:00
{
case TARGET_UNIT_TARGET_ENEMY :
2011-09-15 14:08:17 +02:00
if ( Unit * magnet = m_caster -> SelectMagnetTarget ( target , m_spellInfo ))
2010-04-07 19:14:10 +02:00
if ( magnet != target )
2011-06-23 13:28:52 +02:00
m_targets . SetUnitTarget ( magnet );
2010-02-20 23:59:05 +01:00
pushType = PUSH_CHAIN ;
break ;
case TARGET_UNIT_TARGET_ANY :
2011-07-26 23:09:28 +02:00
if ( ! m_spellInfo -> IsPositive ())
2011-09-15 14:08:17 +02:00
if ( Unit * magnet = m_caster -> SelectMagnetTarget ( target , m_spellInfo ))
2010-04-07 19:14:10 +02:00
if ( magnet != target )
2011-06-23 13:28:52 +02:00
m_targets . SetUnitTarget ( magnet );
2010-02-20 23:59:05 +01:00
pushType = PUSH_CHAIN ;
break ;
2011-08-16 19:44:18 +02:00
case TARGET_UNIT_TARGET_CHAINHEAL_ALLY :
2010-02-20 23:59:05 +01:00
pushType = PUSH_CHAIN ;
break ;
case TARGET_UNIT_TARGET_ALLY :
2011-09-16 11:40:53 +02:00
AddUnitTarget ( target , effectMask , false );
2011-05-16 01:51:58 +07:00
break ;
2010-02-20 23:59:05 +01:00
case TARGET_UNIT_TARGET_RAID :
case TARGET_UNIT_TARGET_PARTY :
2011-06-04 12:13:27 +02:00
case TARGET_UNIT_TARGET_MINIPET :
2011-09-16 11:40:53 +02:00
AddUnitTarget ( target , effectMask , false );
2010-02-20 23:59:05 +01:00
break ;
2011-07-02 16:12:19 +02:00
case TARGET_UNIT_TARGET_PASSENGER :
2011-09-16 11:40:53 +02:00
AddUnitTarget ( target , effectMask , false );
2011-07-02 16:12:19 +02:00
break ;
2011-08-16 19:44:18 +02:00
case TARGET_UNIT_LASTTARGET_AREA_PARTY :
case TARGET_UNIT_TARGET_AREA_RAID_CLASS :
2010-02-20 23:59:05 +01:00
pushType = PUSH_CASTER_CENTER ; // not real
break ;
2011-07-27 11:00:39 +02:00
default :
break ;
2010-02-20 23:59:05 +01:00
}
break ;
}
case TARGET_TYPE_UNIT_NEARBY :
{
2011-09-15 14:08:17 +02:00
WorldObject * target = NULL ;
2010-02-20 23:59:05 +01:00
float range ;
2011-09-05 14:01:50 +02:00
switch ( cur . GetTarget ())
2010-02-20 23:59:05 +01:00
{
case TARGET_UNIT_NEARBY_ENEMY :
2011-07-26 23:09:28 +02:00
range = m_spellInfo -> GetMaxRange ( false );
2010-04-07 19:14:10 +02:00
if ( modOwner ) modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_RANGE , range , this );
2010-10-16 16:34:21 +02:00
target = SearchNearbyTarget ( range , SPELL_TARGETS_ENEMY , SpellEffIndex ( i ));
2010-02-20 23:59:05 +01:00
break ;
case TARGET_UNIT_NEARBY_ALLY :
2011-06-30 00:49:10 +02:00
case TARGET_UNIT_NEARBY_PARTY : // TODO: fix party/raid targets
2010-02-20 23:59:05 +01:00
case TARGET_UNIT_NEARBY_RAID :
2011-07-26 23:09:28 +02:00
range = m_spellInfo -> GetMaxRange ( true );
2010-04-07 19:14:10 +02:00
if ( modOwner ) modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_RANGE , range , this );
2010-10-16 16:34:21 +02:00
target = SearchNearbyTarget ( range , SPELL_TARGETS_ALLY , SpellEffIndex ( i ));
2010-02-20 23:59:05 +01:00
break ;
case TARGET_UNIT_NEARBY_ENTRY :
case TARGET_GAMEOBJECT_NEARBY_ENTRY :
2011-07-26 23:09:28 +02:00
range = m_spellInfo -> GetMaxRange ( m_spellInfo -> IsPositive ());
2010-04-07 19:14:10 +02:00
if ( modOwner ) modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_RANGE , range , this );
2010-10-16 16:34:21 +02:00
target = SearchNearbyTarget ( range , SPELL_TARGETS_ENTRY , SpellEffIndex ( i ));
2010-02-20 23:59:05 +01:00
break ;
2011-07-27 11:00:39 +02:00
default :
break ;
2010-02-20 23:59:05 +01:00
}
2010-04-07 19:14:10 +02:00
if ( ! target )
2011-09-16 11:40:53 +02:00
return 0 ;
2010-04-07 19:14:10 +02:00
else if ( target -> GetTypeId () == TYPEID_GAMEOBJECT )
2011-09-16 11:40:53 +02:00
AddGOTarget (( GameObject * ) target , effectMask );
2010-02-20 23:59:05 +01:00
else
{
pushType = PUSH_CHAIN ;
2011-06-23 13:28:52 +02:00
if ( m_targets . GetUnitTarget () != target )
m_targets . SetUnitTarget (( Unit * ) target );
2010-02-20 23:59:05 +01:00
}
break ;
}
case TARGET_TYPE_AREA_SRC :
pushType = PUSH_SRC_CENTER ;
break ;
case TARGET_TYPE_AREA_DST :
pushType = PUSH_DST_CENTER ;
break ;
case TARGET_TYPE_AREA_CONE :
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> AttributesCu & SPELL_ATTR0_CU_CONE_BACK )
2010-02-20 23:59:05 +01:00
pushType = PUSH_IN_BACK ;
2011-07-26 23:09:28 +02:00
else if ( m_spellInfo -> AttributesCu & SPELL_ATTR0_CU_CONE_LINE )
2010-02-20 23:59:05 +01:00
pushType = PUSH_IN_LINE ;
else
pushType = PUSH_IN_FRONT ;
break ;
case TARGET_TYPE_DEST_CASTER : //4+8+2
{
2011-07-27 12:35:59 +02:00
if ( cur . GetTarget () == TARGET_SRC_CASTER )
2010-02-20 23:59:05 +01:00
{
2011-06-23 13:28:52 +02:00
m_targets . SetSrc ( * m_caster );
2010-02-20 23:59:05 +01:00
break ;
}
2011-08-16 19:44:18 +02:00
else if ( cur . GetTarget () == TARGET_DEST_CASTER )
2010-02-20 23:59:05 +01:00
{
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( * m_caster );
2010-02-20 23:59:05 +01:00
break ;
}
float angle , dist ;
float objSize = m_caster -> GetObjectSize ();
2011-08-16 19:44:18 +02:00
if ( cur . GetTarget () == TARGET_DEST_CASTER_SUMMON )
2010-11-14 23:31:32 +02:00
dist = 0.0f ;
else
2011-07-26 23:09:28 +02:00
dist = m_spellInfo -> Effects [ i ]. CalcRadius ( m_caster );
2010-07-21 02:06:51 +02:00
if ( modOwner ) modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_RADIUS , dist , this );
2010-04-07 19:14:10 +02:00
if ( dist < objSize )
2010-02-20 23:59:05 +01:00
dist = objSize ;
2011-07-27 12:35:59 +02:00
else if ( cur . GetTarget () == TARGET_DEST_CASTER_RANDOM )
2010-08-22 12:39:39 -07:00
dist = objSize + ( dist - objSize ) * ( float ) rand_norm ();
2010-02-20 23:59:05 +01:00
2011-09-05 14:01:50 +02:00
switch ( cur . GetTarget ())
2010-02-20 23:59:05 +01:00
{
2010-08-22 12:39:39 -07:00
case TARGET_DEST_CASTER_FRONT_LEFT : angle = static_cast < float > ( - M_PI / 4 ); break ;
case TARGET_DEST_CASTER_BACK_LEFT : angle = static_cast < float > ( - 3 * M_PI / 4 ); break ;
case TARGET_DEST_CASTER_BACK_RIGHT : angle = static_cast < float > ( 3 * M_PI / 4 ); break ;
case TARGET_DEST_CASTER_FRONT_RIGHT : angle = static_cast < float > ( M_PI / 4 ); break ;
2011-08-16 19:44:18 +02:00
case TARGET_DEST_CASTER_SUMMON :
2010-02-20 23:59:05 +01:00
case TARGET_DEST_CASTER_FRONT_LEAP :
2010-08-22 12:39:39 -07:00
case TARGET_DEST_CASTER_FRONT : angle = 0.0f ; break ;
case TARGET_DEST_CASTER_BACK : angle = static_cast < float > ( M_PI ); break ;
2011-06-09 16:39:41 +02:00
case TARGET_DEST_CASTER_RIGHT : angle = static_cast < float > ( - M_PI / 2 ); break ;
case TARGET_DEST_CASTER_LEFT : angle = static_cast < float > ( M_PI / 2 ); break ;
2010-08-22 12:39:39 -07:00
default : angle = ( float ) rand_norm () * static_cast < float > ( 2 * M_PI ); break ;
2010-02-20 23:59:05 +01:00
}
Position pos ;
2011-07-27 12:35:59 +02:00
if ( cur . GetTarget () == TARGET_DEST_CASTER_FRONT_LEAP )
2010-07-21 02:06:51 +02:00
m_caster -> GetFirstCollisionPosition ( pos , dist , angle );
else
m_caster -> GetNearPosition ( pos , dist , angle );
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( * m_caster );
m_targets . ModDst ( pos );
2010-02-20 23:59:05 +01:00
break ;
}
case TARGET_TYPE_DEST_TARGET : //2+8+2
{
2011-06-23 13:28:52 +02:00
Unit * target = m_targets . GetUnitTarget ();
2010-04-07 19:14:10 +02:00
if ( ! target )
2010-02-20 23:59:05 +01:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "SPELL: no unit target for spell ID %u" , m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
break ;
}
2011-08-16 19:44:18 +02:00
if ( cur . GetTarget () == TARGET_DEST_TARGET_ENEMY || cur . GetTarget () == TARGET_DEST_TARGET_ANY )
2010-02-20 23:59:05 +01:00
{
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( * target );
2010-02-20 23:59:05 +01:00
break ;
}
float angle , dist ;
float objSize = target -> GetObjectSize ();
2011-07-26 23:09:28 +02:00
dist = m_spellInfo -> Effects [ i ]. CalcRadius ( m_caster );
2010-04-07 19:14:10 +02:00
if ( dist < objSize )
2010-02-20 23:59:05 +01:00
dist = objSize ;
2011-07-27 12:35:59 +02:00
else if ( cur . GetTarget () == TARGET_DEST_TARGET_RANDOM )
2010-08-22 12:39:39 -07:00
dist = objSize + ( dist - objSize ) * ( float ) rand_norm ();
2010-02-20 23:59:05 +01:00
2011-09-05 14:01:50 +02:00
switch ( cur . GetTarget ())
2010-02-20 23:59:05 +01:00
{
2010-08-22 12:39:39 -07:00
case TARGET_DEST_TARGET_FRONT : angle = 0.0f ; break ;
case TARGET_DEST_TARGET_BACK : angle = static_cast < float > ( M_PI ); break ;
case TARGET_DEST_TARGET_RIGHT : angle = static_cast < float > ( M_PI / 2 ); break ;
case TARGET_DEST_TARGET_LEFT : angle = static_cast < float > ( - M_PI / 2 ); break ;
case TARGET_DEST_TARGET_FRONT_LEFT : angle = static_cast < float > ( - M_PI / 4 ); break ;
case TARGET_DEST_TARGET_BACK_LEFT : angle = static_cast < float > ( - 3 * M_PI / 4 ); break ;
case TARGET_DEST_TARGET_BACK_RIGHT : angle = static_cast < float > ( 3 * M_PI / 4 ); break ;
case TARGET_DEST_TARGET_FRONT_RIGHT : angle = static_cast < float > ( M_PI / 4 ); break ;
default : angle = ( float ) rand_norm () * static_cast < float > ( 2 * M_PI ); break ;
2010-02-20 23:59:05 +01:00
}
Position pos ;
target -> GetNearPosition ( pos , dist , angle );
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( * target );
m_targets . ModDst ( pos );
2010-02-20 23:59:05 +01:00
break ;
}
case TARGET_TYPE_DEST_DEST : //5+8+1
{
2010-04-07 19:14:10 +02:00
if ( ! m_targets . HasDst ())
2010-02-20 23:59:05 +01:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "SPELL: no destination for spell ID %u" , m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
break ;
}
float angle ;
2011-09-05 14:01:50 +02:00
switch ( cur . GetTarget ())
2010-02-20 23:59:05 +01:00
{
case TARGET_DEST_DYNOBJ_ENEMY :
case TARGET_DEST_DYNOBJ_ALLY :
case TARGET_DEST_DYNOBJ_NONE :
case TARGET_DEST_DEST :
2011-09-16 11:40:53 +02:00
return effectMask ;
2010-02-20 23:59:05 +01:00
case TARGET_DEST_TRAJ :
SelectTrajTargets ();
2011-09-16 11:40:53 +02:00
return effectMask ;
2010-08-22 12:39:39 -07:00
case TARGET_DEST_DEST_FRONT : angle = 0.0f ; break ;
case TARGET_DEST_DEST_BACK : angle = static_cast < float > ( M_PI ); break ;
case TARGET_DEST_DEST_RIGHT : angle = static_cast < float > ( M_PI / 2 ); break ;
case TARGET_DEST_DEST_LEFT : angle = static_cast < float > ( - M_PI / 2 ); break ;
case TARGET_DEST_DEST_FRONT_LEFT : angle = static_cast < float > ( - M_PI / 4 ); break ;
case TARGET_DEST_DEST_BACK_LEFT : angle = static_cast < float > ( - 3 * M_PI / 4 ); break ;
case TARGET_DEST_DEST_BACK_RIGHT : angle = static_cast < float > ( 3 * M_PI / 4 ); break ;
case TARGET_DEST_DEST_FRONT_RIGHT : angle = static_cast < float > ( M_PI / 4 ); break ;
default : angle = ( float ) rand_norm () * static_cast < float > ( 2 * M_PI ); break ;
2010-02-20 23:59:05 +01:00
}
2011-07-26 23:09:28 +02:00
float dist = m_spellInfo -> Effects [ i ]. CalcRadius ( m_caster );
2011-08-16 19:44:18 +02:00
if ( cur . GetTarget () == TARGET_DEST_DEST_RANDOM || cur . GetTarget () == TARGET_DEST_DEST_RADIUS )
2010-08-22 12:39:39 -07:00
dist *= ( float ) rand_norm ();
2010-02-20 23:59:05 +01:00
// must has dst, no need to set flag
2011-06-23 13:28:52 +02:00
Position pos = * m_targets . GetDst ();
2010-08-08 20:32:14 +02:00
m_caster -> MovePosition ( pos , dist , angle );
2011-06-23 13:28:52 +02:00
m_targets . ModDst ( pos );
2010-02-20 23:59:05 +01:00
break ;
}
case TARGET_TYPE_DEST_SPECIAL :
{
2011-09-05 14:01:50 +02:00
switch ( cur . GetTarget ())
2010-02-20 23:59:05 +01:00
{
2011-08-16 19:44:18 +02:00
case TARGET_DEST_DB :
2010-12-22 21:25:23 +01:00
if ( SpellTargetPosition const * st = sSpellMgr -> GetSpellTargetPosition ( m_spellInfo -> Id ))
2010-02-20 23:59:05 +01:00
{
//TODO: fix this check
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ 0 ]. Effect == SPELL_EFFECT_TELEPORT_UNITS || m_spellInfo -> Effects [ 1 ]. Effect == SPELL_EFFECT_TELEPORT_UNITS || m_spellInfo -> Effects [ 2 ]. Effect == SPELL_EFFECT_TELEPORT_UNITS )
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( st -> target_X , st -> target_Y , st -> target_Z , st -> target_Orientation , ( int32 ) st -> target_mapId );
2010-04-07 19:14:10 +02:00
else if ( st -> target_mapId == m_caster -> GetMapId ())
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( st -> target_X , st -> target_Y , st -> target_Z , st -> target_Orientation );
2010-02-20 23:59:05 +01:00
}
else
{
2011-09-04 23:44:01 +01:00
sLog -> outError ( "SPELL: unknown target coordinates for spell ID %u" , m_spellInfo -> Id );
2011-06-12 01:47:45 +02:00
Unit * target = NULL ;
2010-04-07 19:14:10 +02:00
if ( uint64 guid = m_caster -> GetUInt64Value ( UNIT_FIELD_TARGET ))
2010-02-20 23:59:05 +01:00
target = ObjectAccessor :: GetUnit ( * m_caster , guid );
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( target ? * target : * m_caster );
2010-02-20 23:59:05 +01:00
}
break ;
2011-08-16 19:44:18 +02:00
case TARGET_DEST_HOME :
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( m_caster -> ToPlayer () -> m_homebindX , m_caster -> ToPlayer () -> m_homebindY , m_caster -> ToPlayer () -> m_homebindZ , m_caster -> ToPlayer () -> GetOrientation (), m_caster -> ToPlayer () -> m_homebindMapId );
2010-02-20 23:59:05 +01:00
break ;
2011-08-16 19:44:18 +02:00
case TARGET_DEST_NEARBY_ENTRY :
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
float range = m_spellInfo -> GetMaxRange ( m_spellInfo -> IsPositive ());
2010-04-07 19:14:10 +02:00
if ( modOwner ) modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_RANGE , range , this );
2010-02-20 23:59:05 +01:00
2011-09-15 14:08:17 +02:00
if ( WorldObject * target = SearchNearbyTarget ( range , SPELL_TARGETS_ENTRY , SpellEffIndex ( i )))
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( * target );
2010-02-20 23:59:05 +01:00
break ;
}
2011-07-27 11:00:39 +02:00
default :
break ;
2010-02-20 23:59:05 +01:00
}
break ;
}
case TARGET_TYPE_CHANNEL :
{
if ( ! m_originalCaster || ! m_originalCaster -> GetCurrentSpell ( CURRENT_CHANNELED_SPELL ))
{
2011-06-07 16:23:20 +02:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "SPELL: no current channeled spell for spell ID %u - spell triggering this spell was interrupted." , m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
break ;
}
2011-07-27 12:35:59 +02:00
switch ( cur . GetTarget ())
2010-02-20 23:59:05 +01:00
{
2010-08-18 15:04:00 +02:00
case TARGET_UNIT_CHANNEL_TARGET :
// unit target may be no longer avalible - teleported out of map for example
2011-06-23 13:28:52 +02:00
if ( Unit * target = Unit :: GetUnit ( * m_caster , m_originalCaster -> GetCurrentSpell ( CURRENT_CHANNELED_SPELL ) -> m_targets . GetUnitTargetGUID ()))
2011-09-16 11:40:53 +02:00
AddUnitTarget ( target , effectMask );
2010-02-20 23:59:05 +01:00
else
2010-12-23 23:25:44 +01:00
sLog -> outError ( "SPELL: cannot find channel spell target for spell ID %u" , m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
break ;
2010-08-18 15:04:00 +02:00
case TARGET_DEST_CHANNEL_TARGET :
2010-02-20 23:59:05 +01:00
if ( m_originalCaster -> GetCurrentSpell ( CURRENT_CHANNELED_SPELL ) -> m_targets . HasDst ())
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( m_originalCaster -> GetCurrentSpell ( CURRENT_CHANNELED_SPELL ) -> m_targets );
else if ( Unit * target = Unit :: GetUnit ( * m_caster , m_originalCaster -> GetCurrentSpell ( CURRENT_CHANNELED_SPELL ) -> m_targets . GetUnitTargetGUID ()))
m_targets . SetDst ( * target );
2010-02-20 23:59:05 +01:00
else
2010-12-23 23:25:44 +01:00
sLog -> outError ( "SPELL: cannot find channel spell destination for spell ID %u" , m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
break ;
2010-08-18 15:04:00 +02:00
case TARGET_DEST_CHANNEL_CASTER :
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( * m_originalCaster -> GetCurrentSpell ( CURRENT_CHANNELED_SPELL ) -> GetCaster ());
2010-08-18 15:04:00 +02:00
break ;
2011-07-27 11:00:39 +02:00
default :
break ;
2010-02-20 23:59:05 +01:00
}
break ;
}
default :
{
2011-07-27 12:35:59 +02:00
switch ( cur . GetTarget ())
2010-02-20 23:59:05 +01:00
{
2011-08-16 19:44:18 +02:00
case TARGET_GAMEOBJECT_TARGET :
2011-06-23 13:28:52 +02:00
if ( m_targets . GetGOTarget ())
2011-09-16 11:40:53 +02:00
AddGOTarget ( m_targets . GetGOTarget (), effectMask );
2010-02-20 23:59:05 +01:00
break ;
2011-08-16 19:44:18 +02:00
case TARGET_GAMEOBJECT_ITEM_TARGET :
2011-07-28 23:44:39 +02:00
if ( m_targets . GetGOTargetGUID ())
2011-09-16 11:40:53 +02:00
AddGOTarget ( m_targets . GetGOTarget (), effectMask );
2011-06-23 13:28:52 +02:00
else if ( m_targets . GetItemTarget ())
2011-09-16 11:40:53 +02:00
AddItemTarget ( m_targets . GetItemTarget (), effectMask );
2010-02-20 23:59:05 +01:00
break ;
default :
2011-02-17 19:47:08 +06:00
sLog -> outError ( "SPELL (caster[type: %u; guidlow: %u], spell: %u): unhandled spell target (%u)" ,
2011-08-03 11:23:08 +02:00
m_caster -> GetTypeId (), m_caster -> GetGUIDLow (), m_spellInfo -> Id , cur . GetTarget ());
2010-02-20 23:59:05 +01:00
break ;
}
break ;
}
}
if ( pushType == PUSH_CHAIN ) // Chain
{
2011-06-23 13:28:52 +02:00
Unit * target = m_targets . GetUnitTarget ();
2010-02-20 23:59:05 +01:00
if ( ! target )
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "SPELL: no chain unit target for spell ID %u" , m_spellInfo -> Id );
2011-09-16 11:40:53 +02:00
return 0 ;
2010-02-20 23:59:05 +01:00
}
//Chain: 2, 6, 22, 25, 45, 77
2011-07-26 23:09:28 +02:00
uint32 maxTargets = m_spellInfo -> Effects [ i ]. ChainTarget ;
2010-02-20 23:59:05 +01:00
if ( modOwner )
modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_JUMP_TARGETS , maxTargets , this );
if ( maxTargets > 1 )
{
2010-12-04 10:31:14 +01:00
//otherwise, this multiplier is used for something else
2011-09-16 11:40:53 +02:00
for ( uint32 k = i ; k < MAX_SPELL_EFFECTS ; ++ k )
if ( effectMask & ( 1 << k ))
m_damageMultipliers [ k ] = 1.0f ;
m_applyMultiplierMask |= effectMask ;
2010-12-04 10:31:14 +01:00
2010-02-20 23:59:05 +01:00
float range ;
std :: list < Unit *> unitList ;
2011-07-27 12:35:59 +02:00
switch ( cur . GetTarget ())
2010-02-20 23:59:05 +01:00
{
case TARGET_UNIT_NEARBY_ENEMY :
case TARGET_UNIT_TARGET_ENEMY :
case TARGET_UNIT_NEARBY_ENTRY : // fix me
2011-07-26 23:09:28 +02:00
range = m_spellInfo -> GetMaxRange ( false );
2010-02-20 23:59:05 +01:00
if ( modOwner ) modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_RANGE , range , this );
SearchChainTarget ( unitList , range , maxTargets , SPELL_TARGETS_ENEMY );
break ;
2011-08-16 19:44:18 +02:00
case TARGET_UNIT_TARGET_CHAINHEAL_ALLY :
2010-02-20 23:59:05 +01:00
case TARGET_UNIT_NEARBY_ALLY : // fix me
2011-06-30 02:17:07 +02:00
case TARGET_UNIT_NEARBY_PARTY :
2010-02-20 23:59:05 +01:00
case TARGET_UNIT_NEARBY_RAID :
2011-07-26 23:09:28 +02:00
range = m_spellInfo -> GetMaxRange ( true );
2010-02-20 23:59:05 +01:00
if ( modOwner ) modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_RANGE , range , this );
SearchChainTarget ( unitList , range , maxTargets , SPELL_TARGETS_CHAINHEAL );
break ;
2011-07-27 11:00:39 +02:00
default :
break ;
2010-02-20 23:59:05 +01:00
}
2011-01-21 23:42:51 +01:00
CallScriptAfterUnitTargetSelectHandlers ( unitList , SpellEffIndex ( i ));
2010-02-20 23:59:05 +01:00
for ( std :: list < Unit *>:: iterator itr = unitList . begin (); itr != unitList . end (); ++ itr )
2011-09-16 11:40:53 +02:00
AddUnitTarget ( * itr , effectMask , false );
2010-02-20 23:59:05 +01:00
}
else
2011-09-16 11:40:53 +02:00
AddUnitTarget ( target , effectMask , false );
2010-02-20 23:59:05 +01:00
}
else if ( pushType )
{
float radius ;
SpellTargets targetType ;
2011-09-05 14:01:50 +02:00
switch ( cur . GetTarget ())
2010-02-20 23:59:05 +01:00
{
2011-08-16 19:44:18 +02:00
case TARGET_UNIT_SRC_AREA_ENEMY :
case TARGET_UNIT_DEST_AREA_ENEMY :
case TARGET_UNIT_CONE_ENEMY_24 :
case TARGET_UNIT_CONE_ENEMY_54 :
case TARGET_UNIT_CONE_ENEMY_104 :
2011-07-26 23:09:28 +02:00
radius = m_spellInfo -> Effects [ i ]. CalcRadius ();
2010-02-20 23:59:05 +01:00
targetType = SPELL_TARGETS_ENEMY ;
break ;
2011-08-16 19:44:18 +02:00
case TARGET_UNIT_SRC_AREA_ALLY :
case TARGET_UNIT_DEST_AREA_ALLY :
2010-02-20 23:59:05 +01:00
case TARGET_UNIT_CONE_ALLY :
2011-07-26 23:09:28 +02:00
radius = m_spellInfo -> Effects [ i ]. CalcRadius ();
2010-02-20 23:59:05 +01:00
targetType = SPELL_TARGETS_ALLY ;
break ;
2011-08-16 19:44:18 +02:00
case TARGET_UNIT_DEST_AREA_ENTRY :
case TARGET_UNIT_SRC_AREA_ENTRY :
2010-02-20 23:59:05 +01:00
case TARGET_UNIT_CONE_ENTRY : // fix me
2011-07-26 23:09:28 +02:00
radius = m_spellInfo -> Effects [ i ]. CalcRadius ();
2010-02-20 23:59:05 +01:00
targetType = SPELL_TARGETS_ENTRY ;
break ;
2011-08-16 19:44:18 +02:00
case TARGET_GAMEOBJECT_SRC_AREA :
case TARGET_GAMEOBJECT_DEST_AREA :
case TARGET_GAMEOBJECT_CONE :
2011-07-26 23:09:28 +02:00
radius = m_spellInfo -> Effects [ i ]. CalcRadius ();
2010-07-30 01:51:33 +02:00
targetType = SPELL_TARGETS_GO ;
break ;
2010-02-20 23:59:05 +01:00
default :
2011-07-26 23:09:28 +02:00
radius = m_spellInfo -> Effects [ i ]. CalcRadius ();
2010-02-20 23:59:05 +01:00
targetType = SPELL_TARGETS_NONE ;
break ;
}
2010-04-07 19:14:10 +02:00
if ( modOwner )
2010-02-20 23:59:05 +01:00
modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_RADIUS , radius , this );
radius *= m_spellValue -> RadiusMod ;
std :: list < Unit *> unitList ;
2010-07-30 01:51:33 +02:00
std :: list < GameObject *> gobjectList ;
switch ( targetType )
2010-02-20 23:59:05 +01:00
{
2010-07-30 01:51:33 +02:00
case SPELL_TARGETS_ENTRY :
2010-02-20 23:59:05 +01:00
{
2010-12-22 21:25:23 +01:00
ConditionList conditions = sConditionMgr -> GetConditionsForNotGroupedEntry ( CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET , m_spellInfo -> Id );
2010-07-30 01:51:33 +02:00
if ( ! conditions . empty ())
2010-02-20 23:59:05 +01:00
{
2010-07-30 01:51:33 +02:00
for ( ConditionList :: const_iterator i_spellST = conditions . begin (); i_spellST != conditions . end (); ++ i_spellST )
2010-02-20 23:59:05 +01:00
{
2010-07-30 01:51:33 +02:00
if (( * i_spellST ) -> mConditionType != CONDITION_SPELL_SCRIPT_TARGET )
continue ;
2011-09-16 11:40:53 +02:00
if (( * i_spellST ) -> mConditionValue3 && ! (( * i_spellST ) -> mConditionValue3 & effectMask ))
2010-10-16 16:34:21 +02:00
continue ;
2010-07-30 01:51:33 +02:00
if (( * i_spellST ) -> mConditionValue1 == SPELL_TARGET_TYPE_CREATURE )
SearchAreaTarget ( unitList , radius , pushType , SPELL_TARGETS_ENTRY , ( * i_spellST ) -> mConditionValue2 );
else if (( * i_spellST ) -> mConditionValue1 == SPELL_TARGET_TYPE_CONTROLLED )
2010-02-20 23:59:05 +01:00
{
2010-07-30 01:51:33 +02:00
for ( Unit :: ControlList :: iterator itr = m_caster -> m_Controlled . begin (); itr != m_caster -> m_Controlled . end (); ++ itr )
if (( * itr ) -> GetEntry () == ( * i_spellST ) -> mConditionValue2 &&
2011-05-22 16:01:53 -07:00
( * itr ) -> IsInMap ( m_caster )) // For 60243 and 52173 need skip radius check or use range (no radius entry for effect)
2010-07-30 01:51:33 +02:00
unitList . push_back ( * itr );
2010-02-20 23:59:05 +01:00
}
}
2010-07-30 01:51:33 +02:00
}
else
{
// Custom entries
// TODO: move these to sql
switch ( m_spellInfo -> Id )
{
case 46584 : // Raise Dead
2010-02-20 23:59:05 +01:00
{
2010-07-30 01:51:33 +02:00
if ( WorldObject * result = FindCorpseUsing < Trinity :: RaiseDeadObjectCheck > ())
2010-02-20 23:59:05 +01:00
{
2011-09-05 14:01:50 +02:00
switch ( result -> GetTypeId ())
2010-02-20 23:59:05 +01:00
{
case TYPEID_UNIT :
2011-06-23 13:28:52 +02:00
m_targets . SetDst ( * result );
2010-08-21 20:08:47 +02:00
break ;
default :
break ;
2010-02-20 23:59:05 +01:00
}
}
2010-07-30 01:51:33 +02:00
break ;
}
// Corpse Explosion
case 49158 :
case 51325 :
case 51326 :
case 51327 :
case 51328 :
// Search for ghoul if our ghoul or dead body not valid unit target
2011-06-23 13:28:52 +02:00
if ( ! ( m_targets . GetUnitTarget () && (( m_targets . GetUnitTarget () -> GetEntry () == 26125 && m_targets . GetUnitTarget () -> GetOwnerGUID () == m_caster -> GetGUID ())
|| ( m_targets . GetUnitTarget () -> getDeathState () == CORPSE
&& m_targets . GetUnitTarget () -> GetTypeId () == TYPEID_UNIT
&& ! ( m_targets . GetUnitTarget () -> GetCreatureTypeMask () & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL )
&& m_targets . GetUnitTarget () -> GetDisplayId () == m_targets . GetUnitTarget () -> GetNativeDisplayId ()))))
2010-02-20 23:59:05 +01:00
{
2010-07-30 01:51:33 +02:00
CleanupTargetList ();
WorldObject * result = FindCorpseUsing < Trinity :: ExplodeCorpseObjectCheck > ();
if ( result )
{
switch ( result -> GetTypeId ())
{
case TYPEID_UNIT :
case TYPEID_PLAYER :
2011-06-23 13:28:52 +02:00
m_targets . SetUnitTarget (( Unit * ) result );
2010-07-30 01:51:33 +02:00
break ;
2010-08-21 20:55:31 +02:00
default :
break ;
2010-07-30 01:51:33 +02:00
}
}
else
{
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2011-04-29 20:47:02 +02:00
m_caster -> ToPlayer () -> RemoveSpellCooldown ( m_spellInfo -> Id , true );
2010-07-30 01:51:33 +02:00
SendCastResult ( SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW );
finish ( false );
}
2010-02-20 23:59:05 +01:00
}
2010-07-30 01:51:33 +02:00
break ;
2010-02-20 23:59:05 +01:00
2010-07-30 01:51:33 +02:00
default :
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell (ID: %u) (caster Entry: %u) does not have type CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET record in `conditions` table." , m_spellInfo -> Id , m_caster -> GetEntry ());
2010-02-20 23:59:05 +01:00
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ i ]. Effect == SPELL_EFFECT_TELEPORT_UNITS )
2010-07-30 01:51:33 +02:00
SearchAreaTarget ( unitList , radius , pushType , SPELL_TARGETS_ENTRY , 0 );
2011-07-26 23:09:28 +02:00
else if ( m_spellInfo -> IsPositiveEffect ( i ))
2010-07-30 01:51:33 +02:00
SearchAreaTarget ( unitList , radius , pushType , SPELL_TARGETS_ALLY );
else
SearchAreaTarget ( unitList , radius , pushType , SPELL_TARGETS_ENEMY );
}
2010-02-20 23:59:05 +01:00
}
2010-07-30 01:51:33 +02:00
break ;
2010-02-20 23:59:05 +01:00
}
2010-07-30 01:51:33 +02:00
case SPELL_TARGETS_GO :
2010-02-20 23:59:05 +01:00
{
2010-12-22 21:25:23 +01:00
ConditionList conditions = sConditionMgr -> GetConditionsForNotGroupedEntry ( CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET , m_spellInfo -> Id );
2010-07-30 01:51:33 +02:00
if ( ! conditions . empty ())
2010-02-20 23:59:05 +01:00
{
2010-07-30 01:51:33 +02:00
for ( ConditionList :: const_iterator i_spellST = conditions . begin (); i_spellST != conditions . end (); ++ i_spellST )
2010-02-20 23:59:05 +01:00
{
2010-07-30 01:51:33 +02:00
if (( * i_spellST ) -> mConditionType != CONDITION_SPELL_SCRIPT_TARGET )
continue ;
2011-09-16 11:40:53 +02:00
if (( * i_spellST ) -> mConditionValue3 && ! (( * i_spellST ) -> mConditionValue3 & effectMask ))
2010-10-16 16:34:21 +02:00
continue ;
2010-07-30 01:51:33 +02:00
if (( * i_spellST ) -> mConditionValue1 == SPELL_TARGET_TYPE_GAMEOBJECT )
SearchGOAreaTarget ( gobjectList , radius , pushType , SPELL_TARGETS_GO , ( * i_spellST ) -> mConditionValue2 );
2010-02-20 23:59:05 +01:00
}
}
2010-07-30 01:51:33 +02:00
else
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ i ]. Effect == SPELL_EFFECT_ACTIVATE_OBJECT )
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell (ID: %u) (caster Entry: %u) with SPELL_EFFECT_ACTIVATE_OBJECT does not have type CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET record in `conditions` table." , m_spellInfo -> Id , m_caster -> GetEntry ());
2010-07-30 01:51:33 +02:00
SearchGOAreaTarget ( gobjectList , radius , pushType , SPELL_TARGETS_GO );
2010-02-20 23:59:05 +01:00
}
2010-07-30 01:51:33 +02:00
break ;
}
case SPELL_TARGETS_ALLY :
case SPELL_TARGETS_ENEMY :
case SPELL_TARGETS_CHAINHEAL :
case SPELL_TARGETS_ANY :
SearchAreaTarget ( unitList , radius , pushType , targetType );
break ;
default :
2011-07-27 12:35:59 +02:00
switch ( cur . GetTarget ())
2010-02-20 23:59:05 +01:00
{
2011-08-16 19:44:18 +02:00
case TARGET_UNIT_SRC_AREA_PARTY :
case TARGET_UNIT_DEST_AREA_PARTY :
2010-07-30 01:51:33 +02:00
m_caster -> GetPartyMemberInDist ( unitList , radius ); //fix me
break ;
2011-08-16 19:44:18 +02:00
case TARGET_UNIT_LASTTARGET_AREA_PARTY :
2011-06-23 13:28:52 +02:00
m_targets . GetUnitTarget () -> GetPartyMemberInDist ( unitList , radius );
2010-07-30 01:51:33 +02:00
break ;
2011-08-16 19:44:18 +02:00
case TARGET_UNIT_CASTER_AREA_PARTY :
2010-07-30 01:51:33 +02:00
m_caster -> GetPartyMemberInDist ( unitList , radius );
break ;
2011-08-16 19:44:18 +02:00
case TARGET_UNIT_CASTER_AREA_RAID :
2010-07-30 01:51:33 +02:00
m_caster -> GetRaidMember ( unitList , radius );
break ;
2011-08-16 19:44:18 +02:00
case TARGET_UNIT_TARGET_AREA_RAID_CLASS :
2010-02-20 23:59:05 +01:00
{
2011-06-23 13:28:52 +02:00
Player * targetPlayer = m_targets . GetUnitTarget () && m_targets . GetUnitTarget () -> GetTypeId () == TYPEID_PLAYER
? ( Player * ) m_targets . GetUnitTarget () : NULL ;
2010-02-20 23:59:05 +01:00
2011-10-07 10:54:53 -05:00
Group * group = targetPlayer ? targetPlayer -> GetGroup () : NULL ;
if ( group )
2010-07-30 01:51:33 +02:00
{
2011-10-07 10:54:53 -05:00
for ( GroupReference * itr = group -> GetFirstMember (); itr != NULL ; itr = itr -> next ())
2010-02-20 23:59:05 +01:00
{
2010-07-30 01:51:33 +02:00
Player * Target = itr -> getSource ();
// IsHostileTo check duel and controlled by enemy
2011-05-22 16:01:53 -07:00
if ( Target && targetPlayer -> IsWithinDistInMap ( Target , radius ) && targetPlayer -> getClass () == Target -> getClass () && ! m_caster -> IsHostileTo ( Target ))
2011-09-16 11:40:53 +02:00
AddUnitTarget ( Target , effectMask );
2010-02-20 23:59:05 +01:00
}
}
2011-06-23 13:28:52 +02:00
else if ( m_targets . GetUnitTarget ())
2011-09-16 11:40:53 +02:00
AddUnitTarget ( m_targets . GetUnitTarget (), effectMask );
2010-07-30 01:51:33 +02:00
break ;
2010-02-20 23:59:05 +01:00
}
2011-07-27 11:00:39 +02:00
default :
break ;
2010-02-20 23:59:05 +01:00
}
2010-07-30 01:51:33 +02:00
break ;
2010-02-20 23:59:05 +01:00
}
2010-04-07 19:14:10 +02:00
if ( ! unitList . empty ())
2010-02-20 23:59:05 +01:00
{
2010-06-18 04:17:21 +02:00
// Special target selection for smart heals and energizes
uint32 maxSize = 0 ;
int32 power = - 1 ;
switch ( m_spellInfo -> SpellFamilyName )
{
case SPELLFAMILY_GENERIC :
switch ( m_spellInfo -> Id )
{
case 52759 : // Ancestral Awakening
case 71610 : // Echoes of Light (Althor's Abacus normal version)
case 71641 : // Echoes of Light (Althor's Abacus heroic version)
maxSize = 1 ;
power = POWER_HEALTH ;
break ;
case 54968 : // Glyph of Holy Light
maxSize = m_spellInfo -> MaxAffectedTargets ;
power = POWER_HEALTH ;
break ;
case 57669 : // Replenishment
2010-06-18 16:21:23 +02:00
// In arenas Replenishment may only affect the caster
if ( m_caster -> GetTypeId () == TYPEID_PLAYER && m_caster -> ToPlayer () -> InArena ())
{
unitList . clear ();
unitList . push_back ( m_caster );
break ;
}
2010-06-18 04:17:21 +02:00
maxSize = 10 ;
power = POWER_MANA ;
break ;
default :
break ;
}
break ;
case SPELLFAMILY_PRIEST :
if ( m_spellInfo -> SpellFamilyFlags [ 0 ] == 0x10000000 ) // Circle of Healing
{
maxSize = m_caster -> HasAura ( 55675 ) ? 6 : 5 ; // Glyph of Circle of Healing
power = POWER_HEALTH ;
}
else if ( m_spellInfo -> Id == 64844 ) // Divine Hymn
{
maxSize = 3 ;
power = POWER_HEALTH ;
}
else if ( m_spellInfo -> Id == 64904 ) // Hymn of Hope
{
maxSize = 3 ;
power = POWER_MANA ;
}
2010-06-18 17:21:39 +02:00
else
break ;
2010-06-18 04:17:21 +02:00
// Remove targets outside caster's raid
for ( std :: list < Unit *>:: iterator itr = unitList . begin () ; itr != unitList . end ();)
{
if ( ! ( * itr ) -> IsInRaidWith ( m_caster ))
itr = unitList . erase ( itr );
else
++ itr ;
}
break ;
case SPELLFAMILY_DRUID :
if ( m_spellInfo -> SpellFamilyFlags [ 1 ] == 0x04000000 ) // Wild Growth
{
maxSize = m_caster -> HasAura ( 62970 ) ? 6 : 5 ; // Glyph of Wild Growth
power = POWER_HEALTH ;
}
2011-01-06 19:57:36 +01:00
else if ( m_spellInfo -> SpellFamilyFlags [ 2 ] == 0x0100 ) // Starfall
{
// Remove targets not in LoS or in stealth
for ( std :: list < Unit *>:: iterator itr = unitList . begin () ; itr != unitList . end ();)
{
if (( * itr ) -> HasStealthAura () || ( * itr ) -> HasInvisibilityAura () || ! ( * itr ) -> IsWithinLOSInMap ( m_caster ))
itr = unitList . erase ( itr );
else
++ itr ;
}
break ;
}
2010-06-18 17:21:39 +02:00
else
break ;
2010-06-18 04:17:21 +02:00
// Remove targets outside caster's raid
for ( std :: list < Unit *>:: iterator itr = unitList . begin () ; itr != unitList . end ();)
if ( ! ( * itr ) -> IsInRaidWith ( m_caster ))
itr = unitList . erase ( itr );
else
++ itr ;
break ;
default :
break ;
}
if ( maxSize && power != - 1 )
{
2010-08-30 15:25:15 +02:00
if ( Powers ( power ) == POWER_HEALTH )
2010-06-18 04:17:21 +02:00
{
if ( unitList . size () > maxSize )
{
unitList . sort ( Trinity :: HealthPctOrderPred ());
unitList . resize ( maxSize );
}
}
else
{
for ( std :: list < Unit *>:: iterator itr = unitList . begin () ; itr != unitList . end ();)
if (( * itr ) -> getPowerType () != ( Powers ) power )
itr = unitList . erase ( itr );
else
++ itr ;
2011-05-22 16:01:53 -07:00
2010-06-18 04:17:21 +02:00
if ( unitList . size () > maxSize )
{
unitList . sort ( Trinity :: PowerPctOrderPred (( Powers ) power ));
unitList . resize ( maxSize );
}
}
}
2010-08-08 19:45:53 +02:00
2010-06-18 04:17:21 +02:00
// Other special target selection goes here
2010-04-07 19:14:10 +02:00
if ( uint32 maxTargets = m_spellValue -> MaxAffectedTargets )
2010-02-20 23:59:05 +01:00
{
Unit :: AuraEffectList const & Auras = m_caster -> GetAuraEffectsByType ( SPELL_AURA_MOD_MAX_AFFECTED_TARGETS );
for ( Unit :: AuraEffectList :: const_iterator j = Auras . begin (); j != Auras . end (); ++ j )
2010-04-07 19:14:10 +02:00
if (( * j ) -> IsAffectedOnSpell ( m_spellInfo ))
2010-02-20 23:59:05 +01:00
maxTargets += ( * j ) -> GetAmount ();
2010-04-07 19:14:10 +02:00
if ( m_spellInfo -> Id == 5246 ) //Intimidating Shout
2011-06-23 13:28:52 +02:00
unitList . remove ( m_targets . GetUnitTarget ());
2010-07-30 01:51:33 +02:00
Trinity :: RandomResizeList ( unitList , maxTargets );
2010-02-20 23:59:05 +01:00
}
2011-01-21 23:42:51 +01:00
CallScriptAfterUnitTargetSelectHandlers ( unitList , SpellEffIndex ( i ));
2010-02-20 23:59:05 +01:00
for ( std :: list < Unit *>:: iterator itr = unitList . begin (); itr != unitList . end (); ++ itr )
2011-09-16 11:40:53 +02:00
AddUnitTarget ( * itr , effectMask , false );
2010-02-20 23:59:05 +01:00
}
2010-07-30 01:51:33 +02:00
if ( ! gobjectList . empty ())
{
if ( uint32 maxTargets = m_spellValue -> MaxAffectedTargets )
{
Unit :: AuraEffectList const & Auras = m_caster -> GetAuraEffectsByType ( SPELL_AURA_MOD_MAX_AFFECTED_TARGETS );
for ( Unit :: AuraEffectList :: const_iterator j = Auras . begin (); j != Auras . end (); ++ j )
if (( * j ) -> IsAffectedOnSpell ( m_spellInfo ))
maxTargets += ( * j ) -> GetAmount ();
Trinity :: RandomResizeList ( gobjectList , maxTargets );
}
for ( std :: list < GameObject *>:: iterator itr = gobjectList . begin (); itr != gobjectList . end (); ++ itr )
2011-09-16 11:40:53 +02:00
AddGOTarget ( * itr , effectMask );
2010-07-30 01:51:33 +02:00
}
2010-02-20 23:59:05 +01:00
}
2011-09-16 11:40:53 +02:00
return effectMask ;
2010-02-20 23:59:05 +01:00
}
2011-06-11 22:35:29 +02:00
void Spell :: prepare ( SpellCastTargets const * targets , AuraEffect const * triggeredByAura )
2010-02-20 23:59:05 +01:00
{
if ( m_CastItem )
m_castItemGUID = m_CastItem -> GetGUID ();
else
m_castItemGUID = 0 ;
2011-08-24 08:07:59 +02:00
InitExplicitTargets ( * targets );
2010-02-20 23:59:05 +01:00
2010-10-31 22:37:54 +01:00
if ( Player * plrCaster = m_caster -> GetCharmerOrOwnerPlayerOrPlayerItself ())
2010-06-04 23:24:48 +02:00
{
//check for special spell conditions
2010-12-22 21:25:23 +01:00
ConditionList conditions = sConditionMgr -> GetConditionsForNotGroupedEntry ( CONDITION_SOURCE_TYPE_SPELL , m_spellInfo -> Id );
2010-06-04 23:24:48 +02:00
if ( ! conditions . empty ())
2010-12-22 21:25:23 +01:00
if ( ! sConditionMgr -> IsPlayerMeetToConditions ( plrCaster , conditions ))
2010-06-04 23:24:48 +02:00
{
2010-10-31 22:37:54 +01:00
//SendCastResult(SPELL_FAILED_DONT_REPORT);
SendCastResult ( plrCaster , m_spellInfo , m_cast_count , SPELL_FAILED_DONT_REPORT );
2010-06-04 23:24:48 +02:00
finish ( false );
return ;
}
}
2010-03-19 00:21:57 +01:00
2010-02-20 23:59:05 +01:00
// Fill aura scaling information
2011-07-31 19:03:06 +02:00
if ( m_caster -> IsControlledByPlayer () && ! m_spellInfo -> IsPassive () && m_spellInfo -> SpellLevel && ! m_spellInfo -> IsChanneled () && ! ( _triggeredCastFlags & TRIGGERED_IGNORE_AURA_SCALING ))
2010-02-20 23:59:05 +01:00
{
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
{
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ i ]. Effect == SPELL_EFFECT_APPLY_AURA )
2010-02-20 23:59:05 +01:00
{
// Change aura with ranks only if basepoints are taken from spellInfo and aura is positive
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> IsPositiveEffect ( i ))
2010-02-20 23:59:05 +01:00
{
2011-05-22 16:01:53 -07:00
m_auraScaleMask |= ( 1 << i );
2011-07-26 23:09:28 +02:00
if ( m_spellValue -> EffectBasePoints [ i ] != m_spellInfo -> Effects [ i ]. BasePoints )
2010-02-20 23:59:05 +01:00
{
m_auraScaleMask = 0 ;
break ;
}
}
}
}
}
m_spellState = SPELL_STATE_PREPARING ;
2010-04-07 19:14:10 +02:00
if ( triggeredByAura )
2011-07-26 23:09:28 +02:00
m_triggeredByAuraSpell = triggeredByAura -> GetSpellInfo ();
2010-02-20 23:59:05 +01:00
// create and add update event for this spell
SpellEvent * Event = new SpellEvent ( this );
m_caster -> m_Events . AddEvent ( Event , m_caster -> m_Events . CalculateTime ( 1 ));
//Prevent casting at cast another spell (ServerSide check)
2011-07-31 19:03:06 +02:00
if ( ! ( _triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS ) && m_caster -> IsNonMeleeSpellCasted ( false , true , true ) && m_cast_count )
2010-02-20 23:59:05 +01:00
{
SendCastResult ( SPELL_FAILED_SPELL_IN_PROGRESS );
finish ( false );
return ;
}
2010-07-21 12:14:23 +02:00
2011-09-09 14:27:23 +02:00
if ( DisableMgr :: IsDisabledFor ( DISABLE_TYPE_SPELL , m_spellInfo -> Id , m_caster ))
2010-02-20 23:59:05 +01:00
{
2010-07-21 12:14:23 +02:00
SendCastResult ( SPELL_FAILED_SPELL_UNAVAILABLE );
finish ( false );
return ;
2010-02-20 23:59:05 +01:00
}
2010-07-24 22:41:42 +02:00
LoadScripts ();
2010-02-20 23:59:05 +01:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , true );
2010-02-20 23:59:05 +01:00
// Fill cost data (not use power for item casts
2011-07-26 23:09:28 +02:00
m_powerCost = m_CastItem ? 0 : m_spellInfo -> CalcPowerCost ( m_caster , m_spellSchoolMask );
2010-02-20 23:59:05 +01:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , false );
2010-02-20 23:59:05 +01:00
2010-09-14 13:28:25 +03:00
// Set combo point requirement
2011-07-31 19:03:06 +02:00
if (( _triggeredCastFlags & TRIGGERED_IGNORE_COMBO_POINTS ) || m_CastItem || ! m_caster -> m_movedPlayer )
2010-09-14 13:28:25 +03:00
m_needComboPoints = false ;
2010-02-20 23:59:05 +01:00
SpellCastResult result = CheckCast ( true );
2010-04-07 19:14:10 +02:00
if ( result != SPELL_CAST_OK && ! IsAutoRepeat ()) //always cast autorepeat dummy for triggering
2010-02-20 23:59:05 +01:00
{
2011-08-26 14:23:23 +02:00
// Periodic auras should be interrupted when aura triggers a spell which can't be cast
// for example bladestorm aura should be removed on disarm as of patch 3.3.5
// channeled periodic spells should be affected by this (arcane missiles, penance, etc)
// a possible alternative sollution for those would be validating aura target on unit state change
2011-08-26 15:40:11 +02:00
if ( triggeredByAura && triggeredByAura -> IsPeriodic () && ! triggeredByAura -> GetBase () -> IsPassive ())
2010-02-20 23:59:05 +01:00
{
SendChannelUpdate ( 0 );
triggeredByAura -> GetBase () -> SetDuration ( 0 );
}
2011-08-12 13:22:53 +02:00
2010-02-20 23:59:05 +01:00
SendCastResult ( result );
finish ( false );
return ;
}
// Prepare data for triggers
prepareDataForTriggerSystem ( triggeredByAura );
2011-05-17 13:33:24 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , true );
2010-02-20 23:59:05 +01:00
// calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail)
2011-07-26 23:09:28 +02:00
m_casttime = m_spellInfo -> CalcCastTime ( m_caster , this );
2011-05-17 13:33:24 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , false );
2010-02-20 23:59:05 +01:00
2010-09-10 15:51:31 +03:00
// don't allow channeled spells / spells with cast time to be casted while moving
// (even if they are interrupted on moving, spells with almost immediate effect get to have their effect processed before movement interrupter kicks in)
2011-07-26 23:09:28 +02:00
if (( m_spellInfo -> IsChanneled () || m_casttime ) && m_caster -> GetTypeId () == TYPEID_PLAYER && m_caster -> isMoving () && m_spellInfo -> InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT )
2010-09-10 15:51:31 +03:00
{
SendCastResult ( SPELL_FAILED_MOVING );
finish ( false );
return ;
}
2010-02-20 23:59:05 +01:00
// set timer base at cast time
ReSetTimer ();
2011-07-31 19:03:06 +02:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell::prepare: spell id %u source %u caster %d customCastFlags %u mask %u" , m_spellInfo -> Id , m_caster -> GetEntry (), m_originalCaster ? m_originalCaster -> GetEntry () : - 1 , _triggeredCastFlags , m_targets . GetTargetMask ());
2010-02-20 23:59:05 +01:00
//Containers for channeled spells have to be set
//TODO:Apply this to all casted spells if needed
// Why check duration? 29350: channelled triggers channelled
2011-07-31 19:03:06 +02:00
if (( _triggeredCastFlags & TRIGGERED_CAST_DIRECTLY ) && ( ! m_spellInfo -> IsChanneled () || ! m_spellInfo -> GetMaxDuration ()))
2010-02-20 23:59:05 +01:00
cast ( true );
else
{
// stealth must be removed at cast starting (at show channel bar)
// skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
2011-07-31 19:03:06 +02:00
if ( ! ( _triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS ) && m_spellInfo -> IsBreakingStealth ())
2010-02-20 23:59:05 +01:00
{
m_caster -> RemoveAurasWithInterruptFlags ( AURA_INTERRUPT_FLAG_CAST );
2010-09-28 08:41:24 +03:00
for ( uint32 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2011-09-23 11:58:01 +02:00
if ( m_spellInfo -> Effects [ i ]. GetUsedTargetObjectType () == TARGET_OBJECT_TYPE_UNIT )
2010-02-20 23:59:05 +01:00
{
m_caster -> RemoveAurasWithInterruptFlags ( AURA_INTERRUPT_FLAG_SPELL_ATTACK );
break ;
}
}
2010-04-07 22:59:46 +02:00
m_caster -> SetCurrentCastedSpell ( this );
2010-02-20 23:59:05 +01:00
SendSpellStart ();
2011-07-15 12:33:03 +02:00
// set target for proper facing
2011-07-31 19:03:06 +02:00
if ( m_casttime && ! ( _triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING ))
2011-07-15 12:33:03 +02:00
if ( uint64 target = m_targets . GetUnitTargetGUID ())
if ( m_caster -> GetGUID () != target && m_caster -> GetTypeId () == TYPEID_UNIT )
m_caster -> FocusTarget ( this , target );
2011-07-31 19:03:06 +02:00
if ( ! ( _triggeredCastFlags & TRIGGERED_IGNORE_GCD ))
TriggerGlobalCooldown ();
2011-02-22 17:02:47 +06:00
2011-05-30 19:48:22 +02:00
//item: first cast may destroy item and second cast causes crash
2011-05-22 16:01:53 -07:00
if ( ! m_casttime && ! m_spellInfo -> StartRecoveryTime && ! m_castItemGUID && GetCurrentContainer () == CURRENT_GENERIC_SPELL )
2010-02-20 23:59:05 +01:00
cast ( true );
}
}
void Spell :: cancel ()
{
2010-04-07 19:14:10 +02:00
if ( m_spellState == SPELL_STATE_FINISHED )
2010-02-20 23:59:05 +01:00
return ;
uint32 oldState = m_spellState ;
m_spellState = SPELL_STATE_FINISHED ;
m_autoRepeat = false ;
switch ( oldState )
{
case SPELL_STATE_PREPARING :
2011-02-22 17:02:47 +06:00
CancelGlobalCooldown ();
2011-05-17 13:33:24 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
m_caster -> ToPlayer () -> RestoreSpellMods ( this );
2010-02-20 23:59:05 +01:00
case SPELL_STATE_DELAYED :
SendInterrupted ( 0 );
SendCastResult ( SPELL_FAILED_INTERRUPTED );
2010-04-11 11:19:22 +02:00
break ;
2010-02-20 23:59:05 +01:00
case SPELL_STATE_CASTING :
for ( std :: list < TargetInfo >:: const_iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
if (( * ihit ). missCondition == SPELL_MISS_NONE )
if ( Unit * unit = m_caster -> GetGUID () == ihit -> targetGUID ? m_caster : ObjectAccessor :: GetUnit ( * m_caster , ihit -> targetGUID ))
unit -> RemoveOwnedAura ( m_spellInfo -> Id , m_originalCasterGUID , 0 , AURA_REMOVE_BY_CANCEL );
SendChannelUpdate ( 0 );
SendInterrupted ( 0 );
SendCastResult ( SPELL_FAILED_INTERRUPTED );
// spell is canceled-take mods and clear list
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> RemoveSpellMods ( this );
2010-02-20 23:59:05 +01:00
m_appliedMods . clear ();
2010-04-11 11:19:22 +02:00
break ;
2010-02-20 23:59:05 +01:00
default :
2010-04-11 11:19:22 +02:00
break ;
2010-02-20 23:59:05 +01:00
}
2011-04-11 16:35:31 +06:00
SetReferencedFromCurrent ( false );
if ( m_selfContainer && * m_selfContainer == this )
* m_selfContainer = NULL ;
2010-02-20 23:59:05 +01:00
m_caster -> RemoveDynObject ( m_spellInfo -> Id );
2011-04-29 20:47:02 +02:00
m_caster -> RemoveGameObject ( m_spellInfo -> Id , true );
2010-02-20 23:59:05 +01:00
//set state back so finish will be processed
m_spellState = oldState ;
finish ( false );
}
void Spell :: cast ( bool skipCheck )
{
// update pointers base at GUIDs to prevent access to non-existed already object
UpdatePointers ();
2011-09-11 22:40:48 +02:00
// cancel at lost explicit target during cast
if ( m_targets . GetObjectTargetGUID () && ! m_targets . GetObjectTarget ())
2010-02-20 23:59:05 +01:00
{
2011-09-11 22:40:48 +02:00
cancel ();
return ;
2010-02-20 23:59:05 +01:00
}
2010-09-03 19:58:16 -07:00
// now that we've done the basic check, now run the scripts
// should be done before the spell is actually executed
2011-06-12 01:47:45 +02:00
if ( Player * playerCaster = m_caster -> ToPlayer ())
2010-12-22 21:25:23 +01:00
sScriptMgr -> OnPlayerSpellCast ( playerCaster , this , skipCheck );
2010-09-03 19:58:16 -07:00
2010-02-20 23:59:05 +01:00
SetExecutedCurrently ( true );
2011-06-23 13:28:52 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER && m_targets . GetUnitTarget () && m_targets . GetUnitTarget () != m_caster )
m_caster -> SetInFront ( m_targets . GetUnitTarget ());
2010-02-20 23:59:05 +01:00
// Should this be done for original caster?
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
{
// Set spell which will drop charges for triggered cast spells
// if not successfully casted, will be remove in finish(false)
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , true );
2010-02-20 23:59:05 +01:00
}
2011-09-11 22:24:53 +02:00
// skip check if done already (for instant cast spells for example)
if ( ! skipCheck )
2010-02-20 23:59:05 +01:00
{
SpellCastResult castResult = CheckCast ( false );
2010-04-07 19:14:10 +02:00
if ( castResult != SPELL_CAST_OK )
2010-02-20 23:59:05 +01:00
{
SendCastResult ( castResult );
SendInterrupted ( 0 );
//restore spell mods
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
{
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> RestoreSpellMods ( this );
2010-02-20 23:59:05 +01:00
// cleanup after mod system
// triggered spell pointer can be not removed in some cases
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , false );
2010-02-20 23:59:05 +01:00
}
finish ( false );
SetExecutedCurrently ( false );
return ;
}
2010-06-25 13:15:51 +02:00
// additional check after cast bar completes (must not be in CheckCast)
// if trade not complete then remember it in trade data
2011-06-23 13:28:52 +02:00
if ( m_targets . GetTargetMask () & TARGET_FLAG_TRADE_ITEM )
2010-06-25 13:15:51 +02:00
{
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
{
if ( TradeData * my_trade = m_caster -> ToPlayer () -> GetTradeData ())
{
if ( ! my_trade -> IsInAcceptProcess ())
{
// Spell will be casted at completing the trade. Silently ignore at this place
my_trade -> SetSpell ( m_spellInfo -> Id , m_CastItem );
SendCastResult ( SPELL_FAILED_DONT_REPORT );
SendInterrupted ( 0 );
m_caster -> ToPlayer () -> RestoreSpellMods ( this );
// cleanup after mod system
// triggered spell pointer can be not removed in some cases
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , false );
finish ( false );
SetExecutedCurrently ( false );
return ;
}
}
}
}
2010-02-20 23:59:05 +01:00
}
SelectSpellTargets ();
// Spell may be finished after target map check
2010-04-07 19:14:10 +02:00
if ( m_spellState == SPELL_STATE_FINISHED )
2010-02-20 23:59:05 +01:00
{
SendInterrupted ( 0 );
//restore spell mods
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
{
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> RestoreSpellMods ( this );
2010-02-20 23:59:05 +01:00
// cleanup after mod system
// triggered spell pointer can be not removed in some cases
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , false );
2010-02-20 23:59:05 +01:00
}
finish ( false );
SetExecutedCurrently ( false );
return ;
}
2011-06-26 00:29:12 +02:00
PrepareTriggersExecutedOnHit ();
2010-09-03 20:30:29 -07:00
2010-02-20 23:59:05 +01:00
// traded items have trade slot instead of guid in m_itemTargetGUID
// set to real guid to be sent later to the client
2011-06-23 13:28:52 +02:00
m_targets . UpdateTradeSlotItem ();
2010-02-20 23:59:05 +01:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
{
2011-07-31 19:03:06 +02:00
if ( ! ( _triggeredCastFlags & TRIGGERED_IGNORE_CAST_ITEM ) && m_CastItem )
2010-04-27 22:22:13 +02:00
{
m_caster -> ToPlayer () -> GetAchievementMgr (). StartTimedAchievement ( ACHIEVEMENT_TIMED_TYPE_ITEM , m_CastItem -> GetEntry ());
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM , m_CastItem -> GetEntry ());
2010-04-27 22:22:13 +02:00
}
2010-02-20 23:59:05 +01:00
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL , m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
}
2011-07-31 19:03:06 +02:00
if ( ! ( _triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST ))
2010-02-20 23:59:05 +01:00
{
// Powers have to be taken before SendSpellGo
TakePower ();
TakeReagents (); // we must remove reagents before HandleEffects to allow place crafted item in same slot
}
2011-06-23 13:28:52 +02:00
else if ( Item * targetItem = m_targets . GetItemTarget ())
2010-06-25 13:15:51 +02:00
{
/// Not own traded item (in trader trade slot) req. reagents including triggered spell case
if ( targetItem -> GetOwnerGUID () != m_caster -> GetGUID ())
TakeReagents ();
}
2010-02-20 23:59:05 +01:00
// CAST SPELL
SendSpellCooldown ();
2010-08-21 20:18:54 +02:00
PrepareScriptHitHandlers ();
2010-08-19 14:31:31 +02:00
2011-09-25 13:29:17 +02:00
HandleLaunchPhase ();
2010-02-20 23:59:05 +01:00
// we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
2010-04-07 18:09:10 +02:00
SendSpellGo ();
2010-02-20 23:59:05 +01:00
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
2011-07-26 23:09:28 +02:00
if (( m_spellInfo -> Speed > 0.0f && ! m_spellInfo -> IsChanneled ()) || m_spellInfo -> Id == 14157 )
2010-02-20 23:59:05 +01:00
{
// Remove used for cast item if need (it can be already NULL after TakeReagents call
// in case delayed spell remove item at cast delay start
TakeCastItem ();
// Okay, maps created, now prepare flags
m_immediateHandled = false ;
m_spellState = SPELL_STATE_DELAYED ;
SetDelayStart ( 0 );
2010-12-17 13:43:24 +01:00
if ( m_caster -> HasUnitState ( UNIT_STAT_CASTING ) && ! m_caster -> IsNonMeleeSpellCasted ( false , false , true ))
m_caster -> ClearUnitState ( UNIT_STAT_CASTING );
2010-02-20 23:59:05 +01:00
}
else
{
// Immediate spell, no big deal
handle_immediate ();
}
2011-07-26 23:09:28 +02:00
if ( const std :: vector < int32 > * spell_triggered = sSpellMgr -> GetSpellLinked ( m_spellInfo -> Id ))
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
for ( std :: vector < int32 >:: const_iterator i = spell_triggered -> begin (); i != spell_triggered -> end (); ++ i )
if ( * i < 0 )
m_caster -> RemoveAurasDueToSpell ( - ( * i ));
else
m_caster -> CastSpell ( m_targets . GetUnitTarget () ? m_targets . GetUnitTarget () : m_caster , * i , true );
2010-09-05 13:39:10 +02:00
}
2010-02-20 23:59:05 +01:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , false );
2010-02-20 23:59:05 +01:00
SetExecutedCurrently ( false );
}
void Spell :: handle_immediate ()
{
// start channeling if applicable
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> IsChanneled ())
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
int32 duration = m_spellInfo -> GetDuration ();
2010-02-20 23:59:05 +01:00
if ( duration )
{
2010-04-25 22:20:59 +02:00
// First mod_duration then haste - see Missile Barrage
2010-02-20 23:59:05 +01:00
// Apply duration mod
2010-04-07 19:14:10 +02:00
if ( Player * modOwner = m_caster -> GetSpellModOwner ())
2010-02-20 23:59:05 +01:00
modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_DURATION , duration );
2010-04-25 22:20:59 +02:00
// Apply haste mods
2011-05-12 18:59:49 +07:00
if ( m_spellInfo -> AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION )
m_caster -> ModSpellCastTime ( m_spellInfo , duration , this );
2010-04-25 22:20:59 +02:00
2010-02-20 23:59:05 +01:00
m_spellState = SPELL_STATE_CASTING ;
m_caster -> AddInterruptMask ( m_spellInfo -> ChannelInterruptFlags );
SendChannelStart ( duration );
}
}
2010-08-27 17:49:32 +02:00
PrepareTargetProcessing ();
2010-02-20 23:59:05 +01:00
// process immediate effects (items, ground, etc.) also initialize some variables
_handle_immediate_phase ();
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
DoAllEffectOnTarget ( & ( * ihit ));
for ( std :: list < GOTargetInfo >:: iterator ihit = m_UniqueGOTargetInfo . begin (); ihit != m_UniqueGOTargetInfo . end (); ++ ihit )
DoAllEffectOnTarget ( & ( * ihit ));
2010-08-27 17:49:32 +02:00
FinishTargetProcessing ();
2010-02-20 23:59:05 +01:00
// spell is finished, perform some last features of the spell here
_handle_finish_phase ();
// Remove used for cast item if need (it can be already NULL after TakeReagents call
TakeCastItem ();
2011-08-25 00:32:46 +02:00
// handle ammo consumption for Hunter's volley spell
2011-08-25 00:41:02 +02:00
if ( m_spellInfo -> IsRangedWeaponSpell () && m_spellInfo -> IsChanneled ())
2011-08-25 00:32:46 +02:00
TakeAmmo ();
2011-08-24 23:26:25 +02:00
2010-04-07 19:14:10 +02:00
if ( m_spellState != SPELL_STATE_CASTING )
2010-02-20 23:59:05 +01:00
finish ( true ); // successfully finish spell cast (not last in case autorepeat or channel spell)
}
uint64 Spell :: handle_delayed ( uint64 t_offset )
{
UpdatePointers ();
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , true );
2010-02-20 23:59:05 +01:00
uint64 next_time = 0 ;
2010-08-27 17:49:32 +02:00
PrepareTargetProcessing ();
2010-02-20 23:59:05 +01:00
if ( ! m_immediateHandled )
{
_handle_immediate_phase ();
m_immediateHandled = true ;
}
2010-08-02 20:05:22 +02:00
bool single_missile = ( m_targets . HasDst ());
2010-02-20 23:59:05 +01:00
// now recheck units targeting correctness (need before any effects apply to prevent adding immunity at first effect not allow apply second spell effect and similar cases)
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
{
if ( ihit -> processed == false )
{
2010-04-07 22:59:46 +02:00
if ( single_missile || ihit -> timeDelay <= t_offset )
2010-11-13 18:04:56 +01:00
{
ihit -> timeDelay = t_offset ;
2010-02-20 23:59:05 +01:00
DoAllEffectOnTarget ( & ( * ihit ));
2010-11-13 18:04:56 +01:00
}
2010-04-07 22:59:46 +02:00
else if ( next_time == 0 || ihit -> timeDelay < next_time )
2010-02-20 23:59:05 +01:00
next_time = ihit -> timeDelay ;
}
}
// now recheck gameobject targeting correctness
for ( std :: list < GOTargetInfo >:: iterator ighit = m_UniqueGOTargetInfo . begin (); ighit != m_UniqueGOTargetInfo . end (); ++ ighit )
{
if ( ighit -> processed == false )
{
2010-04-07 22:59:46 +02:00
if ( single_missile || ighit -> timeDelay <= t_offset )
2010-02-20 23:59:05 +01:00
DoAllEffectOnTarget ( & ( * ighit ));
2010-04-07 22:59:46 +02:00
else if ( next_time == 0 || ighit -> timeDelay < next_time )
2010-02-20 23:59:05 +01:00
next_time = ighit -> timeDelay ;
}
}
2010-08-27 17:49:32 +02:00
FinishTargetProcessing ();
2010-02-20 23:59:05 +01:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , false );
2010-02-20 23:59:05 +01:00
// All targets passed - need finish phase
if ( next_time == 0 )
{
// spell is finished, perform some last features of the spell here
_handle_finish_phase ();
finish ( true ); // successfully finish spell cast
// return zero, spell is finished now
return 0 ;
}
else
{
// spell is unfinished, return next execution time
return next_time ;
}
}
void Spell :: _handle_immediate_phase ()
{
m_spellAura = NULL ;
2011-09-25 13:29:17 +02:00
// initialize Diminishing Returns Data
m_diminishLevel = DIMINISHING_LEVEL_1 ;
m_diminishGroup = DIMINISHING_NONE ;
2010-02-20 23:59:05 +01:00
// handle some immediate features of the spell here
2011-07-26 23:09:28 +02:00
HandleThreatSpells ();
2010-02-20 23:59:05 +01:00
2010-08-21 20:18:54 +02:00
PrepareScriptHitHandlers ();
2010-08-19 14:31:31 +02:00
2011-09-25 13:29:17 +02:00
// handle effects with SPELL_EFFECT_HANDLE_HIT mode
2010-09-28 08:41:24 +03:00
for ( uint32 j = 0 ; j < MAX_SPELL_EFFECTS ; ++ j )
2010-02-20 23:59:05 +01:00
{
2011-09-25 13:29:17 +02:00
// don't do anything for empty effect
if ( ! m_spellInfo -> Effects [ j ]. IsEffect ())
2010-02-20 23:59:05 +01:00
continue ;
2011-09-25 13:29:17 +02:00
// call effect handlers to handle destination hit
HandleEffects ( NULL , NULL , NULL , j , SPELL_EFFECT_HANDLE_HIT );
2010-02-20 23:59:05 +01:00
}
// process items
for ( std :: list < ItemTargetInfo >:: iterator ihit = m_UniqueItemInfo . begin (); ihit != m_UniqueItemInfo . end (); ++ ihit )
DoAllEffectOnTarget ( & ( * ihit ));
2010-04-07 19:14:10 +02:00
if ( ! m_originalCaster )
2010-02-20 23:59:05 +01:00
return ;
2011-09-25 13:29:17 +02:00
// Handle procs on cast
// TODO: finish new proc system:P
if ( m_UniqueTargetInfo . empty ())
2010-02-20 23:59:05 +01:00
{
uint32 procAttacker = m_procAttacker ;
if ( ! procAttacker )
{
2011-09-25 13:29:17 +02:00
bool positive = m_spellInfo -> IsPositive ();
2011-09-05 14:01:50 +02:00
switch ( m_spellInfo -> DmgClass )
2010-02-20 23:59:05 +01:00
{
case SPELL_DAMAGE_CLASS_MAGIC :
if ( positive )
2010-10-08 19:17:49 +02:00
procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS ;
2010-02-20 23:59:05 +01:00
else
2010-10-08 19:17:49 +02:00
procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG ;
2010-02-20 23:59:05 +01:00
break ;
case SPELL_DAMAGE_CLASS_NONE :
if ( positive )
2010-10-08 19:17:49 +02:00
procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS ;
2010-02-20 23:59:05 +01:00
else
2010-10-08 19:17:49 +02:00
procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG ;
2010-02-20 23:59:05 +01:00
break ;
}
}
// Proc damage for spells which have only dest targets (2484 should proc 51486 for example)
2011-10-02 16:23:52 +02:00
m_originalCaster -> ProcDamageAndSpell ( NULL , procAttacker , 0 , m_procEx | PROC_EX_NORMAL_HIT , 0 , BASE_ATTACK , m_spellInfo , m_triggeredByAuraSpell );
2010-02-20 23:59:05 +01:00
}
}
void Spell :: _handle_finish_phase ()
{
2010-04-07 19:14:10 +02:00
if ( m_caster -> m_movedPlayer )
2010-02-20 23:59:05 +01:00
{
// Take for real after all targets are processed
if ( m_needComboPoints )
m_caster -> m_movedPlayer -> ClearComboPoints ();
// Real add combo points from effects
if ( m_comboPointGain )
m_caster -> m_movedPlayer -> GainSpellComboPoints ( m_comboPointGain );
}
2011-09-25 16:42:12 +03:00
if ( m_caster -> m_extraAttacks && GetSpellInfo () -> HasEffect ( SPELL_EFFECT_ADD_EXTRA_ATTACKS ))
m_caster -> HandleProcExtraAttackFor ( m_caster -> getVictim ());
2011-06-26 00:29:12 +02:00
// TODO: trigger proc phase finish here
2010-02-20 23:59:05 +01:00
}
void Spell :: SendSpellCooldown ()
{
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
2010-02-20 23:59:05 +01:00
return ;
Player * _player = ( Player * ) m_caster ;
// mana/health/etc potions, disabled by client (until combat out as declarate)
if ( m_CastItem && m_CastItem -> IsPotion ())
{
// need in some way provided data for Spell::finish SendCooldownEvent
_player -> SetLastPotionId ( m_CastItem -> GetEntry ());
return ;
}
// have infinity cooldown but set at aura apply // do not set cooldown for triggered spells (needed by reincarnation)
2011-07-31 19:03:06 +02:00
if ( m_spellInfo -> Attributes & ( SPELL_ATTR0_DISABLED_WHILE_ACTIVE | SPELL_ATTR0_PASSIVE ) || ( _triggeredCastFlags & TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD ))
2010-02-20 23:59:05 +01:00
return ;
2011-04-29 20:47:02 +02:00
_player -> AddSpellAndCategoryCooldowns ( m_spellInfo , m_CastItem ? m_CastItem -> GetEntry () : 0 , this );
2010-02-20 23:59:05 +01:00
}
void Spell :: update ( uint32 difftime )
{
// update pointers based at it's GUIDs
UpdatePointers ();
2011-07-28 23:44:39 +02:00
if ( m_targets . GetUnitTargetGUID () && ! m_targets . GetUnitTarget ())
2010-02-20 23:59:05 +01:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell %u is cancelled due to removal of target." , m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
cancel ();
return ;
}
// check if the player caster has moved before the spell finished
if (( m_caster -> GetTypeId () == TYPEID_PLAYER && m_timer != 0 ) &&
m_caster -> isMoving () && ( m_spellInfo -> InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT ) &&
2011-07-26 23:09:28 +02:00
( m_spellInfo -> Effects [ 0 ]. Effect != SPELL_EFFECT_STUCK || ! m_caster -> HasUnitMovementFlag ( MOVEMENTFLAG_FALLING )))
2010-02-20 23:59:05 +01:00
{
// don't cancel for melee, autorepeat, triggered and instant spells
2011-07-31 19:03:06 +02:00
if ( ! IsNextMeleeSwingSpell () && ! IsAutoRepeat () && ! IsTriggered ())
2010-02-20 23:59:05 +01:00
cancel ();
}
2011-09-05 14:01:50 +02:00
switch ( m_spellState )
2010-02-20 23:59:05 +01:00
{
case SPELL_STATE_PREPARING :
{
2010-04-07 19:14:10 +02:00
if ( m_timer )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( difftime >= m_timer )
2010-02-20 23:59:05 +01:00
m_timer = 0 ;
else
m_timer -= difftime ;
}
2010-04-07 19:14:10 +02:00
if ( m_timer == 0 && ! IsNextMeleeSwingSpell () && ! IsAutoRepeat ())
2011-07-26 23:09:28 +02:00
// don't CheckCast for instant spells - done in spell::prepare, skip duplicate checks, needed for range checks for example
cast ( ! m_casttime );
2010-02-20 23:59:05 +01:00
} break ;
case SPELL_STATE_CASTING :
{
2010-04-07 19:14:10 +02:00
if ( m_timer > 0 )
2010-02-20 23:59:05 +01:00
{
// check if there are alive targets left
if ( ! UpdateChanneledTargetList ())
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Channeled spell %d is removed due to lack of targets" , m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
SendChannelUpdate ( 0 );
finish ();
}
2010-04-07 19:14:10 +02:00
if ( difftime >= m_timer )
2010-02-20 23:59:05 +01:00
m_timer = 0 ;
else
m_timer -= difftime ;
}
2010-04-07 19:14:10 +02:00
if ( m_timer == 0 )
2010-02-20 23:59:05 +01:00
{
SendChannelUpdate ( 0 );
// channeled spell processed independently for quest targeting
// cast at creature (or GO) quest objectives update at successful cast channel finished
2010-04-07 22:59:46 +02:00
// ignore autorepeat/melee casts for speed (not exist quest for spells (hm...)
if ( ! IsAutoRepeat () && ! IsNextMeleeSwingSpell ())
2010-02-20 23:59:05 +01:00
{
2010-04-07 22:59:46 +02:00
if ( Player * p = m_caster -> GetCharmerOrOwnerPlayerOrPlayerItself ())
2010-02-20 23:59:05 +01:00
{
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
{
TargetInfo * target = &* ihit ;
2010-04-07 19:14:10 +02:00
if ( ! IS_CRE_OR_VEH_GUID ( target -> targetGUID ))
2010-02-20 23:59:05 +01:00
continue ;
Unit * unit = m_caster -> GetGUID () == target -> targetGUID ? m_caster : ObjectAccessor :: GetUnit ( * m_caster , target -> targetGUID );
if ( unit == NULL )
continue ;
p -> CastedCreatureOrGO ( unit -> GetEntry (), unit -> GetGUID (), m_spellInfo -> Id );
}
for ( std :: list < GOTargetInfo >:: iterator ihit = m_UniqueGOTargetInfo . begin (); ihit != m_UniqueGOTargetInfo . end (); ++ ihit )
{
GOTargetInfo * target = &* ihit ;
GameObject * go = m_caster -> GetMap () -> GetGameObject ( target -> targetGUID );
2010-04-07 19:14:10 +02:00
if ( ! go )
2010-02-20 23:59:05 +01:00
continue ;
p -> CastedCreatureOrGO ( go -> GetEntry (), go -> GetGUID (), m_spellInfo -> Id );
}
}
}
finish ();
}
} break ;
default :
{
} break ;
}
}
void Spell :: finish ( bool ok )
{
2010-04-07 19:14:10 +02:00
if ( ! m_caster )
2010-02-20 23:59:05 +01:00
return ;
2010-04-07 19:14:10 +02:00
if ( m_spellState == SPELL_STATE_FINISHED )
2010-02-20 23:59:05 +01:00
return ;
m_spellState = SPELL_STATE_FINISHED ;
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> IsChanneled ())
2010-02-20 23:59:05 +01:00
m_caster -> UpdateInterruptMask ();
2010-12-17 13:43:24 +01:00
if ( m_caster -> HasUnitState ( UNIT_STAT_CASTING ) && ! m_caster -> IsNonMeleeSpellCasted ( false , false , true ))
m_caster -> ClearUnitState ( UNIT_STAT_CASTING );
2010-02-20 23:59:05 +01:00
// Unsummon summon as possessed creatures on spell cancel
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> IsChanneled () && m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-02-20 23:59:05 +01:00
{
2011-09-15 14:08:17 +02:00
if ( Unit * charm = m_caster -> GetCharm ())
2010-04-07 19:14:10 +02:00
if ( charm -> GetTypeId () == TYPEID_UNIT
2010-03-07 18:30:53 +01:00
&& charm -> ToCreature () -> HasUnitTypeMask ( UNIT_MASK_PUPPET )
2010-02-20 23:59:05 +01:00
&& charm -> GetUInt32Value ( UNIT_CREATED_BY_SPELL ) == m_spellInfo -> Id )
(( Puppet * ) charm ) -> UnSummon ();
}
2011-07-15 12:33:03 +02:00
if ( m_caster -> GetTypeId () == TYPEID_UNIT )
m_caster -> ReleaseFocus ( this );
2010-04-07 19:14:10 +02:00
if ( ! ok )
2010-02-20 23:59:05 +01:00
return ;
2010-03-07 18:30:53 +01:00
if ( m_caster -> GetTypeId () == TYPEID_UNIT && m_caster -> ToCreature () -> isSummon ())
2010-02-20 23:59:05 +01:00
{
// Unsummon statue
uint32 spell = m_caster -> GetUInt32Value ( UNIT_CREATED_BY_SPELL );
2011-09-15 14:08:17 +02:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( spell );
2010-04-07 23:25:02 +02:00
if ( spellInfo && spellInfo -> SpellIconID == 2056 )
2010-02-20 23:59:05 +01:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Statue %d is unsummoned in spell %d finish" , m_caster -> GetGUIDLow (), m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
m_caster -> setDeathState ( JUST_DIED );
return ;
}
}
2010-09-12 23:52:37 +03:00
if ( IsAutoActionResetSpell ())
2010-02-20 23:59:05 +01:00
{
bool found = false ;
Unit :: AuraEffectList const & vIgnoreReset = m_caster -> GetAuraEffectsByType ( SPELL_AURA_IGNORE_MELEE_RESET );
for ( Unit :: AuraEffectList :: const_iterator i = vIgnoreReset . begin (); i != vIgnoreReset . end (); ++ i )
{
if (( * i ) -> IsAffectedOnSpell ( m_spellInfo ))
{
found = true ;
break ;
}
}
2010-12-19 05:15:47 +01:00
if ( ! found && ! ( m_spellInfo -> AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS ))
2010-02-20 23:59:05 +01:00
{
m_caster -> resetAttackTimer ( BASE_ATTACK );
2010-04-07 19:14:10 +02:00
if ( m_caster -> haveOffhandWeapon ())
2010-02-20 23:59:05 +01:00
m_caster -> resetAttackTimer ( OFF_ATTACK );
2010-09-12 23:52:37 +03:00
m_caster -> resetAttackTimer ( RANGED_ATTACK );
2010-02-20 23:59:05 +01:00
}
}
// potions disabled by client, send event "not in combat" if need
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
{
if ( ! m_triggeredByAuraSpell )
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> UpdatePotionCooldown ( this );
2010-02-20 23:59:05 +01:00
// triggered spell pointer can be not set in some cases
// this is needed for proper apply of triggered spell mods
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , true );
2010-02-20 23:59:05 +01:00
2011-02-03 22:20:40 +01:00
// Take mods after trigger spell (needed for 14177 to affect 48664)
// mods are taken only on succesfull cast and independantly from targets of the spell
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> RemoveSpellMods ( this );
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , false );
2010-02-20 23:59:05 +01:00
}
// Stop Attack for some spells
2010-12-19 05:15:47 +01:00
if ( m_spellInfo -> Attributes & SPELL_ATTR0_STOP_ATTACK_TARGET )
2010-02-20 23:59:05 +01:00
m_caster -> AttackStop ();
}
void Spell :: SendCastResult ( SpellCastResult result )
{
2010-04-07 19:14:10 +02:00
if ( result == SPELL_CAST_OK )
2010-02-20 23:59:05 +01:00
return ;
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
return ;
2010-04-07 19:14:10 +02:00
if ( m_caster -> ToPlayer () -> GetSession () -> PlayerLoading ()) // don't send cast results at loading time
2010-02-20 23:59:05 +01:00
return ;
2011-03-04 21:18:38 +01:00
SendCastResult ( m_caster -> ToPlayer (), m_spellInfo , m_cast_count , result , m_customError );
2010-02-20 23:59:05 +01:00
}
2011-07-26 23:09:28 +02:00
void Spell :: SendCastResult ( Player * caster , SpellInfo const * spellInfo , uint8 cast_count , SpellCastResult result , SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/ )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( result == SPELL_CAST_OK )
2010-02-20 23:59:05 +01:00
return ;
WorldPacket data ( SMSG_CAST_FAILED , ( 4 + 1 + 1 ));
data << uint8 ( cast_count ); // single cast or multi 2.3 (0/1)
data << uint32 ( spellInfo -> Id );
data << uint8 ( result ); // problem
switch ( result )
{
case SPELL_FAILED_REQUIRES_SPELL_FOCUS :
data << uint32 ( spellInfo -> RequiresSpellFocus );
break ;
case SPELL_FAILED_REQUIRES_AREA :
// hardcode areas limitation case
2011-09-05 14:01:50 +02:00
switch ( spellInfo -> Id )
2010-02-20 23:59:05 +01:00
{
case 41617 : // Cenarion Mana Salve
case 41619 : // Cenarion Healing Salve
data << uint32 ( 3905 );
break ;
case 41618 : // Bottled Nethergon Energy
case 41620 : // Bottled Nethergon Vapor
data << uint32 ( 3842 );
break ;
case 45373 : // Bloodberry Elixir
data << uint32 ( 4075 );
break ;
default : // default case (don't must be)
data << uint32 ( 0 );
break ;
}
break ;
case SPELL_FAILED_TOTEMS :
2010-04-07 19:14:10 +02:00
if ( spellInfo -> Totem [ 0 ])
2010-02-20 23:59:05 +01:00
data << uint32 ( spellInfo -> Totem [ 0 ]);
2010-04-07 19:14:10 +02:00
if ( spellInfo -> Totem [ 1 ])
2010-02-20 23:59:05 +01:00
data << uint32 ( spellInfo -> Totem [ 1 ]);
break ;
case SPELL_FAILED_TOTEM_CATEGORY :
2010-04-07 19:14:10 +02:00
if ( spellInfo -> TotemCategory [ 0 ])
2010-02-20 23:59:05 +01:00
data << uint32 ( spellInfo -> TotemCategory [ 0 ]);
2010-04-07 19:14:10 +02:00
if ( spellInfo -> TotemCategory [ 1 ])
2010-02-20 23:59:05 +01:00
data << uint32 ( spellInfo -> TotemCategory [ 1 ]);
break ;
case SPELL_FAILED_EQUIPPED_ITEM_CLASS :
data << uint32 ( spellInfo -> EquippedItemClass );
data << uint32 ( spellInfo -> EquippedItemSubClassMask );
//data << uint32(spellInfo->EquippedItemInventoryTypeMask);
break ;
case SPELL_FAILED_TOO_MANY_OF_ITEM :
{
2010-04-19 09:26:37 +02:00
uint32 item = 0 ;
2011-06-30 08:05:03 +07:00
for ( int8 x = 0 ; x < 3 ; x ++ )
2011-07-26 23:09:28 +02:00
if ( spellInfo -> Effects [ x ]. ItemType )
item = spellInfo -> Effects [ x ]. ItemType ;
2011-06-30 08:05:03 +07:00
ItemTemplate const * pProto = sObjectMgr -> GetItemTemplate ( item );
2010-02-20 23:59:05 +01:00
if ( pProto && pProto -> ItemLimitCategory )
data << uint32 ( pProto -> ItemLimitCategory );
break ;
}
2011-03-04 21:18:38 +01:00
case SPELL_FAILED_CUSTOM_ERROR :
data << uint32 ( customError );
break ;
2010-02-20 23:59:05 +01:00
default :
break ;
}
caster -> GetSession () -> SendPacket ( & data );
}
void Spell :: SendSpellStart ()
{
2010-04-07 19:14:10 +02:00
if ( ! IsNeedSendToClient ())
2010-02-20 23:59:05 +01:00
return ;
2011-02-20 20:16:34 +01:00
//sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Sending SMSG_SPELL_START id=%u", m_spellInfo->Id);
2010-02-20 23:59:05 +01:00
uint32 castFlags = CAST_FLAG_UNKNOWN_2 ;
2011-07-30 19:15:06 +02:00
2011-07-31 19:03:06 +02:00
if (( IsTriggered () && ! m_spellInfo -> IsAutoRepeatRangedSpell ()) || m_triggeredByAuraSpell )
2011-07-30 19:15:06 +02:00
castFlags |= CAST_FLAG_PENDING ;
2010-12-19 05:15:47 +01:00
if ( m_spellInfo -> Attributes & SPELL_ATTR0_REQ_AMMO )
2010-02-20 23:59:05 +01:00
castFlags |= CAST_FLAG_AMMO ;
if (( m_caster -> GetTypeId () == TYPEID_PLAYER ||
2010-03-07 18:30:53 +01:00
( m_caster -> GetTypeId () == TYPEID_UNIT && m_caster -> ToCreature () -> isPet ()))
2011-07-26 23:09:28 +02:00
&& m_spellInfo -> PowerType != POWER_HEALTH )
2010-02-20 23:59:05 +01:00
castFlags |= CAST_FLAG_POWER_LEFT_SELF ;
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> RuneCostID && m_spellInfo -> PowerType == POWER_RUNE )
2010-02-20 23:59:05 +01:00
castFlags |= CAST_FLAG_UNKNOWN_19 ;
WorldPacket data ( SMSG_SPELL_START , ( 8 + 8 + 4 + 4 + 2 ));
2010-04-07 19:14:10 +02:00
if ( m_CastItem )
2010-02-20 23:59:05 +01:00
data . append ( m_CastItem -> GetPackGUID ());
else
data . append ( m_caster -> GetPackGUID ());
data . append ( m_caster -> GetPackGUID ());
data << uint8 ( m_cast_count ); // pending spell cast?
data << uint32 ( m_spellInfo -> Id ); // spellId
data << uint32 ( castFlags ); // cast flags
data << uint32 ( m_timer ); // delay?
2011-06-23 13:28:52 +02:00
m_targets . Write ( data );
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( castFlags & CAST_FLAG_POWER_LEFT_SELF )
2011-07-26 23:09:28 +02:00
data << uint32 ( m_caster -> GetPower (( Powers ) m_spellInfo -> PowerType ));
2010-02-20 23:59:05 +01:00
2010-04-07 22:59:46 +02:00
if ( castFlags & CAST_FLAG_AMMO )
2010-02-20 23:59:05 +01:00
WriteAmmoToPacket ( & data );
2010-04-07 22:59:46 +02:00
if ( castFlags & CAST_FLAG_UNKNOWN_23 )
2010-02-20 23:59:05 +01:00
{
data << uint32 ( 0 );
data << uint32 ( 0 );
}
m_caster -> SendMessageToSet ( & data , true );
}
void Spell :: SendSpellGo ()
{
// not send invisible spell casting
2010-04-07 19:14:10 +02:00
if ( ! IsNeedSendToClient ())
2010-02-20 23:59:05 +01:00
return ;
2011-02-20 20:16:34 +01:00
//sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Sending SMSG_SPELL_GO id=%u", m_spellInfo->Id);
2010-02-20 23:59:05 +01:00
uint32 castFlags = CAST_FLAG_UNKNOWN_9 ;
// triggered spells with spell visual != 0
2011-07-31 19:03:06 +02:00
if (( IsTriggered () && ! m_spellInfo -> IsAutoRepeatRangedSpell ()) || m_triggeredByAuraSpell )
2010-02-20 23:59:05 +01:00
castFlags |= CAST_FLAG_PENDING ;
2010-12-19 05:15:47 +01:00
if ( m_spellInfo -> Attributes & SPELL_ATTR0_REQ_AMMO )
2010-02-20 23:59:05 +01:00
castFlags |= CAST_FLAG_AMMO ; // arrows/bullets visual
if (( m_caster -> GetTypeId () == TYPEID_PLAYER ||
2010-03-07 18:30:53 +01:00
( m_caster -> GetTypeId () == TYPEID_UNIT && m_caster -> ToCreature () -> isPet ()))
2011-07-26 23:09:28 +02:00
&& m_spellInfo -> PowerType != POWER_HEALTH )
2010-02-20 23:59:05 +01:00
castFlags |= CAST_FLAG_POWER_LEFT_SELF ; // should only be sent to self, but the current messaging doesn't make that possible
2010-04-07 19:14:10 +02:00
if (( m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-04-07 18:09:10 +02:00
&& ( m_caster -> getClass () == CLASS_DEATH_KNIGHT )
2011-07-26 23:09:28 +02:00
&& m_spellInfo -> RuneCostID
&& m_spellInfo -> PowerType == POWER_RUNE )
2010-02-20 23:59:05 +01:00
{
castFlags |= CAST_FLAG_UNKNOWN_19 ; // same as in SMSG_SPELL_START
castFlags |= CAST_FLAG_RUNE_LIST ; // rune cooldowns list
castFlags |= CAST_FLAG_UNKNOWN_9 ; // ??
}
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> HasEffect ( SPELL_EFFECT_ACTIVATE_RUNE ))
2010-02-20 23:59:05 +01:00
{
castFlags |= CAST_FLAG_RUNE_LIST ; // rune cooldowns list
castFlags |= CAST_FLAG_UNKNOWN_19 ; // same as in SMSG_SPELL_START
}
WorldPacket data ( SMSG_SPELL_GO , 50 ); // guess size
2010-04-07 19:14:10 +02:00
if ( m_CastItem )
2010-02-20 23:59:05 +01:00
data . append ( m_CastItem -> GetPackGUID ());
else
data . append ( m_caster -> GetPackGUID ());
data . append ( m_caster -> GetPackGUID ());
data << uint8 ( m_cast_count ); // pending spell cast?
data << uint32 ( m_spellInfo -> Id ); // spellId
data << uint32 ( castFlags ); // cast flags
data << uint32 ( getMSTime ()); // timestamp
WriteSpellGoTargets ( & data );
2011-06-23 13:28:52 +02:00
m_targets . Write ( data );
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( castFlags & CAST_FLAG_POWER_LEFT_SELF )
2011-07-26 23:09:28 +02:00
data << uint32 ( m_caster -> GetPower (( Powers ) m_spellInfo -> PowerType ));
2010-02-20 23:59:05 +01:00
2010-04-07 22:59:46 +02:00
if ( castFlags & CAST_FLAG_RUNE_LIST ) // rune cooldowns list
2010-02-20 23:59:05 +01:00
{
2011-04-07 23:13:35 +02:00
Player * player = m_caster -> ToPlayer ();
uint8 runeMaskInitial = m_runesState ;
uint8 runeMaskAfterCast = player -> GetRunesState ();
data << uint8 ( runeMaskInitial ); // runes state before
data << uint8 ( runeMaskAfterCast ); // runes state after
2010-02-20 23:59:05 +01:00
for ( uint8 i = 0 ; i < MAX_RUNES ; ++ i )
{
2011-04-07 23:13:35 +02:00
uint8 mask = ( 1 << i );
if ( mask & runeMaskInitial && ! ( mask & runeMaskAfterCast )) // usable before andon cooldown now...
{
// float casts ensure the division is performed on floats as we need float result
float baseCd = float ( player -> GetRuneBaseCooldown ( i ));
data << uint8 (( baseCd - float ( player -> GetRuneCooldown ( i ))) / baseCd * 255 ); // rune cooldown passed
}
2010-02-20 23:59:05 +01:00
}
}
2010-04-07 22:59:46 +02:00
if ( castFlags & CAST_FLAG_UNKNOWN_18 ) // unknown wotlk
2010-02-20 23:59:05 +01:00
{
data << float ( 0 );
data << uint32 ( 0 );
}
2010-04-07 22:59:46 +02:00
if ( castFlags & CAST_FLAG_AMMO )
2010-02-20 23:59:05 +01:00
WriteAmmoToPacket ( & data );
2010-04-07 22:59:46 +02:00
if ( castFlags & CAST_FLAG_UNKNOWN_20 ) // unknown wotlk
2010-02-20 23:59:05 +01:00
{
data << uint32 ( 0 );
data << uint32 ( 0 );
}
2011-06-23 13:28:52 +02:00
if ( m_targets . GetTargetMask () & TARGET_FLAG_DEST_LOCATION )
2010-02-20 23:59:05 +01:00
{
data << uint8 ( 0 );
}
m_caster -> SendMessageToSet ( & data , true );
}
2011-09-15 14:08:17 +02:00
void Spell :: WriteAmmoToPacket ( WorldPacket * data )
2010-02-20 23:59:05 +01:00
{
uint32 ammoInventoryType = 0 ;
uint32 ammoDisplayID = 0 ;
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
{
2011-09-15 14:08:17 +02:00
Item * pItem = m_caster -> ToPlayer () -> GetWeaponForAttack ( RANGED_ATTACK );
2010-04-07 19:14:10 +02:00
if ( pItem )
2010-02-20 23:59:05 +01:00
{
2011-04-28 22:42:33 +02:00
ammoInventoryType = pItem -> GetTemplate () -> InventoryType ;
2010-04-07 22:59:46 +02:00
if ( ammoInventoryType == INVTYPE_THROWN )
2011-04-28 22:42:33 +02:00
ammoDisplayID = pItem -> GetTemplate () -> DisplayInfoID ;
2010-02-20 23:59:05 +01:00
else
{
2010-03-07 15:20:19 +01:00
uint32 ammoID = m_caster -> ToPlayer () -> GetUInt32Value ( PLAYER_AMMO_ID );
2010-04-07 19:14:10 +02:00
if ( ammoID )
2010-02-20 23:59:05 +01:00
{
2011-09-15 14:08:17 +02:00
ItemTemplate const * pProto = sObjectMgr -> GetItemTemplate ( ammoID );
2010-04-07 19:14:10 +02:00
if ( pProto )
2010-02-20 23:59:05 +01:00
{
ammoDisplayID = pProto -> DisplayInfoID ;
ammoInventoryType = pProto -> InventoryType ;
}
}
2010-04-07 19:14:10 +02:00
else if ( m_caster -> HasAura ( 46699 )) // Requires No Ammo
2010-02-20 23:59:05 +01:00
{
ammoDisplayID = 5996 ; // normal arrow
ammoInventoryType = INVTYPE_AMMO ;
}
}
}
}
else
{
for ( uint8 i = 0 ; i < 3 ; ++ i )
{
2010-04-07 19:14:10 +02:00
if ( uint32 item_id = m_caster -> GetUInt32Value ( UNIT_VIRTUAL_ITEM_SLOT_ID + i ))
2010-02-20 23:59:05 +01:00
{
2011-06-11 22:35:29 +02:00
if ( ItemEntry const * itemEntry = sItemStore . LookupEntry ( item_id ))
2010-02-20 23:59:05 +01:00
{
2010-04-07 23:25:02 +02:00
if ( itemEntry -> Class == ITEM_CLASS_WEAPON )
2010-02-20 23:59:05 +01:00
{
2011-09-05 14:01:50 +02:00
switch ( itemEntry -> SubClass )
2010-02-20 23:59:05 +01:00
{
case ITEM_SUBCLASS_WEAPON_THROWN :
ammoDisplayID = itemEntry -> DisplayId ;
ammoInventoryType = itemEntry -> InventoryType ;
break ;
case ITEM_SUBCLASS_WEAPON_BOW :
case ITEM_SUBCLASS_WEAPON_CROSSBOW :
ammoDisplayID = 5996 ; // is this need fixing?
ammoInventoryType = INVTYPE_AMMO ;
break ;
case ITEM_SUBCLASS_WEAPON_GUN :
ammoDisplayID = 5998 ; // is this need fixing?
ammoInventoryType = INVTYPE_AMMO ;
break ;
}
2010-04-07 19:14:10 +02:00
if ( ammoDisplayID )
2010-02-20 23:59:05 +01:00
break ;
}
}
}
}
}
* data << uint32 ( ammoDisplayID );
* data << uint32 ( ammoInventoryType );
}
2011-09-15 14:08:17 +02:00
void Spell :: WriteSpellGoTargets ( WorldPacket * data )
2010-02-20 23:59:05 +01:00
{
// This function also fill data for channeled spells:
// m_needAliveTargetMask req for stop channelig if one target die
uint32 hit = m_UniqueGOTargetInfo . size (); // Always hits on GO
uint32 miss = 0 ;
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
{
if (( * ihit ). effectMask == 0 ) // No effect apply - all immuned add state
{
// possibly SPELL_MISS_IMMUNE2 for this??
ihit -> missCondition = SPELL_MISS_IMMUNE2 ;
++ miss ;
}
else if (( * ihit ). missCondition == SPELL_MISS_NONE )
++ hit ;
else
++ miss ;
}
* data << ( uint8 ) hit ;
for ( std :: list < TargetInfo >:: const_iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
{
if (( * ihit ). missCondition == SPELL_MISS_NONE ) // Add only hits
{
* data << uint64 ( ihit -> targetGUID );
2010-08-30 17:32:51 +02:00
m_channelTargetEffectMask |= ihit -> effectMask ;
2010-02-20 23:59:05 +01:00
}
}
for ( std :: list < GOTargetInfo >:: const_iterator ighit = m_UniqueGOTargetInfo . begin (); ighit != m_UniqueGOTargetInfo . end (); ++ ighit )
* data << uint64 ( ighit -> targetGUID ); // Always hits
* data << ( uint8 ) miss ;
for ( std :: list < TargetInfo >:: const_iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
{
2010-04-07 22:59:46 +02:00
if ( ihit -> missCondition != SPELL_MISS_NONE ) // Add only miss
2010-02-20 23:59:05 +01:00
{
* data << uint64 ( ihit -> targetGUID );
* data << uint8 ( ihit -> missCondition );
2010-04-07 22:59:46 +02:00
if ( ihit -> missCondition == SPELL_MISS_REFLECT )
2010-02-20 23:59:05 +01:00
* data << uint8 ( ihit -> reflectResult );
}
}
// Reset m_needAliveTargetMask for non channeled spell
2011-07-26 23:09:28 +02:00
if ( ! m_spellInfo -> IsChanneled ())
2010-08-30 17:32:51 +02:00
m_channelTargetEffectMask = 0 ;
2010-02-20 23:59:05 +01:00
}
void Spell :: SendLogExecute ()
{
WorldPacket data ( SMSG_SPELLLOGEXECUTE , ( 8 + 4 + 4 + 4 + 4 + 8 ));
2010-08-27 17:49:32 +02:00
data . append ( m_caster -> GetPackGUID ());
2010-02-20 23:59:05 +01:00
data << uint32 ( m_spellInfo -> Id );
2010-08-27 17:49:32 +02:00
uint8 effCount = 0 ;
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2010-02-20 23:59:05 +01:00
{
2010-08-27 17:49:32 +02:00
if ( m_effectExecuteData [ i ])
++ effCount ;
2010-02-20 23:59:05 +01:00
}
2010-08-27 17:49:32 +02:00
if ( ! effCount )
return ;
data << uint32 ( effCount );
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
{
if ( ! m_effectExecuteData [ i ])
continue ;
2011-07-26 23:09:28 +02:00
data << uint32 ( m_spellInfo -> Effects [ i ]. Effect ); // spell effect
2010-08-27 17:49:32 +02:00
data . append ( * m_effectExecuteData [ i ]);
2010-09-12 01:40:27 +02:00
2010-08-27 17:49:32 +02:00
delete m_effectExecuteData [ i ];
m_effectExecuteData [ i ] = NULL ;
}
2010-02-20 23:59:05 +01:00
m_caster -> SendMessageToSet ( & data , true );
}
2011-06-11 22:35:29 +02:00
void Spell :: ExecuteLogEffectTakeTargetPower ( uint8 effIndex , Unit * target , uint32 powerType , uint32 powerTaken , float gainMultiplier )
2010-08-27 17:49:32 +02:00
{
InitEffectExecuteData ( effIndex );
m_effectExecuteData [ effIndex ] -> append ( target -> GetPackGUID ());
* m_effectExecuteData [ effIndex ] << uint32 ( powerTaken );
2010-08-29 03:38:21 +02:00
* m_effectExecuteData [ effIndex ] << uint32 ( powerType );
2010-08-27 17:49:32 +02:00
* m_effectExecuteData [ effIndex ] << float ( gainMultiplier );
}
2011-06-11 22:35:29 +02:00
void Spell :: ExecuteLogEffectExtraAttacks ( uint8 effIndex , Unit * victim , uint32 attCount )
2010-08-27 17:49:32 +02:00
{
InitEffectExecuteData ( effIndex );
m_effectExecuteData [ effIndex ] -> append ( victim -> GetPackGUID ());
* m_effectExecuteData [ effIndex ] << uint32 ( attCount );
}
2011-06-11 22:35:29 +02:00
void Spell :: ExecuteLogEffectInterruptCast ( uint8 effIndex , Unit * victim , uint32 spellId )
2010-08-27 17:49:32 +02:00
{
InitEffectExecuteData ( effIndex );
m_effectExecuteData [ effIndex ] -> append ( victim -> GetPackGUID ());
* m_effectExecuteData [ effIndex ] << uint32 ( spellId );
}
2011-06-11 22:35:29 +02:00
void Spell :: ExecuteLogEffectDurabilityDamage ( uint8 effIndex , Unit * victim , uint32 /*itemslot*/ , uint32 damage )
2010-08-27 17:49:32 +02:00
{
InitEffectExecuteData ( effIndex );
m_effectExecuteData [ effIndex ] -> append ( victim -> GetPackGUID ());
2010-08-29 03:38:21 +02:00
* m_effectExecuteData [ effIndex ] << uint32 ( m_spellInfo -> Id );
2010-08-27 17:49:32 +02:00
* m_effectExecuteData [ effIndex ] << uint32 ( damage );
}
2011-09-15 14:08:17 +02:00
void Spell :: ExecuteLogEffectOpenLock ( uint8 effIndex , Object * obj )
2010-08-27 17:49:32 +02:00
{
InitEffectExecuteData ( effIndex );
m_effectExecuteData [ effIndex ] -> append ( obj -> GetPackGUID ());
}
void Spell :: ExecuteLogEffectCreateItem ( uint8 effIndex , uint32 entry )
{
InitEffectExecuteData ( effIndex );
* m_effectExecuteData [ effIndex ] << uint32 ( entry );
}
void Spell :: ExecuteLogEffectDestroyItem ( uint8 effIndex , uint32 entry )
{
InitEffectExecuteData ( effIndex );
* m_effectExecuteData [ effIndex ] << uint32 ( entry );
}
2011-09-15 14:08:17 +02:00
void Spell :: ExecuteLogEffectSummonObject ( uint8 effIndex , WorldObject * obj )
2010-08-27 17:49:32 +02:00
{
InitEffectExecuteData ( effIndex );
m_effectExecuteData [ effIndex ] -> append ( obj -> GetPackGUID ());
}
2011-09-15 14:08:17 +02:00
void Spell :: ExecuteLogEffectUnsummonObject ( uint8 effIndex , WorldObject * obj )
2010-08-27 17:49:32 +02:00
{
InitEffectExecuteData ( effIndex );
m_effectExecuteData [ effIndex ] -> append ( obj -> GetPackGUID ());
}
2011-06-11 22:35:29 +02:00
void Spell :: ExecuteLogEffectResurrect ( uint8 effIndex , Unit * target )
2010-08-27 17:49:32 +02:00
{
InitEffectExecuteData ( effIndex );
m_effectExecuteData [ effIndex ] -> append ( target -> GetPackGUID ());
}
2010-02-20 23:59:05 +01:00
void Spell :: SendInterrupted ( uint8 result )
{
WorldPacket data ( SMSG_SPELL_FAILURE , ( 8 + 4 + 1 ));
data . append ( m_caster -> GetPackGUID ());
data << uint8 ( m_cast_count );
data << uint32 ( m_spellInfo -> Id );
data << uint8 ( result );
m_caster -> SendMessageToSet ( & data , true );
data . Initialize ( SMSG_SPELL_FAILED_OTHER , ( 8 + 4 ));
data . append ( m_caster -> GetPackGUID ());
data << uint8 ( m_cast_count );
data << uint32 ( m_spellInfo -> Id );
data << uint8 ( result );
m_caster -> SendMessageToSet ( & data , true );
}
void Spell :: SendChannelUpdate ( uint32 time )
{
2010-04-07 19:14:10 +02:00
if ( time == 0 )
2010-02-20 23:59:05 +01:00
{
m_caster -> SetUInt64Value ( UNIT_FIELD_CHANNEL_OBJECT , 0 );
m_caster -> SetUInt32Value ( UNIT_CHANNEL_SPELL , 0 );
}
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
return ;
2010-04-07 22:59:46 +02:00
WorldPacket data ( MSG_CHANNEL_UPDATE , 8 + 4 );
2010-02-20 23:59:05 +01:00
data . append ( m_caster -> GetPackGUID ());
data << uint32 ( time );
m_caster -> SendMessageToSet ( & data , true );
}
void Spell :: SendChannelStart ( uint32 duration )
{
2011-08-26 12:05:47 +02:00
uint64 channelTarget = m_targets . GetObjectTargetGUID ();
2010-02-20 23:59:05 +01:00
2010-04-07 22:59:46 +02:00
WorldPacket data ( MSG_CHANNEL_START , ( 8 + 4 + 4 ));
2010-02-20 23:59:05 +01:00
data . append ( m_caster -> GetPackGUID ());
data << uint32 ( m_spellInfo -> Id );
data << uint32 ( duration );
m_caster -> SendMessageToSet ( & data , true );
m_timer = duration ;
2011-08-12 13:22:53 +02:00
if ( channelTarget )
m_caster -> SetUInt64Value ( UNIT_FIELD_CHANNEL_OBJECT , channelTarget );
2010-02-20 23:59:05 +01:00
m_caster -> SetUInt32Value ( UNIT_CHANNEL_SPELL , m_spellInfo -> Id );
}
void Spell :: SendResurrectRequest ( Player * target )
{
2011-07-12 10:43:58 +02:00
// get ressurector name for creature resurrections, otherwise packet will be not accepted
// for player resurrections the name is looked up by guid
char const * resurrectorName = m_caster -> GetTypeId () == TYPEID_PLAYER ? "" : m_caster -> GetNameForLocaleIdx ( target -> GetSession () -> GetSessionDbLocaleIndex ());
2010-02-20 23:59:05 +01:00
2011-07-12 10:43:58 +02:00
WorldPacket data ( SMSG_RESURRECT_REQUEST , ( 8 + 4 + strlen ( resurrectorName ) + 1 + 1 + 1 + 4 ));
data << uint64 ( m_caster -> GetGUID ()); // resurrector guid
data << uint32 ( strlen ( resurrectorName ) + 1 );
2010-02-20 23:59:05 +01:00
2011-07-12 10:43:58 +02:00
data << resurrectorName ;
data << uint8 ( 0 ); // null terminator
2010-02-20 23:59:05 +01:00
2011-07-12 10:43:58 +02:00
data << uint8 ( m_caster -> GetTypeId () == TYPEID_PLAYER ? 0 : 1 ); // "you'll be afflicted with resurrection sickness"
// override delay sent with SMSG_CORPSE_RECLAIM_DELAY, set instant resurrection for spells with this attribute
if ( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_IGNORE_RESURRECTION_TIMER )
data << uint32 ( 0 );
2010-02-20 23:59:05 +01:00
target -> GetSession () -> SendPacket ( & data );
}
void Spell :: TakeCastItem ()
{
2010-04-07 19:14:10 +02:00
if ( ! m_CastItem || m_caster -> GetTypeId () != TYPEID_PLAYER )
2010-02-20 23:59:05 +01:00
return ;
// not remove cast item at triggered spell (equipping, weapon damage, etc)
2011-07-31 19:03:06 +02:00
if ( _triggeredCastFlags & TRIGGERED_IGNORE_CAST_ITEM )
2010-02-20 23:59:05 +01:00
return ;
2011-09-15 14:08:17 +02:00
ItemTemplate const * proto = m_CastItem -> GetTemplate ();
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( ! proto )
2010-02-20 23:59:05 +01:00
{
// This code is to avoid a crash
// I'm not sure, if this is really an error, but I guess every item needs a prototype
2011-04-29 20:47:02 +02:00
sLog -> outError ( "Cast item has no item prototype highId=%d, lowId=%d" , m_CastItem -> GetGUIDHigh (), m_CastItem -> GetGUIDLow ());
2010-02-20 23:59:05 +01:00
return ;
}
bool expendable = false ;
bool withoutCharges = false ;
for ( int i = 0 ; i < MAX_ITEM_PROTO_SPELLS ; ++ i )
{
if ( proto -> Spells [ i ]. SpellId )
{
// item has limited charges
if ( proto -> Spells [ i ]. SpellCharges )
{
if ( proto -> Spells [ i ]. SpellCharges < 0 )
expendable = true ;
int32 charges = m_CastItem -> GetSpellCharges ( i );
// item has charges left
if ( charges )
{
( charges > 0 ) ? -- charges : ++ charges ; // abs(charges) less at 1 after use
if ( proto -> Stackable == 1 )
m_CastItem -> SetSpellCharges ( i , charges );
m_CastItem -> SetState ( ITEM_CHANGED , ( Player * ) m_caster );
}
// all charges used
withoutCharges = ( charges == 0 );
}
}
}
if ( expendable && withoutCharges )
{
uint32 count = 1 ;
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> DestroyItemCount ( m_CastItem , count , true );
2010-02-20 23:59:05 +01:00
2011-06-23 13:28:52 +02:00
// prevent crash at access to deleted m_targets.GetItemTarget
if ( m_CastItem == m_targets . GetItemTarget ())
m_targets . SetItemTarget ( NULL );
2010-02-20 23:59:05 +01:00
m_CastItem = NULL ;
}
}
void Spell :: TakePower ()
{
2010-04-07 19:14:10 +02:00
if ( m_CastItem || m_triggeredByAuraSpell )
2010-02-20 23:59:05 +01:00
return ;
2011-09-05 14:01:50 +02:00
Powers powerType = Powers ( m_spellInfo -> PowerType );
2010-02-20 23:59:05 +01:00
bool hit = true ;
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-02-20 23:59:05 +01:00
{
2011-09-05 14:01:50 +02:00
if ( powerType == POWER_RAGE || powerType == POWER_ENERGY || powerType == POWER_RUNE )
2011-07-28 23:44:39 +02:00
if ( uint64 targetGUID = m_targets . GetUnitTargetGUID ())
2010-02-20 23:59:05 +01:00
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
2010-04-07 19:14:10 +02:00
if ( ihit -> targetGUID == targetGUID )
2010-02-20 23:59:05 +01:00
{
2010-04-08 08:20:08 +02:00
if ( ihit -> missCondition != SPELL_MISS_NONE && ihit -> missCondition != SPELL_MISS_MISS /* && ihit->targetGUID != m_caster->GetGUID()*/ )
2010-02-20 23:59:05 +01:00
hit = false ;
if ( ihit -> missCondition != SPELL_MISS_NONE )
{
//lower spell cost on fail (by talent aura)
2011-09-15 14:08:17 +02:00
if ( Player * modOwner = m_caster -> ToPlayer () -> GetSpellModOwner ())
2010-02-20 23:59:05 +01:00
modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_SPELL_COST_REFUND_ON_FAIL , m_powerCost );
}
break ;
}
}
2011-04-07 23:13:35 +02:00
if ( powerType == POWER_RUNE )
2010-02-20 23:59:05 +01:00
{
2011-04-07 23:13:35 +02:00
TakeRunePower ( hit );
2010-02-20 23:59:05 +01:00
return ;
}
if ( ! m_powerCost )
return ;
// health as power used
2011-09-05 14:01:50 +02:00
if ( powerType == POWER_HEALTH )
2010-02-20 23:59:05 +01:00
{
2010-04-07 22:59:46 +02:00
m_caster -> ModifyHealth ( - ( int32 ) m_powerCost );
2010-02-20 23:59:05 +01:00
return ;
}
2011-09-05 14:01:50 +02:00
if ( powerType >= MAX_POWERS )
2010-02-20 23:59:05 +01:00
{
2011-09-05 14:01:50 +02:00
sLog -> outError ( "Spell::TakePower: Unknown power type '%d'" , powerType );
2010-02-20 23:59:05 +01:00
return ;
}
2010-04-07 19:14:10 +02:00
if ( hit )
2010-02-20 23:59:05 +01:00
m_caster -> ModifyPower ( powerType , - m_powerCost );
else
m_caster -> ModifyPower ( powerType , - irand ( 0 , m_powerCost / 4 ));
// Set the five second timer
if ( powerType == POWER_MANA && m_powerCost > 0 )
m_caster -> SetLastManaUse ( getMSTime ());
}
void Spell :: TakeAmmo ()
{
2010-04-07 19:14:10 +02:00
if ( m_attackType == RANGED_ATTACK && m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-02-20 23:59:05 +01:00
{
2011-09-15 14:08:17 +02:00
Item * pItem = m_caster -> ToPlayer () -> GetWeaponForAttack ( RANGED_ATTACK );
2010-02-20 23:59:05 +01:00
// wands don't have ammo
2011-04-28 22:42:33 +02:00
if ( ! pItem || pItem -> IsBroken () || pItem -> GetTemplate () -> SubClass == ITEM_SUBCLASS_WEAPON_WAND )
2010-02-20 23:59:05 +01:00
return ;
2011-04-28 22:42:33 +02:00
if ( pItem -> GetTemplate () -> InventoryType == INVTYPE_THROWN )
2010-02-20 23:59:05 +01:00
{
2010-04-07 23:25:02 +02:00
if ( pItem -> GetMaxStackCount () == 1 )
2010-02-20 23:59:05 +01:00
{
// decrease durability for non-stackable throw weapon
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> DurabilityPointLossForEquipSlot ( EQUIPMENT_SLOT_RANGED );
2010-02-20 23:59:05 +01:00
}
else
{
// decrease items amount for stackable throw weapon
uint32 count = 1 ;
2010-04-07 22:59:46 +02:00
m_caster -> ToPlayer () -> DestroyItemCount ( pItem , count , true );
2010-02-20 23:59:05 +01:00
}
}
2010-04-07 19:14:10 +02:00
else if ( uint32 ammo = m_caster -> ToPlayer () -> GetUInt32Value ( PLAYER_AMMO_ID ))
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> DestroyItemCount ( ammo , 1 , true );
2010-02-20 23:59:05 +01:00
}
}
SpellCastResult Spell :: CheckRuneCost ( uint32 runeCostID )
{
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> PowerType != POWER_RUNE || ! runeCostID )
2010-02-20 23:59:05 +01:00
return SPELL_CAST_OK ;
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
2010-02-20 23:59:05 +01:00
return SPELL_CAST_OK ;
2011-09-15 14:08:17 +02:00
Player * plr = ( Player * ) m_caster ;
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( plr -> getClass () != CLASS_DEATH_KNIGHT )
2010-02-20 23:59:05 +01:00
return SPELL_CAST_OK ;
2011-09-15 14:08:17 +02:00
SpellRuneCostEntry const * src = sSpellRuneCostStore . LookupEntry ( runeCostID );
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( ! src )
2010-02-20 23:59:05 +01:00
return SPELL_CAST_OK ;
2010-04-07 19:14:10 +02:00
if ( src -> NoRuneCost ())
2010-02-20 23:59:05 +01:00
return SPELL_CAST_OK ;
int32 runeCost [ NUM_RUNE_TYPES ]; // blood, frost, unholy, death
for ( uint32 i = 0 ; i < RUNE_DEATH ; ++ i )
{
runeCost [ i ] = src -> RuneCost [ i ];
2010-04-07 19:14:10 +02:00
if ( Player * modOwner = m_caster -> GetSpellModOwner ())
2010-02-20 23:59:05 +01:00
modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_COST , runeCost [ i ], this );
}
runeCost [ RUNE_DEATH ] = MAX_RUNES ; // calculated later
for ( uint32 i = 0 ; i < MAX_RUNES ; ++ i )
{
RuneType rune = plr -> GetCurrentRune ( i );
2010-04-07 19:14:10 +02:00
if (( plr -> GetRuneCooldown ( i ) == 0 ) && ( runeCost [ rune ] > 0 ))
2010-02-20 23:59:05 +01:00
runeCost [ rune ] -- ;
}
for ( uint32 i = 0 ; i < RUNE_DEATH ; ++ i )
2010-04-07 19:14:10 +02:00
if ( runeCost [ i ] > 0 )
2010-02-20 23:59:05 +01:00
runeCost [ RUNE_DEATH ] += runeCost [ i ];
2010-04-07 19:14:10 +02:00
if ( runeCost [ RUNE_DEATH ] > MAX_RUNES )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_POWER ; // not sure if result code is correct
return SPELL_CAST_OK ;
}
2011-04-07 23:13:35 +02:00
void Spell :: TakeRunePower ( bool didHit )
2010-02-20 23:59:05 +01:00
{
2011-07-27 11:00:39 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER || m_caster -> getClass () != CLASS_DEATH_KNIGHT )
2010-02-20 23:59:05 +01:00
return ;
2011-09-15 14:08:17 +02:00
SpellRuneCostEntry const * runeCostData = sSpellRuneCostStore . LookupEntry ( m_spellInfo -> RuneCostID );
2011-04-07 23:13:35 +02:00
if ( ! runeCostData || ( runeCostData -> NoRuneCost () && runeCostData -> NoRunicPowerGain ()))
2010-02-20 23:59:05 +01:00
return ;
2011-09-15 14:08:17 +02:00
Player * player = m_caster -> ToPlayer ();
2011-07-27 11:00:39 +02:00
m_runesState = player -> GetRunesState (); // store previous state
2010-02-20 23:59:05 +01:00
int32 runeCost [ NUM_RUNE_TYPES ]; // blood, frost, unholy, death
for ( uint32 i = 0 ; i < RUNE_DEATH ; ++ i )
{
2011-04-07 23:13:35 +02:00
runeCost [ i ] = runeCostData -> RuneCost [ i ];
2010-04-07 19:14:10 +02:00
if ( Player * modOwner = m_caster -> GetSpellModOwner ())
2010-02-20 23:59:05 +01:00
modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_COST , runeCost [ i ], this );
}
runeCost [ RUNE_DEATH ] = 0 ; // calculated later
for ( uint32 i = 0 ; i < MAX_RUNES ; ++ i )
{
2011-04-07 23:13:35 +02:00
RuneType rune = player -> GetCurrentRune ( i );
if ( ! player -> GetRuneCooldown ( i ) && runeCost [ rune ] > 0 )
2010-02-20 23:59:05 +01:00
{
2011-07-27 11:00:39 +02:00
player -> SetRuneCooldown ( i , didHit ? player -> GetRuneBaseCooldown ( i ) : uint32 ( RUNE_MISS_COOLDOWN ));
2011-04-07 23:13:35 +02:00
player -> SetLastUsedRune ( rune );
2010-02-20 23:59:05 +01:00
runeCost [ rune ] -- ;
}
}
runeCost [ RUNE_DEATH ] = runeCost [ RUNE_BLOOD ] + runeCost [ RUNE_UNHOLY ] + runeCost [ RUNE_FROST ];
2010-04-07 19:14:10 +02:00
if ( runeCost [ RUNE_DEATH ] > 0 )
2010-02-20 23:59:05 +01:00
{
for ( uint32 i = 0 ; i < MAX_RUNES ; ++ i )
{
2011-04-07 23:13:35 +02:00
RuneType rune = player -> GetCurrentRune ( i );
if ( ! player -> GetRuneCooldown ( i ) && rune == RUNE_DEATH )
2010-02-20 23:59:05 +01:00
{
2011-07-27 11:00:39 +02:00
player -> SetRuneCooldown ( i , didHit ? player -> GetRuneBaseCooldown ( i ) : uint32 ( RUNE_MISS_COOLDOWN ));
2011-04-07 23:13:35 +02:00
player -> SetLastUsedRune ( rune );
2010-02-20 23:59:05 +01:00
runeCost [ rune ] -- ;
2011-04-07 23:13:35 +02:00
// keep Death Rune type if missed
if ( didHit )
player -> RestoreBaseRune ( i );
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( runeCost [ RUNE_DEATH ] == 0 )
2010-02-20 23:59:05 +01:00
break ;
}
}
}
// you can gain some runic power when use runes
2011-04-07 23:13:35 +02:00
if ( didHit )
if ( int32 rp = int32 ( runeCostData -> runePowerGain * sWorld -> getRate ( RATE_POWER_RUNICPOWER_INCOME )))
player -> ModifyPower ( POWER_RUNIC_POWER , int32 ( rp ));
2010-02-20 23:59:05 +01:00
}
void Spell :: TakeReagents ()
{
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
return ;
2011-09-05 14:01:50 +02:00
ItemTemplate const * castItemTemplate = m_CastItem
? m_CastItem -> GetTemplate ()
: NULL ;
2010-02-20 23:59:05 +01:00
// do not take reagents for these item casts
2011-09-05 14:01:50 +02:00
if ( castItemTemplate && castItemTemplate -> Flags & ITEM_PROTO_FLAG_TRIGGERED_CAST )
2010-02-20 23:59:05 +01:00
return ;
2011-09-05 14:01:50 +02:00
Player * p_caster = m_caster -> ToPlayer ();
2010-02-20 23:59:05 +01:00
if ( p_caster -> CanNoReagentCast ( m_spellInfo ))
return ;
2010-09-28 08:41:24 +03:00
for ( uint32 x = 0 ; x < MAX_SPELL_REAGENTS ; ++ x )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( m_spellInfo -> Reagent [ x ] <= 0 )
2010-02-20 23:59:05 +01:00
continue ;
uint32 itemid = m_spellInfo -> Reagent [ x ];
uint32 itemcount = m_spellInfo -> ReagentCount [ x ];
// if CastItem is also spell reagent
2011-09-05 14:01:50 +02:00
if ( castItemTemplate && castItemTemplate -> ItemId == itemid )
2010-02-20 23:59:05 +01:00
{
2011-09-05 14:01:50 +02:00
for ( int s = 0 ; s < MAX_ITEM_PROTO_SPELLS ; ++ s )
2010-02-20 23:59:05 +01:00
{
2011-09-05 14:01:50 +02:00
// CastItem will be used up and does not count as reagent
int32 charges = m_CastItem -> GetSpellCharges ( s );
if ( castItemTemplate -> Spells [ s ]. SpellCharges < 0 && abs ( charges ) < 2 )
2010-02-20 23:59:05 +01:00
{
2011-09-05 14:01:50 +02:00
++ itemcount ;
break ;
2010-02-20 23:59:05 +01:00
}
}
2011-09-05 14:01:50 +02:00
m_CastItem = NULL ;
2010-02-20 23:59:05 +01:00
}
2011-06-23 13:28:52 +02:00
// if GetItemTarget is also spell reagent
if ( m_targets . GetItemTargetEntry () == itemid )
m_targets . SetItemTarget ( NULL );
2010-02-20 23:59:05 +01:00
p_caster -> DestroyItemCount ( itemid , itemcount , true );
}
}
2011-07-26 23:09:28 +02:00
void Spell :: HandleThreatSpells ()
2010-02-20 23:59:05 +01:00
{
2011-08-21 12:00:36 +02:00
if ( m_UniqueTargetInfo . empty ())
2010-02-20 23:59:05 +01:00
return ;
2011-08-21 12:00:36 +02:00
if (( m_spellInfo -> AttributesEx & SPELL_ATTR1_NO_THREAT ) ||
( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO ))
2010-02-20 23:59:05 +01:00
return ;
2011-08-21 12:00:36 +02:00
float threat = 0.0f ;
if ( SpellThreatEntry const * threatEntry = sSpellMgr -> GetSpellThreatEntry ( m_spellInfo -> Id ))
{
if ( threatEntry -> apPctMod != 0.0f )
threat += threatEntry -> apPctMod * m_caster -> GetTotalAttackPowerValue ( BASE_ATTACK );
threat += threatEntry -> flatMod ;
}
else if (( m_spellInfo -> AttributesCu & SPELL_ATTR0_CU_NO_INITIAL_THREAT ) == 0 )
threat += m_spellInfo -> SpellLevel ;
2010-02-20 23:59:05 +01:00
2011-08-21 12:00:36 +02:00
// past this point only multiplicative effects occur
if ( threat == 0.0f )
2010-02-20 23:59:05 +01:00
return ;
2011-08-21 12:00:36 +02:00
// since 2.0.1 threat from positive effects also is distributed among all targets, so the overall caused threat is at most the defined bonus
threat /= m_UniqueTargetInfo . size ();
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
{
if ( ihit -> missCondition != SPELL_MISS_NONE )
continue ;
Unit * target = ObjectAccessor :: GetUnit ( * m_caster , ihit -> targetGUID );
if ( ! target )
continue ;
// positive spells distribute threat among all units that are in combat with target, like healing
if ( m_spellInfo -> _IsPositiveSpell ())
target -> getHostileRefManager (). threatAssist ( m_caster , threat , m_spellInfo );
// for negative spells threat gets distributed among affected targets
else
{
if ( ! target -> CanHaveThreatList ())
continue ;
2010-02-20 23:59:05 +01:00
2011-08-21 12:00:36 +02:00
target -> AddThreat ( m_caster , threat , m_spellInfo -> GetSchoolMask (), m_spellInfo );
}
}
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell %u, added an additional %f threat for %s %u target(s)" , m_spellInfo -> Id , threat , m_spellInfo -> _IsPositiveSpell () ? "assisting" : "harming" , uint32 ( m_UniqueTargetInfo . size ()));
2010-02-20 23:59:05 +01:00
}
2011-09-25 13:29:17 +02:00
void Spell :: HandleEffects ( Unit * pUnitTarget , Item * pItemTarget , GameObject * pGOTarget , uint32 i , SpellEffectHandleMode mode )
2010-02-20 23:59:05 +01:00
{
2011-09-25 13:29:17 +02:00
effectHandleMode = mode ;
2010-02-20 23:59:05 +01:00
unitTarget = pUnitTarget ;
itemTarget = pItemTarget ;
gameObjTarget = pGOTarget ;
2011-07-26 23:09:28 +02:00
uint8 eff = m_spellInfo -> Effects [ i ]. Effect ;
2010-02-20 23:59:05 +01:00
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell: %u Effect : %u" , m_spellInfo -> Id , eff );
2010-02-20 23:59:05 +01:00
2011-09-25 13:29:17 +02:00
// we do not need DamageMultiplier here.
2010-07-25 16:23:57 +02:00
damage = CalculateDamage ( i , NULL );
2011-09-25 13:29:17 +02:00
bool preventDefault = CallScriptEffectHandlers (( SpellEffIndex ) i , mode );
2010-07-24 22:41:42 +02:00
2010-08-19 14:31:31 +02:00
if ( ! preventDefault && eff < TOTAL_SPELL_EFFECTS )
2010-02-20 23:59:05 +01:00
{
2010-08-27 19:36:27 +02:00
( this ->* SpellEffects [ eff ])(( SpellEffIndex ) i );
2010-02-20 23:59:05 +01:00
}
}
SpellCastResult Spell :: CheckCast ( bool strict )
{
2010-09-08 07:01:55 +03:00
// check death state
2011-08-30 00:13:53 +02:00
if ( ! m_caster -> isAlive () && ! ( m_spellInfo -> Attributes & SPELL_ATTR0_PASSIVE ) && ! (( m_spellInfo -> Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD ) || ( IsTriggered () && ! m_triggeredByAuraSpell )))
2010-09-08 07:01:55 +03:00
return SPELL_FAILED_CASTER_DEAD ;
2010-02-20 23:59:05 +01:00
// check cooldowns to prevent cheating
2010-12-19 05:15:47 +01:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER && ! ( m_spellInfo -> Attributes & SPELL_ATTR0_PASSIVE ))
2010-02-20 23:59:05 +01:00
{
//can cast triggered (by aura only?) spells while have this flag
2011-07-31 19:03:06 +02:00
if ( ! ( _triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE ) && m_caster -> ToPlayer () -> HasFlag ( PLAYER_FLAGS , PLAYER_ALLOW_ONLY_ABILITY ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_SPELL_IN_PROGRESS ;
2011-07-23 03:30:43 +07:00
if ( m_caster -> ToPlayer () -> HasSpellCooldown ( m_spellInfo -> Id ))
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( m_triggeredByAuraSpell )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_DONT_REPORT ;
else
return SPELL_FAILED_NOT_READY ;
}
}
2011-06-11 13:08:23 +02:00
if ( m_spellInfo -> AttributesEx7 & SPELL_ATTR7_IS_CHEAT_SPELL && ! m_caster -> HasFlag ( UNIT_FIELD_FLAGS_2 , UNIT_FLAG2_ALLOW_CHEAT_SPELLS ))
2011-10-02 16:23:52 +02:00
{
m_customError = SPELL_CUSTOM_ERROR_GM_ONLY ;
return SPELL_FAILED_CUSTOM_ERROR ;
}
2011-06-11 13:02:54 +02:00
2011-02-22 17:02:47 +06:00
// Check global cooldown
2011-07-31 19:03:06 +02:00
if ( strict && ! ( _triggeredCastFlags & TRIGGERED_IGNORE_GCD ) && HasGlobalCooldown ())
2011-02-22 17:02:47 +06:00
return SPELL_FAILED_NOT_READY ;
2011-07-31 19:03:06 +02:00
// only triggered spells can be processed an ended battleground
if ( ! IsTriggered () && m_caster -> GetTypeId () == TYPEID_PLAYER )
2011-06-11 22:35:29 +02:00
if ( Battleground * bg = m_caster -> ToPlayer () -> GetBattleground ())
2010-04-07 19:14:10 +02:00
if ( bg -> GetStatus () == STATUS_WAIT_LEAVE )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_DONT_REPORT ;
2011-06-12 02:30:32 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER && VMAP :: VMapFactory :: createOrGetVMapManager () -> isLineOfSightCalcEnabled ())
2010-06-05 00:59:25 +02:00
{
2011-06-12 02:30:32 +02:00
if ( m_spellInfo -> Attributes & SPELL_ATTR0_OUTDOORS_ONLY &&
2010-06-05 00:59:25 +02:00
! m_caster -> GetMap () -> IsOutdoors ( m_caster -> GetPositionX (), m_caster -> GetPositionY (), m_caster -> GetPositionZ ()))
return SPELL_FAILED_ONLY_OUTDOORS ;
2011-06-12 02:30:32 +02:00
if ( m_spellInfo -> Attributes & SPELL_ATTR0_INDOORS_ONLY &&
2010-06-05 00:59:25 +02:00
m_caster -> GetMap () -> IsOutdoors ( m_caster -> GetPositionX (), m_caster -> GetPositionY (), m_caster -> GetPositionZ ()))
return SPELL_FAILED_ONLY_INDOORS ;
}
2010-02-20 23:59:05 +01:00
// only check at first call, Stealth auras are already removed at second call
// for now, ignore triggered spells
2011-07-31 19:03:06 +02:00
if ( strict && ! ( _triggeredCastFlags & TRIGGERED_IGNORE_SHAPESHIFT ))
2010-02-20 23:59:05 +01:00
{
bool checkForm = true ;
// Ignore form req aura
Unit :: AuraEffectList const & ignore = m_caster -> GetAuraEffectsByType ( SPELL_AURA_MOD_IGNORE_SHAPESHIFT );
for ( Unit :: AuraEffectList :: const_iterator i = ignore . begin (); i != ignore . end (); ++ i )
{
if ( ! ( * i ) -> IsAffectedOnSpell ( m_spellInfo ))
continue ;
checkForm = false ;
break ;
}
if ( checkForm )
{
// Cannot be used in this stance/form
2011-07-26 23:09:28 +02:00
SpellCastResult shapeError = m_spellInfo -> CheckShapeshift ( m_caster -> GetShapeshiftForm ());
2010-04-07 19:14:10 +02:00
if ( shapeError != SPELL_CAST_OK )
2010-02-20 23:59:05 +01:00
return shapeError ;
2010-12-19 05:15:47 +01:00
if (( m_spellInfo -> Attributes & SPELL_ATTR0_ONLY_STEALTHED ) && ! ( m_caster -> HasStealthAura ()))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ONLY_STEALTHED ;
}
}
2011-10-02 16:23:52 +02:00
Unit :: AuraEffectList const & blockSpells = m_caster -> GetAuraEffectsByType ( SPELL_AURA_BLOCK_SPELL_FAMILY );
for ( Unit :: AuraEffectList :: const_iterator blockItr = blockSpells . begin (); blockItr != blockSpells . end (); ++ blockItr )
if (( * blockItr ) -> GetMiscValue () == m_spellInfo -> SpellFamilyName )
return SPELL_FAILED_SPELL_UNAVAILABLE ;
bool reqCombat = true ;
2010-02-20 23:59:05 +01:00
Unit :: AuraEffectList const & stateAuras = m_caster -> GetAuraEffectsByType ( SPELL_AURA_ABILITY_IGNORE_AURASTATE );
for ( Unit :: AuraEffectList :: const_iterator j = stateAuras . begin (); j != stateAuras . end (); ++ j )
{
2010-04-07 19:14:10 +02:00
if (( * j ) -> IsAffectedOnSpell ( m_spellInfo ))
2010-02-20 23:59:05 +01:00
{
2010-09-08 10:59:10 +02:00
m_needComboPoints = false ;
2010-04-07 23:25:02 +02:00
if (( * j ) -> GetMiscValue () == 1 )
2010-02-20 23:59:05 +01:00
{
reqCombat = false ;
break ;
}
}
}
// caster state requirements
// not for triggered spells (needed by execute)
2011-07-31 19:03:06 +02:00
if ( ! ( _triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE ))
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> CasterAuraState && ! m_caster -> HasAuraState ( AuraStateType ( m_spellInfo -> CasterAuraState ), m_spellInfo , m_caster ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CASTER_AURASTATE ;
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> CasterAuraStateNot && m_caster -> HasAuraState ( AuraStateType ( m_spellInfo -> CasterAuraStateNot ), m_spellInfo , m_caster ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CASTER_AURASTATE ;
// Note: spell 62473 requres casterAuraSpell = triggering spell
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> CasterAuraSpell && ! m_caster -> HasAura ( sSpellMgr -> GetSpellIdForDifficulty ( m_spellInfo -> CasterAuraSpell , m_caster )))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CASTER_AURASTATE ;
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> ExcludeCasterAuraSpell && m_caster -> HasAura ( sSpellMgr -> GetSpellIdForDifficulty ( m_spellInfo -> ExcludeCasterAuraSpell , m_caster )))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CASTER_AURASTATE ;
2011-07-26 23:09:28 +02:00
if ( reqCombat && m_caster -> isInCombat () && ! m_spellInfo -> CanBeUsedInCombat ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_AFFECTING_COMBAT ;
}
// cancel autorepeat spells if cast start when moving
// (not wand currently autorepeat cast delayed to moving stop anyway in spell update code)
2010-04-07 22:59:46 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER && m_caster -> ToPlayer () -> isMoving ())
2010-02-20 23:59:05 +01:00
{
// skip stuck spell to allow use it in falling case and apply spell limitations at movement
2011-07-26 23:09:28 +02:00
if (( ! m_caster -> HasUnitMovementFlag ( MOVEMENTFLAG_FALLING ) || m_spellInfo -> Effects [ 0 ]. Effect != SPELL_EFFECT_STUCK ) &&
2010-04-07 22:59:46 +02:00
( IsAutoRepeat () || ( m_spellInfo -> AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED ) != 0 ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_MOVING ;
}
2011-07-31 19:03:06 +02:00
Vehicle * vehicle = m_caster -> GetVehicle ();
if ( vehicle && ! ( _triggeredCastFlags & TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE ))
2011-07-30 20:36:19 +02:00
{
uint16 checkMask = 0 ;
for ( uint8 effIndex = EFFECT_0 ; effIndex < MAX_SPELL_EFFECTS ; ++ effIndex )
{
SpellEffectInfo const * effInfo = & m_spellInfo -> Effects [ effIndex ];
if ( effInfo -> ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT )
{
SpellShapeshiftEntry const * shapeShiftEntry = sSpellShapeshiftStore . LookupEntry ( effInfo -> MiscValue );
if ( shapeShiftEntry && ( shapeShiftEntry -> flags1 & 1 ) == 0 ) // unk flag
checkMask |= VEHICLE_SEAT_FLAG_UNCONTROLLED ;
break ;
}
}
if ( m_spellInfo -> HasAura ( SPELL_AURA_MOUNTED ))
checkMask |= VEHICLE_SEAT_FLAG_CAN_CAST_MOUNT_SPELL ;
if ( ! checkMask )
checkMask = VEHICLE_SEAT_FLAG_CAN_ATTACK ;
VehicleSeatEntry const * vehicleSeat = vehicle -> GetSeatForPassenger ( m_caster );
if ( ! ( m_spellInfo -> AttributesEx6 & SPELL_ATTR6_CASTABLE_WHILE_ON_VEHICLE ) && ! ( m_spellInfo -> Attributes & SPELL_ATTR0_CASTABLE_WHILE_MOUNTED )
&& ( vehicleSeat -> m_flags & checkMask ) != checkMask )
return SPELL_FAILED_DONT_REPORT ;
}
2011-09-06 11:21:40 +02:00
// Don't check explicit target for passive spells (workaround) (check should be skipped only for learn case)
// those spells may have incorrect target entries or not filled at all (for example 15332)
// such spells when learned are not targeting anyone using targeting system, they should apply directly to caster instead
// also, such casts shouldn't be sent to client
2011-09-16 22:17:20 +02:00
if ( ! (( m_spellInfo -> Attributes & SPELL_ATTR0_PASSIVE ) && ( ! m_targets . GetUnitTarget () || m_targets . GetUnitTarget () == m_caster )))
2011-08-26 12:05:47 +02:00
{
2011-09-03 20:38:23 +02:00
// Check explicit target for m_originalCaster - todo: get rid of such workarounds
SpellCastResult castResult = m_spellInfo -> CheckExplicitTarget ( m_originalCaster ? m_originalCaster : m_caster , m_targets . GetObjectTarget (), m_targets . GetItemTarget ());
2011-08-26 12:05:47 +02:00
if ( castResult != SPELL_CAST_OK )
return castResult ;
}
2011-08-24 08:07:59 +02:00
if ( Unit * target = m_targets . GetUnitTarget ())
2010-02-20 23:59:05 +01:00
{
2011-08-24 08:07:59 +02:00
SpellCastResult castResult = m_spellInfo -> CheckTarget ( m_caster , target , false );
if ( castResult != SPELL_CAST_OK )
return castResult ;
2010-02-20 23:59:05 +01:00
2011-08-19 14:53:40 +02:00
if ( target != m_caster )
{
// Must be behind the target
if (( m_spellInfo -> AttributesCu & SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET ) && target -> HasInArc ( static_cast < float > ( M_PI ), m_caster ))
return SPELL_FAILED_NOT_BEHIND ;
2010-02-20 23:59:05 +01:00
2011-08-19 14:53:40 +02:00
// Target must be facing you
if (( m_spellInfo -> AttributesCu & SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER ) && ! target -> HasInArc ( static_cast < float > ( M_PI ), m_caster ))
return SPELL_FAILED_NOT_INFRONT ;
2010-02-20 23:59:05 +01:00
2011-08-19 14:53:40 +02:00
if ( ! ( m_spellInfo -> AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS ) && VMAP :: VMapFactory :: checkSpellForLoS ( m_spellInfo -> Id ) && ! m_caster -> IsWithinLOSInMap ( target ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_LINE_OF_SIGHT ;
}
2011-08-19 14:53:40 +02:00
else
2010-02-20 23:59:05 +01:00
{
if ( m_caster -> GetTypeId () == TYPEID_PLAYER ) // Target - is player caster
{
2010-03-25 17:09:05 +01:00
// Lay on Hands - cannot be self-cast on paladin with Forbearance or after using Avenging Wrath
if ( m_spellInfo -> SpellFamilyName == SPELLFAMILY_PALADIN && m_spellInfo -> SpellFamilyFlags [ 0 ] & 0x0008000 )
2010-03-26 22:21:33 +01:00
if ( target -> HasAura ( 61988 )) // Immunity shield marker
2010-04-07 18:09:10 +02:00
return SPELL_FAILED_TARGET_AURASTATE ;
2010-02-20 23:59:05 +01:00
}
}
2011-09-16 22:17:20 +02:00
}
2010-02-20 23:59:05 +01:00
2011-09-16 22:17:20 +02:00
// check pet presence
for ( int j = 0 ; j < MAX_SPELL_EFFECTS ; ++ j )
{
if ( m_spellInfo -> Effects [ j ]. TargetA . GetTarget () == TARGET_UNIT_PET )
2010-02-20 23:59:05 +01:00
{
2011-09-16 22:17:20 +02:00
if ( ! m_caster -> GetGuardianPet ())
2010-02-20 23:59:05 +01:00
{
2011-09-16 22:17:20 +02:00
if ( m_triggeredByAuraSpell ) // not report pet not existence for triggered spells
return SPELL_FAILED_DONT_REPORT ;
else
return SPELL_FAILED_NO_PET ;
2010-02-20 23:59:05 +01:00
}
2011-09-16 22:17:20 +02:00
break ;
2010-02-20 23:59:05 +01:00
}
}
// Spell casted only on battleground
2010-12-19 05:15:47 +01:00
if (( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_BATTLEGROUND ) && m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-08-08 04:37:24 +02:00
if ( ! m_caster -> ToPlayer () -> InBattleground ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ONLY_BATTLEGROUNDS ;
// do not allow spells to be cast in arenas
2010-12-19 05:15:47 +01:00
// - with greater than 10 min CD without SPELL_ATTR4_USABLE_IN_ARENA flag
// - with SPELL_ATTR4_NOT_USABLE_IN_ARENA flag
if (( m_spellInfo -> AttributesEx4 & SPELL_ATTR4_NOT_USABLE_IN_ARENA ) ||
2011-07-26 23:09:28 +02:00
( m_spellInfo -> GetRecoveryTime () > 10 * MINUTE * IN_MILLISECONDS && ! ( m_spellInfo -> AttributesEx4 & SPELL_ATTR4_USABLE_IN_ARENA )))
2010-04-07 19:14:10 +02:00
if ( MapEntry const * mapEntry = sMapStore . LookupEntry ( m_caster -> GetMapId ()))
if ( mapEntry -> IsBattleArena ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NOT_IN_ARENA ;
// zone check
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () == TYPEID_UNIT || ! m_caster -> ToPlayer () -> isGameMaster ())
2010-02-20 23:59:05 +01:00
{
uint32 zone , area ;
2011-04-29 20:47:02 +02:00
m_caster -> GetZoneAndAreaId ( zone , area );
2010-02-20 23:59:05 +01:00
2011-07-26 23:09:28 +02:00
SpellCastResult locRes = m_spellInfo -> CheckLocation ( m_caster -> GetMapId (), zone , area ,
2010-03-07 15:20:19 +01:00
m_caster -> GetTypeId () == TYPEID_PLAYER ? m_caster -> ToPlayer () : NULL );
2010-04-07 19:14:10 +02:00
if ( locRes != SPELL_CAST_OK )
2010-02-20 23:59:05 +01:00
return locRes ;
}
// not let players cast spells at mount (and let do it to creatures)
2011-07-31 19:03:06 +02:00
if ( m_caster -> IsMounted () && m_caster -> GetTypeId () == TYPEID_PLAYER && ! ( _triggeredCastFlags & TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE ) &&
2011-07-26 23:09:28 +02:00
! m_spellInfo -> IsPassive () && ! ( m_spellInfo -> Attributes & SPELL_ATTR0_CASTABLE_WHILE_MOUNTED ))
2010-02-20 23:59:05 +01:00
{
if ( m_caster -> isInFlight ())
return SPELL_FAILED_NOT_ON_TAXI ;
else
return SPELL_FAILED_NOT_MOUNTED ;
}
2010-10-22 17:22:38 -03:00
SpellCastResult castResult = SPELL_CAST_OK ;
2010-02-20 23:59:05 +01:00
// always (except passive spells) check items (focus object can be required for any type casts)
2011-07-26 23:09:28 +02:00
if ( ! m_spellInfo -> IsPassive ())
2010-02-20 23:59:05 +01:00
{
2010-10-22 17:22:38 -03:00
castResult = CheckItems ();
2010-04-07 19:14:10 +02:00
if ( castResult != SPELL_CAST_OK )
2010-02-20 23:59:05 +01:00
return castResult ;
}
2010-10-22 17:22:38 -03:00
// Triggered spells also have range check
// TODO: determine if there is some flag to enable/disable the check
castResult = CheckRange ( strict );
if ( castResult != SPELL_CAST_OK )
return castResult ;
2011-07-31 19:03:06 +02:00
if ( ! ( _triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST ))
2010-02-20 23:59:05 +01:00
{
castResult = CheckPower ();
2010-04-07 19:14:10 +02:00
if ( castResult != SPELL_CAST_OK )
2010-02-20 23:59:05 +01:00
return castResult ;
2011-07-31 19:03:06 +02:00
}
2011-08-01 11:17:34 +02:00
2011-07-31 19:03:06 +02:00
if ( ! ( _triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS ))
{
2010-02-20 23:59:05 +01:00
castResult = CheckCasterAuras ();
2010-04-07 19:14:10 +02:00
if ( castResult != SPELL_CAST_OK )
2010-02-20 23:59:05 +01:00
return castResult ;
}
2011-03-04 21:18:38 +01:00
// script hook
castResult = CallScriptCheckCastHandlers ();
if ( castResult != SPELL_CAST_OK )
return castResult ;
2010-09-28 08:41:24 +03:00
for ( int i = 0 ; i < MAX_SPELL_EFFECTS ; i ++ )
2010-02-20 23:59:05 +01:00
{
// for effects of spells that have only one target
2011-09-05 14:01:50 +02:00
switch ( m_spellInfo -> Effects [ i ]. Effect )
2010-02-20 23:59:05 +01:00
{
case SPELL_EFFECT_DUMMY :
{
if ( m_spellInfo -> Id == 51582 ) // Rocket Boots Engaged
{
2010-04-07 19:14:10 +02:00
if ( m_caster -> IsInWater ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ONLY_ABOVEWATER ;
}
2010-04-07 19:14:10 +02:00
else if ( m_spellInfo -> SpellIconID == 156 ) // Holy Shock
2010-02-20 23:59:05 +01:00
{
// spell different for friends and enemies
// hurt version required facing
2011-06-23 13:28:52 +02:00
if ( m_targets . GetUnitTarget () && ! m_caster -> IsFriendlyTo ( m_targets . GetUnitTarget ()) && ! m_caster -> HasInArc ( static_cast < float > ( M_PI ), m_targets . GetUnitTarget ()))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_UNIT_NOT_INFRONT ;
}
else if ( m_spellInfo -> SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo -> SpellFamilyFlags [ 0 ] == 0x2000 ) // Death Coil (DeathKnight)
{
2011-06-23 13:28:52 +02:00
Unit * target = m_targets . GetUnitTarget ();
2010-02-20 23:59:05 +01:00
if ( ! target || ( target -> IsFriendlyTo ( m_caster ) && target -> GetCreatureType () != CREATURE_TYPE_UNDEAD ))
return SPELL_FAILED_BAD_TARGETS ;
}
else if ( m_spellInfo -> Id == 19938 ) // Awaken Peon
{
2011-09-15 14:08:17 +02:00
Unit * unit = m_targets . GetUnitTarget ();
2010-04-07 19:14:10 +02:00
if ( ! unit || ! unit -> HasAura ( 17743 ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
}
else if ( m_spellInfo -> Id == 52264 ) // Deliver Stolen Horse
{
2011-04-29 20:47:02 +02:00
if ( ! m_caster -> FindNearestCreature ( 28653 , 5 ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_OUT_OF_RANGE ;
}
else if ( m_spellInfo -> Id == 31789 ) // Righteous Defense
{
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
return SPELL_FAILED_DONT_REPORT ;
2011-06-23 13:28:52 +02:00
Unit * target = m_targets . GetUnitTarget ();
2010-02-20 23:59:05 +01:00
if ( ! target || ! target -> IsFriendlyTo ( m_caster ) || target -> getAttackers (). empty ())
return SPELL_FAILED_BAD_TARGETS ;
}
break ;
}
case SPELL_EFFECT_LEARN_SPELL :
{
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
return SPELL_FAILED_BAD_TARGETS ;
2011-07-27 12:35:59 +02:00
if ( m_spellInfo -> Effects [ i ]. TargetA . GetTarget () != TARGET_UNIT_PET )
2010-02-20 23:59:05 +01:00
break ;
2010-03-07 15:20:19 +01:00
Pet * pet = m_caster -> ToPlayer () -> GetPet ();
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( ! pet )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_PET ;
2011-09-15 14:08:17 +02:00
SpellInfo const * learn_spellproto = sSpellMgr -> GetSpellInfo ( m_spellInfo -> Effects [ i ]. TriggerSpell );
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( ! learn_spellproto )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NOT_KNOWN ;
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> SpellLevel > pet -> getLevel ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_LOWLEVEL ;
break ;
}
case SPELL_EFFECT_LEARN_PET_SPELL :
{
2011-09-24 02:01:18 +02:00
// check target only for unit target case
if ( Unit * unitTarget = m_targets . GetUnitTarget ())
{
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
return SPELL_FAILED_BAD_TARGETS ;
2010-02-20 23:59:05 +01:00
2011-09-24 02:01:18 +02:00
Pet * pet = unitTarget -> ToPet ();
if ( ! pet || pet -> GetOwner () != m_caster )
return SPELL_FAILED_BAD_TARGETS ;
2010-02-20 23:59:05 +01:00
2011-09-24 02:01:18 +02:00
SpellInfo const * learn_spellproto = sSpellMgr -> GetSpellInfo ( m_spellInfo -> Effects [ i ]. TriggerSpell );
2010-02-20 23:59:05 +01:00
2011-09-24 02:01:18 +02:00
if ( ! learn_spellproto )
return SPELL_FAILED_NOT_KNOWN ;
2010-02-20 23:59:05 +01:00
2011-09-24 02:01:18 +02:00
if ( m_spellInfo -> SpellLevel > pet -> getLevel ())
return SPELL_FAILED_LOWLEVEL ;
}
2010-02-20 23:59:05 +01:00
break ;
}
case SPELL_EFFECT_APPLY_GLYPH :
{
2011-07-26 23:09:28 +02:00
uint32 glyphId = m_spellInfo -> Effects [ i ]. MiscValue ;
2011-09-15 14:08:17 +02:00
if ( GlyphPropertiesEntry const * gp = sGlyphPropertiesStore . LookupEntry ( glyphId ))
2010-04-07 19:14:10 +02:00
if ( m_caster -> HasAura ( gp -> SpellId ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_UNIQUE_GLYPH ;
break ;
}
case SPELL_EFFECT_FEED_PET :
{
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
return SPELL_FAILED_BAD_TARGETS ;
2011-06-23 13:28:52 +02:00
Item * foodItem = m_targets . GetItemTarget ();
2010-04-07 19:14:10 +02:00
if ( ! foodItem )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
2010-03-07 15:20:19 +01:00
Pet * pet = m_caster -> ToPlayer () -> GetPet ();
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( ! pet )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_PET ;
2011-04-28 22:42:33 +02:00
if ( ! pet -> HaveInDiet ( foodItem -> GetTemplate ()))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_WRONG_PET_FOOD ;
2011-04-28 22:42:33 +02:00
if ( ! pet -> GetCurrentFoodBenefitLevel ( foodItem -> GetTemplate () -> ItemLevel ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_FOOD_LOWLEVEL ;
2010-04-07 19:14:10 +02:00
if ( m_caster -> isInCombat () || pet -> isInCombat ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_AFFECTING_COMBAT ;
break ;
}
case SPELL_EFFECT_POWER_BURN :
case SPELL_EFFECT_POWER_DRAIN :
{
// Can be area effect, Check only for players and not check if target - caster (spell can have multiply drain/burn effects)
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2011-06-23 13:28:52 +02:00
if ( Unit * target = m_targets . GetUnitTarget ())
2011-07-26 23:09:28 +02:00
if ( target != m_caster && target -> getPowerType () != Powers ( m_spellInfo -> Effects [ i ]. MiscValue ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
break ;
}
case SPELL_EFFECT_CHARGE :
{
if ( m_spellInfo -> SpellFamilyName == SPELLFAMILY_WARRIOR )
{
// Warbringer - can't be handled in proc system - should be done before checkcast root check and charge effect process
if ( strict && m_caster -> IsScriptOverriden ( m_spellInfo , 6953 ))
m_caster -> RemoveMovementImpairingAuras ();
}
2010-12-17 13:43:24 +01:00
if ( m_caster -> HasUnitState ( UNIT_STAT_ROOT ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ROOTED ;
break ;
}
case SPELL_EFFECT_SKINNING :
{
2011-06-23 13:28:52 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER || ! m_targets . GetUnitTarget () || m_targets . GetUnitTarget () -> GetTypeId () != TYPEID_UNIT )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
2011-06-23 13:28:52 +02:00
if ( ! ( m_targets . GetUnitTarget () -> GetUInt32Value ( UNIT_FIELD_FLAGS ) & UNIT_FLAG_SKINNABLE ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_TARGET_UNSKINNABLE ;
2011-06-23 13:28:52 +02:00
Creature * creature = m_targets . GetUnitTarget () -> ToCreature ();
2010-03-30 23:39:18 +02:00
if ( creature -> GetCreatureType () != CREATURE_TYPE_CRITTER && ! creature -> loot . isLooted ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_TARGET_NOT_LOOTED ;
uint32 skill = creature -> GetCreatureInfo () -> GetRequiredLootSkill ();
2010-03-07 15:20:19 +01:00
int32 skillValue = m_caster -> ToPlayer () -> GetSkillValue ( skill );
2011-06-23 13:28:52 +02:00
int32 TargetLevel = m_targets . GetUnitTarget () -> getLevel ();
2010-02-20 23:59:05 +01:00
int32 ReqValue = ( skillValue < 100 ? ( TargetLevel - 10 ) * 10 : TargetLevel * 5 );
if ( ReqValue > skillValue )
return SPELL_FAILED_LOW_CASTLEVEL ;
// chance for fail at orange skinning attempt
2010-04-07 22:59:46 +02:00
if (( m_selfContainer && ( * m_selfContainer ) == this ) &&
2010-12-23 23:25:44 +01:00
skillValue < sWorld -> GetConfigMaxSkillValue () &&
2010-04-07 22:59:46 +02:00
( ReqValue < 0 ? 0 : ReqValue ) > irand ( skillValue - 25 , skillValue + 37 ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_TRY_AGAIN ;
break ;
}
case SPELL_EFFECT_OPEN_LOCK :
{
2011-08-16 19:44:18 +02:00
if ( m_spellInfo -> Effects [ i ]. TargetA . GetTarget () != TARGET_GAMEOBJECT_TARGET &&
m_spellInfo -> Effects [ i ]. TargetA . GetTarget () != TARGET_GAMEOBJECT_ITEM_TARGET )
2010-02-20 23:59:05 +01:00
break ;
2010-04-07 22:59:46 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER // only players can open locks, gather etc.
2011-08-16 19:44:18 +02:00
// we need a go target in case of TARGET_GAMEOBJECT_TARGET
|| ( m_spellInfo -> Effects [ i ]. TargetA . GetTarget () == TARGET_GAMEOBJECT_TARGET && ! m_targets . GetGOTarget ()))
2010-08-04 10:34:30 +02:00
return SPELL_FAILED_BAD_TARGETS ;
2011-09-15 14:08:17 +02:00
Item * pTempItem = NULL ;
2011-06-23 13:28:52 +02:00
if ( m_targets . GetTargetMask () & TARGET_FLAG_TRADE_ITEM )
2010-08-04 10:34:30 +02:00
{
if ( TradeData * pTrade = m_caster -> ToPlayer () -> GetTradeData ())
2011-06-23 13:28:52 +02:00
pTempItem = pTrade -> GetTraderData () -> GetItem ( TradeSlots ( m_targets . GetItemTargetGUID ()));
2010-08-04 10:34:30 +02:00
}
2011-06-23 13:28:52 +02:00
else if ( m_targets . GetTargetMask () & TARGET_FLAG_ITEM )
pTempItem = m_caster -> ToPlayer () -> GetItemByGuid ( m_targets . GetItemTargetGUID ());
2010-08-04 10:34:30 +02:00
2011-08-16 19:44:18 +02:00
// we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM_TARGET
if ( m_spellInfo -> Effects [ i ]. TargetA . GetTarget () == TARGET_GAMEOBJECT_ITEM_TARGET &&
2011-06-23 13:28:52 +02:00
! m_targets . GetGOTarget () &&
2011-04-28 22:42:33 +02:00
( ! pTempItem || ! pTempItem -> GetTemplate () -> LockID || ! pTempItem -> IsLocked ()))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
2011-06-23 13:28:52 +02:00
if ( m_spellInfo -> Id != 1842 || ( m_targets . GetGOTarget () &&
m_targets . GetGOTarget () -> GetGOInfo () -> type != GAMEOBJECT_TYPE_TRAP ))
2010-08-08 04:37:24 +02:00
if ( m_caster -> ToPlayer () -> InBattleground () && // In Battleground players can use only flags and banners
! m_caster -> ToPlayer () -> CanUseBattlegroundObject ())
2010-05-23 18:20:10 -03:00
return SPELL_FAILED_TRY_AGAIN ;
2010-02-20 23:59:05 +01:00
// get the lock entry
uint32 lockId = 0 ;
2011-06-23 13:28:52 +02:00
if ( GameObject * go = m_targets . GetGOTarget ())
2010-02-20 23:59:05 +01:00
{
lockId = go -> GetGOInfo () -> GetLockId ();
if ( ! lockId )
return SPELL_FAILED_BAD_TARGETS ;
}
2011-06-23 13:28:52 +02:00
else if ( Item * itm = m_targets . GetItemTarget ())
2011-04-28 22:42:33 +02:00
lockId = itm -> GetTemplate () -> LockID ;
2010-02-20 23:59:05 +01:00
SkillType skillId = SKILL_NONE ;
int32 reqSkillValue = 0 ;
int32 skillValue = 0 ;
// check lock compatibility
SpellCastResult res = CanOpenLock ( i , lockId , skillId , reqSkillValue , skillValue );
2010-04-07 19:14:10 +02:00
if ( res != SPELL_CAST_OK )
2010-02-20 23:59:05 +01:00
return res ;
// chance for fail at orange mining/herb/LockPicking gathering attempt
// second check prevent fail at rechecks
2010-04-07 19:14:10 +02:00
if ( skillId != SKILL_NONE && ( ! m_selfContainer || (( * m_selfContainer ) != this )))
2010-02-20 23:59:05 +01:00
{
bool canFailAtMax = skillId != SKILL_HERBALISM && skillId != SKILL_MINING ;
// chance for failure in orange gather / lockpick (gathering skill can't fail at maxskill)
2010-12-23 23:25:44 +01:00
if (( canFailAtMax || skillValue < sWorld -> GetConfigMaxSkillValue ()) && reqSkillValue > irand ( skillValue - 25 , skillValue + 37 ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_TRY_AGAIN ;
}
break ;
}
case SPELL_EFFECT_SUMMON_DEAD_PET :
{
2011-09-15 14:08:17 +02:00
Creature * pet = m_caster -> GetGuardianPet ();
2010-04-07 19:14:10 +02:00
if ( ! pet )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_PET ;
2010-04-07 19:14:10 +02:00
if ( pet -> isAlive ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ALREADY_HAVE_SUMMON ;
break ;
}
// This is generic summon effect
case SPELL_EFFECT_SUMMON :
{
2011-09-15 14:08:17 +02:00
SummonPropertiesEntry const * SummonProperties = sSummonPropertiesStore . LookupEntry ( m_spellInfo -> Effects [ i ]. MiscValueB );
2010-04-07 19:14:10 +02:00
if ( ! SummonProperties )
2010-02-20 23:59:05 +01:00
break ;
2011-09-05 14:01:50 +02:00
switch ( SummonProperties -> Category )
2010-02-20 23:59:05 +01:00
{
case SUMMON_CATEGORY_PET :
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetPetGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ALREADY_HAVE_SUMMON ;
case SUMMON_CATEGORY_PUPPET :
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetCharmGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ALREADY_HAVE_CHARM ;
break ;
}
break ;
}
2010-07-20 22:55:28 +02:00
case SPELL_EFFECT_CREATE_TAMED_PET :
{
2011-06-23 13:28:52 +02:00
if ( m_targets . GetUnitTarget ())
2010-07-20 22:55:28 +02:00
{
2011-06-23 13:28:52 +02:00
if ( m_targets . GetUnitTarget () -> GetTypeId () != TYPEID_PLAYER )
2010-07-20 22:55:28 +02:00
return SPELL_FAILED_BAD_TARGETS ;
2011-06-23 13:28:52 +02:00
if ( m_targets . GetUnitTarget () -> GetPetGUID ())
2010-07-20 22:55:28 +02:00
return SPELL_FAILED_ALREADY_HAVE_SUMMON ;
}
break ;
}
2010-02-20 23:59:05 +01:00
case SPELL_EFFECT_SUMMON_PET :
{
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetPetGUID ()) //let warlock do a replacement summon
2010-02-20 23:59:05 +01:00
{
2010-04-07 23:25:02 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER && m_caster -> getClass () == CLASS_WARLOCK )
2010-02-20 23:59:05 +01:00
{
if ( strict ) //starting cast, trigger pet stun (cast by pet so it doesn't attack player)
2010-04-07 19:14:10 +02:00
if ( Pet * pet = m_caster -> ToPlayer () -> GetPet ())
2010-02-20 23:59:05 +01:00
pet -> CastSpell ( pet , 32752 , true , NULL , NULL , pet -> GetGUID ());
}
else
return SPELL_FAILED_ALREADY_HAVE_SUMMON ;
}
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetCharmGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ALREADY_HAVE_CHARM ;
break ;
}
case SPELL_EFFECT_SUMMON_PLAYER :
{
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
2010-04-07 19:14:10 +02:00
if ( ! m_caster -> ToPlayer () -> GetSelection ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
2011-07-27 12:14:27 +02:00
Player * target = ObjectAccessor :: FindPlayer ( m_caster -> ToPlayer () -> GetSelection ());
2011-08-03 09:28:12 -07:00
if ( ! target || m_caster -> ToPlayer () == target || ( ! target -> IsInSameRaidWith ( m_caster -> ToPlayer ()) && m_spellInfo -> Id != 48955 )) // refer-a-friend spell
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
// check if our map is dungeon
2011-03-09 23:07:50 +01:00
MapEntry const * map = sMapStore . LookupEntry ( m_caster -> GetMapId ());
if ( map -> IsDungeon ())
2010-02-20 23:59:05 +01:00
{
2011-03-09 23:07:50 +01:00
uint32 mapId = m_caster -> GetMap () -> GetId ();
Difficulty difficulty = m_caster -> GetMap () -> GetDifficulty ();
if ( map -> IsRaid ())
if ( InstancePlayerBind * targetBind = target -> GetBoundInstance ( mapId , difficulty ))
2011-09-15 00:02:45 +02:00
if ( InstancePlayerBind * casterBind = m_caster -> ToPlayer () -> GetBoundInstance ( mapId , difficulty ))
if ( targetBind -> perm && targetBind -> save != casterBind -> save )
return SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE ;
2011-03-09 23:07:50 +01:00
2011-04-28 22:16:13 +02:00
InstanceTemplate const * instance = sObjectMgr -> GetInstanceTemplate ( mapId );
2010-04-07 19:14:10 +02:00
if ( ! instance )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_TARGET_NOT_IN_INSTANCE ;
2011-03-09 23:07:50 +01:00
if ( ! target -> Satisfy ( sObjectMgr -> GetAccessRequirement ( mapId , difficulty ), mapId ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
}
break ;
}
2011-08-03 09:28:12 -07:00
// RETURN HERE
case SPELL_EFFECT_SUMMON_RAF_FRIEND :
{
2011-09-29 12:43:05 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
2011-08-03 09:28:12 -07:00
return SPELL_FAILED_BAD_TARGETS ;
Player * playerCaster = m_caster -> ToPlayer ();
2011-08-12 13:22:53 +02:00
//
2011-09-29 12:43:05 +02:00
if ( ! ( playerCaster -> GetSelection ()))
2011-08-03 09:28:12 -07:00
return SPELL_FAILED_BAD_TARGETS ;
Player * target = ObjectAccessor :: FindPlayer ( playerCaster -> GetSelection ());
if ( ! target ||
! ( target -> GetSession () -> GetRecruiterId () == playerCaster -> GetSession () -> GetAccountId () || target -> GetSession () -> GetAccountId () == playerCaster -> GetSession () -> GetRecruiterId ()))
return SPELL_FAILED_BAD_TARGETS ;
break ;
}
2010-02-20 23:59:05 +01:00
case SPELL_EFFECT_LEAP :
case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER :
{
//Do not allow to cast it before BG starts.
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2011-09-15 14:08:17 +02:00
if ( Battleground const * bg = m_caster -> ToPlayer () -> GetBattleground ())
2010-04-07 19:14:10 +02:00
if ( bg -> GetStatus () != STATUS_IN_PROGRESS )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_TRY_AGAIN ;
break ;
}
case SPELL_EFFECT_STEAL_BENEFICIAL_BUFF :
{
2011-06-23 13:28:52 +02:00
if ( m_targets . GetUnitTarget () == m_caster )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
break ;
}
2010-05-09 08:39:25 +02:00
case SPELL_EFFECT_LEAP_BACK :
{
2010-05-21 10:24:51 +02:00
// Spell 781 (Disengage) requires player to be in combat
if ( m_caster -> GetTypeId () == TYPEID_PLAYER && m_spellInfo -> Id == 781 && ! m_caster -> isInCombat ())
return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW ;
2011-06-23 13:28:52 +02:00
Unit * target = m_targets . GetUnitTarget ();
2010-12-17 13:43:24 +01:00
if ( m_caster == target && m_caster -> HasUnitState ( UNIT_STAT_ROOT ))
2010-05-21 10:24:51 +02:00
{
2010-05-21 12:25:03 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-05-21 10:24:51 +02:00
return SPELL_FAILED_ROOTED ;
else
return SPELL_FAILED_DONT_REPORT ;
}
2010-05-09 08:39:25 +02:00
break ;
}
2010-10-16 17:53:33 +03:00
case SPELL_EFFECT_TALENT_SPEC_SELECT :
// can't change during already started arena/battleground
2011-01-12 02:06:06 +01:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
if ( Battleground const * bg = m_caster -> ToPlayer () -> GetBattleground ())
if ( bg -> GetStatus () == STATUS_IN_PROGRESS )
return SPELL_FAILED_NOT_IN_BATTLEGROUND ;
2010-10-16 17:53:33 +03:00
break ;
2010-05-21 10:24:51 +02:00
default :
break ;
2010-02-20 23:59:05 +01:00
}
}
2010-09-28 08:41:24 +03:00
for ( int i = 0 ; i < MAX_SPELL_EFFECTS ; i ++ )
2010-02-20 23:59:05 +01:00
{
2011-09-05 14:01:50 +02:00
switch ( m_spellInfo -> Effects [ i ]. ApplyAuraName )
2010-02-20 23:59:05 +01:00
{
case SPELL_AURA_DUMMY :
{
//custom check
2011-09-05 14:01:50 +02:00
switch ( m_spellInfo -> Id )
2010-02-20 23:59:05 +01:00
{
// Tag Murloc
case 30877 :
{
2011-06-23 13:28:52 +02:00
Unit * target = m_targets . GetUnitTarget ();
2010-02-20 23:59:05 +01:00
if ( ! target || target -> GetEntry () != 17326 )
return SPELL_FAILED_BAD_TARGETS ;
break ;
}
case 61336 :
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER || ! m_caster -> ToPlayer () -> IsInFeralForm ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ONLY_SHAPESHIFT ;
break ;
case 1515 :
{
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
return SPELL_FAILED_BAD_TARGETS ;
2011-06-23 13:28:52 +02:00
if ( ! m_targets . GetUnitTarget () || m_targets . GetUnitTarget () -> GetTypeId () == TYPEID_PLAYER )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_IMPLICIT_TARGETS ;
2011-06-23 13:28:52 +02:00
Creature * target = m_targets . GetUnitTarget () -> ToCreature ();
2010-02-20 23:59:05 +01:00
if ( target -> getLevel () > m_caster -> getLevel ())
return SPELL_FAILED_HIGHLEVEL ;
// use SMSG_PET_TAME_FAILURE?
2010-03-07 15:20:19 +01:00
if ( ! target -> GetCreatureInfo () -> isTameable ( m_caster -> ToPlayer () -> CanTameExoticPets ()))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetPetGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ALREADY_HAVE_SUMMON ;
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetCharmGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ALREADY_HAVE_CHARM ;
break ;
}
case 44795 : // Parachute
{
float x , y , z ;
m_caster -> GetPosition ( x , y , z );
2010-06-05 00:59:25 +02:00
float ground_Z = m_caster -> GetMap () -> GetHeight ( x , y , z );
2010-02-20 23:59:05 +01:00
if ( fabs ( ground_Z - z ) < 0.1f )
return SPELL_FAILED_DONT_REPORT ;
break ;
}
default :
break ;
}
break ;
}
case SPELL_AURA_MOD_POSSESS_PET :
{
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_PET ;
2011-09-15 14:08:17 +02:00
Pet * pet = m_caster -> ToPlayer () -> GetPet ();
2010-04-07 19:14:10 +02:00
if ( ! pet )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_PET ;
2010-04-07 19:14:10 +02:00
if ( pet -> GetCharmerGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CHARMED ;
break ;
}
case SPELL_AURA_MOD_POSSESS :
case SPELL_AURA_MOD_CHARM :
case SPELL_AURA_AOE_CHARM :
{
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetCharmerGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CHARMED ;
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ i ]. ApplyAuraName == SPELL_AURA_MOD_CHARM
|| m_spellInfo -> Effects [ i ]. ApplyAuraName == SPELL_AURA_MOD_POSSESS )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetPetGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ALREADY_HAVE_SUMMON ;
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetCharmGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ALREADY_HAVE_CHARM ;
}
2011-06-23 13:28:52 +02:00
if ( Unit * target = m_targets . GetUnitTarget ())
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( target -> GetTypeId () == TYPEID_UNIT && target -> ToCreature () -> IsVehicle ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_IMPLICIT_TARGETS ;
2010-07-20 01:42:14 +02:00
if ( target -> IsMounted ())
return SPELL_FAILED_CANT_BE_CHARMED ;
2010-04-07 19:14:10 +02:00
if ( target -> GetCharmerGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CHARMED ;
int32 damage = CalculateDamage ( i , target );
2010-04-07 19:14:10 +02:00
if ( damage && int32 ( target -> getLevel ()) > damage )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_HIGHLEVEL ;
}
break ;
}
case SPELL_AURA_MOUNTED :
{
if ( m_caster -> IsInWater ())
return SPELL_FAILED_ONLY_ABOVEWATER ;
// Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells
2011-07-31 19:03:06 +02:00
bool allowMount = ! m_caster -> GetMap () -> IsDungeon () || m_caster -> GetMap () -> IsBattlegroundOrArena ();
2011-09-15 14:08:17 +02:00
InstanceTemplate const * it = sObjectMgr -> GetInstanceTemplate ( m_caster -> GetMapId ());
2010-03-21 18:17:20 +01:00
if ( it )
2011-07-31 19:03:06 +02:00
allowMount = it -> AllowMount ;
if ( m_caster -> GetTypeId () == TYPEID_PLAYER && ! allowMount && ! m_spellInfo -> AreaGroupId )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_MOUNTS_ALLOWED ;
2010-12-09 17:03:42 +06:00
if ( m_caster -> IsInDisallowedMountForm ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NOT_SHAPESHIFT ;
break ;
}
case SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS :
{
2011-06-23 13:28:52 +02:00
if ( ! m_targets . GetUnitTarget ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_IMPLICIT_TARGETS ;
// can be casted at non-friendly unit or own pet/charm
2011-06-23 13:28:52 +02:00
if ( m_caster -> IsFriendlyTo ( m_targets . GetUnitTarget ()))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_TARGET_FRIENDLY ;
break ;
}
case SPELL_AURA_FLY :
case SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED :
{
// not allow cast fly spells if not have req. skills (all spells is self target)
// allow always ghost flight spells
if ( m_originalCaster && m_originalCaster -> GetTypeId () == TYPEID_PLAYER && m_originalCaster -> isAlive ())
{
2010-06-16 19:58:40 +02:00
if ( AreaTableEntry const * pArea = GetAreaEntryByAreaID ( m_originalCaster -> GetAreaId ()))
2011-06-28 13:05:15 +02:00
if ( pArea -> flags & AREA_FLAG_NO_FLY_ZONE )
2011-07-31 19:03:06 +02:00
return ( _triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR ) ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_NOT_HERE ;
2010-02-20 23:59:05 +01:00
}
break ;
}
case SPELL_AURA_PERIODIC_MANA_LEECH :
{
2011-06-23 13:28:52 +02:00
if ( ! m_targets . GetUnitTarget ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_IMPLICIT_TARGETS ;
if ( m_caster -> GetTypeId () != TYPEID_PLAYER || m_CastItem )
break ;
2011-06-23 13:28:52 +02:00
if ( m_targets . GetUnitTarget () -> getPowerType () != POWER_MANA )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
break ;
}
default :
break ;
}
}
2010-06-25 13:15:51 +02:00
// check trade slot case (last, for allow catch any another cast problems)
2011-06-23 13:28:52 +02:00
if ( m_targets . GetTargetMask () & TARGET_FLAG_TRADE_ITEM )
2010-06-25 13:15:51 +02:00
{
2010-11-04 21:59:27 +01:00
if ( m_CastItem )
return SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW ;
2010-06-25 13:15:51 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
return SPELL_FAILED_NOT_TRADING ;
TradeData * my_trade = m_caster -> ToPlayer () -> GetTradeData ();
if ( ! my_trade )
return SPELL_FAILED_NOT_TRADING ;
2011-06-23 13:28:52 +02:00
TradeSlots slot = TradeSlots ( m_targets . GetItemTargetGUID ());
2010-06-25 13:15:51 +02:00
if ( slot != TRADE_SLOT_NONTRADED )
2010-08-04 10:34:30 +02:00
return SPELL_FAILED_BAD_TARGETS ;
2010-06-25 13:15:51 +02:00
2011-07-31 19:03:06 +02:00
if ( ! IsTriggered ())
2010-06-25 13:15:51 +02:00
if ( my_trade -> GetSpell ())
return SPELL_FAILED_ITEM_ALREADY_ENCHANTED ;
}
2010-09-08 01:35:36 +03:00
// check if caster has at least 1 combo point for spells that require combo points
2010-09-14 13:28:25 +03:00
if ( m_needComboPoints )
2010-09-08 10:59:10 +02:00
if ( Player * plrCaster = m_caster -> ToPlayer ())
2010-09-08 11:22:51 +02:00
if ( ! plrCaster -> GetComboPoints ())
2010-09-08 10:59:10 +02:00
return SPELL_FAILED_NO_COMBO_POINTS ;
2010-09-08 01:35:36 +03:00
2010-02-20 23:59:05 +01:00
// all ok
return SPELL_CAST_OK ;
}
SpellCastResult Spell :: CheckPetCast ( Unit * target )
{
2011-07-31 19:03:06 +02:00
if ( m_caster -> HasUnitState ( UNIT_STAT_CASTING ) && ! ( _triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS )) //prevent spellcast interruption by another spellcast
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_SPELL_IN_PROGRESS ;
2011-08-20 09:49:18 +02:00
// dead owner (pets still alive when owners ressed?)
2011-09-15 14:08:17 +02:00
if ( Unit * owner = m_caster -> GetCharmerOrOwner ())
2011-08-20 09:49:18 +02:00
if ( ! owner -> isAlive ())
return SPELL_FAILED_CASTER_DEAD ;
2010-02-20 23:59:05 +01:00
2011-08-20 09:49:18 +02:00
if ( ! target && m_targets . GetUnitTarget ())
target = m_targets . GetUnitTarget ();
2010-02-20 23:59:05 +01:00
2011-08-20 09:49:18 +02:00
for ( uint32 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
{
if ( m_spellInfo -> Effects [ i ]. TargetA . GetType () == TARGET_TYPE_UNIT_TARGET
|| m_spellInfo -> Effects [ i ]. TargetA . GetType () == TARGET_TYPE_DEST_TARGET )
2010-02-20 23:59:05 +01:00
{
2011-08-20 09:49:18 +02:00
if ( ! target )
return SPELL_FAILED_BAD_IMPLICIT_TARGETS ;
m_targets . SetUnitTarget ( target );
break ;
2010-02-20 23:59:05 +01:00
}
2011-08-20 09:49:18 +02:00
}
2010-02-20 23:59:05 +01:00
2011-08-20 09:49:18 +02:00
// cooldown
2011-08-20 10:01:57 +02:00
if ( Creature const * creatureCaster = m_caster -> ToCreature ())
if ( creatureCaster -> HasSpellCooldown ( m_spellInfo -> Id ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NOT_READY ;
return CheckCast ( true );
}
SpellCastResult Spell :: CheckCasterAuras () const
{
2010-04-07 22:59:46 +02:00
// spells totally immuned to caster auras (wsg flag drop, give marks etc)
2011-06-30 08:05:03 +07:00
if ( m_spellInfo -> AttributesEx6 & SPELL_ATTR6_IGNORE_CASTER_AURAS )
2010-02-20 23:59:05 +01:00
return SPELL_CAST_OK ;
uint8 school_immune = 0 ;
uint32 mechanic_immune = 0 ;
uint32 dispel_immune = 0 ;
// Check if the spell grants school or mechanic immunity.
// We use bitmasks so the loop is done only once and not on every aura check below.
2010-12-19 05:15:47 +01:00
if ( m_spellInfo -> AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY )
2010-02-20 23:59:05 +01:00
{
2010-09-28 08:41:24 +03:00
for ( int i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ i ]. ApplyAuraName == SPELL_AURA_SCHOOL_IMMUNITY )
school_immune |= uint32 ( m_spellInfo -> Effects [ i ]. MiscValue );
else if ( m_spellInfo -> Effects [ i ]. ApplyAuraName == SPELL_AURA_MECHANIC_IMMUNITY )
mechanic_immune |= 1 << uint32 ( m_spellInfo -> Effects [ i ]. MiscValue );
else if ( m_spellInfo -> Effects [ i ]. ApplyAuraName == SPELL_AURA_DISPEL_IMMUNITY )
dispel_immune |= SpellInfo :: GetDispelMask ( DispelType ( m_spellInfo -> Effects [ i ]. MiscValue ));
2010-02-20 23:59:05 +01:00
}
2010-07-26 22:57:25 +02:00
// immune movement impairment and loss of control
2010-04-07 23:25:02 +02:00
if ( m_spellInfo -> Id == 42292 || m_spellInfo -> Id == 59752 )
2010-02-20 23:59:05 +01:00
mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK ;
}
2011-06-30 08:05:03 +07:00
bool usableInStun = m_spellInfo -> AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_STUNNED ;
2011-01-14 20:24:39 +01:00
// Glyph of Pain Suppression
2011-06-30 08:05:03 +07:00
// there is no other way to handle it
if ( m_spellInfo -> Id == 33206 && ! m_caster -> HasAura ( 63248 ))
usableInStun = false ;
2011-01-14 20:24:39 +01:00
2010-02-20 23:59:05 +01:00
// Check whether the cast should be prevented by any state you might have.
SpellCastResult prevented_reason = SPELL_CAST_OK ;
// Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out
uint32 unitflag = m_caster -> GetUInt32Value ( UNIT_FIELD_FLAGS ); // Get unit state
2011-06-30 08:05:03 +07:00
if ( unitflag & UNIT_FLAG_STUNNED )
{
// spell is usable while stunned, check if caster has only mechanic stun auras, another stun types must prevent cast spell
if ( usableInStun )
{
bool foundNotStun = false ;
Unit :: AuraEffectList const & stunAuras = m_caster -> GetAuraEffectsByType ( SPELL_AURA_MOD_STUN );
for ( Unit :: AuraEffectList :: const_iterator i = stunAuras . begin (); i != stunAuras . end (); ++ i )
{
2011-07-26 23:09:28 +02:00
if ( ! (( * i ) -> GetSpellInfo () -> GetAllEffectsMechanicMask () & ( 1 << MECHANIC_STUN )))
2011-06-30 08:05:03 +07:00
{
foundNotStun = true ;
break ;
}
}
if ( foundNotStun )
prevented_reason = SPELL_FAILED_STUNNED ;
}
else
prevented_reason = SPELL_FAILED_STUNNED ;
}
2010-12-19 05:15:47 +01:00
else if ( unitflag & UNIT_FLAG_CONFUSED && ! ( m_spellInfo -> AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_CONFUSED ))
2010-02-20 23:59:05 +01:00
prevented_reason = SPELL_FAILED_CONFUSED ;
2010-12-19 05:15:47 +01:00
else if ( unitflag & UNIT_FLAG_FLEEING && ! ( m_spellInfo -> AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_FEARED ))
2010-02-20 23:59:05 +01:00
prevented_reason = SPELL_FAILED_FLEEING ;
2010-04-07 19:14:10 +02:00
else if ( unitflag & UNIT_FLAG_SILENCED && m_spellInfo -> PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
2010-02-20 23:59:05 +01:00
prevented_reason = SPELL_FAILED_SILENCED ;
2010-04-07 19:14:10 +02:00
else if ( unitflag & UNIT_FLAG_PACIFIED && m_spellInfo -> PreventionType == SPELL_PREVENTION_TYPE_PACIFY )
2010-02-20 23:59:05 +01:00
prevented_reason = SPELL_FAILED_PACIFIED ;
// Attr must make flag drop spell totally immune from all effects
2010-04-07 19:14:10 +02:00
if ( prevented_reason != SPELL_CAST_OK )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( school_immune || mechanic_immune || dispel_immune )
2010-02-20 23:59:05 +01:00
{
//Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
Unit :: AuraApplicationMap const & auras = m_caster -> GetAppliedAuras ();
for ( Unit :: AuraApplicationMap :: const_iterator itr = auras . begin (); itr != auras . end (); ++ itr )
{
2011-06-11 22:35:29 +02:00
Aura const * aura = itr -> second -> GetBase ();
2011-07-26 23:09:28 +02:00
SpellInfo const * auraInfo = aura -> GetSpellInfo ();
if ( auraInfo -> GetAllEffectsMechanicMask () & mechanic_immune )
2010-02-20 23:59:05 +01:00
continue ;
2011-07-26 23:09:28 +02:00
if ( auraInfo -> GetSchoolMask () & school_immune )
2010-02-20 23:59:05 +01:00
continue ;
2011-07-26 23:09:28 +02:00
if ( auraInfo -> GetDispelMask () & dispel_immune )
2010-02-20 23:59:05 +01:00
continue ;
//Make a second check for spell failed so the right SPELL_FAILED message is returned.
//That is needed when your casting is prevented by multiple states and you are only immune to some of them.
2011-06-30 08:05:03 +07:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2010-02-20 23:59:05 +01:00
{
2011-06-30 08:05:03 +07:00
if ( AuraEffect * part = aura -> GetEffect ( i ))
2010-02-20 23:59:05 +01:00
{
2011-06-30 08:05:03 +07:00
switch ( part -> GetAuraType ())
2010-02-20 23:59:05 +01:00
{
case SPELL_AURA_MOD_STUN :
2011-07-26 23:09:28 +02:00
if ( ! usableInStun || ! ( auraInfo -> GetAllEffectsMechanicMask () & ( 1 << MECHANIC_STUN )))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_STUNNED ;
break ;
case SPELL_AURA_MOD_CONFUSE :
2010-12-19 05:15:47 +01:00
if ( ! ( m_spellInfo -> AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_CONFUSED ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CONFUSED ;
break ;
case SPELL_AURA_MOD_FEAR :
2010-12-19 05:15:47 +01:00
if ( ! ( m_spellInfo -> AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_FEARED ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_FLEEING ;
break ;
case SPELL_AURA_MOD_SILENCE :
case SPELL_AURA_MOD_PACIFY :
case SPELL_AURA_MOD_PACIFY_SILENCE :
2010-04-07 23:25:02 +02:00
if ( m_spellInfo -> PreventionType == SPELL_PREVENTION_TYPE_PACIFY )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_PACIFIED ;
2010-04-07 23:25:02 +02:00
else if ( m_spellInfo -> PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_SILENCED ;
break ;
default : break ;
}
}
}
}
}
// You are prevented from casting and the spell casted does not grant immunity. Return a failed error.
else
return prevented_reason ;
}
return SPELL_CAST_OK ;
}
bool Spell :: CanAutoCast ( Unit * target )
{
uint64 targetguid = target -> GetGUID ();
2010-09-28 08:41:24 +03:00
for ( uint32 j = 0 ; j < MAX_SPELL_EFFECTS ; ++ j )
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ j ]. Effect == SPELL_EFFECT_APPLY_AURA )
2010-02-20 23:59:05 +01:00
{
2010-04-07 22:59:46 +02:00
if ( m_spellInfo -> StackAmount <= 1 )
2010-02-20 23:59:05 +01:00
{
2010-04-07 22:59:46 +02:00
if ( target -> HasAuraEffect ( m_spellInfo -> Id , j ))
2010-02-20 23:59:05 +01:00
return false ;
}
else
{
2011-09-15 14:08:17 +02:00
if ( AuraEffect * aureff = target -> GetAuraEffect ( m_spellInfo -> Id , j ))
2010-02-20 23:59:05 +01:00
if ( aureff -> GetBase () -> GetStackAmount () >= m_spellInfo -> StackAmount )
return false ;
}
}
2011-07-28 13:21:31 +02:00
else if ( m_spellInfo -> Effects [ j ]. IsAreaAuraEffect ())
2010-02-20 23:59:05 +01:00
{
2010-04-07 22:59:46 +02:00
if ( target -> HasAuraEffect ( m_spellInfo -> Id , j ))
2010-02-20 23:59:05 +01:00
return false ;
}
}
SpellCastResult result = CheckPetCast ( target );
2010-04-07 19:14:10 +02:00
if ( result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT )
2010-02-20 23:59:05 +01:00
{
SelectSpellTargets ();
//check if among target units, our WANTED target is as well (->only self cast spells return false)
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
2010-04-07 22:59:46 +02:00
if ( ihit -> targetGUID == targetguid )
2010-02-20 23:59:05 +01:00
return true ;
}
return false ; //target invalid
}
2011-08-06 20:42:00 +07:00
SpellCastResult Spell :: CheckRange ( bool strict )
2010-02-20 23:59:05 +01:00
{
2011-08-06 20:42:00 +07:00
// Don't check for instant cast spells
if ( ! strict && m_casttime == 0 )
return SPELL_CAST_OK ;
2011-10-19 00:24:43 +02:00
uint32 range_type = 0 ;
if ( m_spellInfo -> RangeEntry )
{
// self cast is used for triggered spells, no range checking needed
if ( m_spellInfo -> RangeEntry -> ID == 1 )
return SPELL_CAST_OK ;
range_type = m_spellInfo -> RangeEntry -> type ;
}
2011-08-06 20:42:00 +07:00
2011-06-23 13:28:52 +02:00
Unit * target = m_targets . GetUnitTarget ();
2011-07-26 23:09:28 +02:00
float max_range = m_caster -> GetSpellMaxRangeForTarget ( target , m_spellInfo );
float min_range = m_caster -> GetSpellMinRangeForTarget ( target , m_spellInfo );
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( Player * modOwner = m_caster -> GetSpellModOwner ())
2010-02-20 23:59:05 +01:00
modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_RANGE , max_range , this );
2010-04-07 19:14:10 +02:00
if ( target && target != m_caster )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( range_type == SPELL_RANGE_MELEE )
2010-02-20 23:59:05 +01:00
{
// Because of lag, we can not check too strictly here.
2010-04-07 19:14:10 +02:00
if ( ! m_caster -> IsWithinMeleeRange ( target , max_range ))
2011-07-31 19:03:06 +02:00
return ! ( _triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR ) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT ;
2010-02-20 23:59:05 +01:00
}
2010-04-07 19:14:10 +02:00
else if ( ! m_caster -> IsWithinCombatRange ( target , max_range ))
2011-07-31 19:03:06 +02:00
return ! ( _triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR ) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT ; //0x5A;
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( range_type == SPELL_RANGE_RANGED )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( m_caster -> IsWithinMeleeRange ( target ))
2011-07-31 19:03:06 +02:00
return ! ( _triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR ) ? SPELL_FAILED_TOO_CLOSE : SPELL_FAILED_DONT_REPORT ;
2010-02-20 23:59:05 +01:00
}
2010-04-07 19:14:10 +02:00
else if ( min_range && m_caster -> IsWithinCombatRange ( target , min_range )) // skip this check if min_range = 0
2011-07-31 19:03:06 +02:00
return ! ( _triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR ) ? SPELL_FAILED_TOO_CLOSE : SPELL_FAILED_DONT_REPORT ;
2010-02-20 23:59:05 +01:00
2010-04-07 22:59:46 +02:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER &&
2010-08-22 12:39:39 -07:00
( m_spellInfo -> FacingCasterFlags & SPELL_FACING_FLAG_INFRONT ) && ! m_caster -> HasInArc ( static_cast < float > ( M_PI ), target ))
2011-07-31 19:03:06 +02:00
return ! ( _triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR ) ? SPELL_FAILED_UNIT_NOT_INFRONT : SPELL_FAILED_DONT_REPORT ;
2010-02-20 23:59:05 +01:00
}
2010-04-07 19:14:10 +02:00
if ( m_targets . HasDst () && ! m_targets . HasTraj ())
2010-02-20 23:59:05 +01:00
{
2011-06-23 13:28:52 +02:00
if ( ! m_caster -> IsWithinDist3d ( m_targets . GetDst (), max_range ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_OUT_OF_RANGE ;
2011-06-23 13:28:52 +02:00
if ( min_range && m_caster -> IsWithinDist3d ( m_targets . GetDst (), min_range ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_TOO_CLOSE ;
}
return SPELL_CAST_OK ;
}
SpellCastResult Spell :: CheckPower ()
{
// item cast not used power
2010-04-07 19:14:10 +02:00
if ( m_CastItem )
2010-02-20 23:59:05 +01:00
return SPELL_CAST_OK ;
// health as power used - need check health amount
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> PowerType == POWER_HEALTH )
2010-02-20 23:59:05 +01:00
{
2010-08-26 15:54:56 +06:00
if ( int32 ( m_caster -> GetHealth ()) <= m_powerCost )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CASTER_AURASTATE ;
return SPELL_CAST_OK ;
}
// Check valid power type
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> PowerType >= MAX_POWERS )
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
sLog -> outError ( "Spell::CheckPower: Unknown power type '%d'" , m_spellInfo -> PowerType );
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_UNKNOWN ;
}
//check rune cost only if a spell has PowerType == POWER_RUNE
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> PowerType == POWER_RUNE )
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
SpellCastResult failReason = CheckRuneCost ( m_spellInfo -> RuneCostID );
2010-04-07 19:14:10 +02:00
if ( failReason != SPELL_CAST_OK )
2010-02-20 23:59:05 +01:00
return failReason ;
}
// Check power amount
2011-07-26 23:09:28 +02:00
Powers powerType = Powers ( m_spellInfo -> PowerType );
2010-08-26 15:54:56 +06:00
if ( int32 ( m_caster -> GetPower ( powerType )) < m_powerCost )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_POWER ;
else
return SPELL_CAST_OK ;
}
SpellCastResult Spell :: CheckItems ()
{
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
return SPELL_CAST_OK ;
Player * p_caster = ( Player * ) m_caster ;
2010-04-07 19:14:10 +02:00
if ( ! m_CastItem )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( m_castItemGUID )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ITEM_NOT_READY ;
}
else
{
uint32 itemid = m_CastItem -> GetEntry ();
2010-04-07 22:59:46 +02:00
if ( ! p_caster -> HasItemCount ( itemid , 1 ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ITEM_NOT_READY ;
2011-09-15 14:08:17 +02:00
ItemTemplate const * proto = m_CastItem -> GetTemplate ();
2010-04-07 19:14:10 +02:00
if ( ! proto )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ITEM_NOT_READY ;
2010-09-28 08:41:24 +03:00
for ( int i = 0 ; i < MAX_ITEM_SPELLS ; ++ i )
2010-02-20 23:59:05 +01:00
if ( proto -> Spells [ i ]. SpellCharges )
2010-04-07 19:14:10 +02:00
if ( m_CastItem -> GetSpellCharges ( i ) == 0 )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_CHARGES_REMAIN ;
// consumable cast item checks
2011-06-23 13:28:52 +02:00
if ( proto -> Class == ITEM_CLASS_CONSUMABLE && m_targets . GetUnitTarget ())
2010-02-20 23:59:05 +01:00
{
// such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example
SpellCastResult failReason = SPELL_CAST_OK ;
2010-09-28 08:41:24 +03:00
for ( int i = 0 ; i < MAX_SPELL_EFFECTS ; i ++ )
2010-02-20 23:59:05 +01:00
{
2011-06-23 13:28:52 +02:00
// skip check, pet not required like checks, and for TARGET_UNIT_PET m_targets.GetUnitTarget() is not the real target but the caster
2011-07-27 12:35:59 +02:00
if ( m_spellInfo -> Effects [ i ]. TargetA . GetTarget () == TARGET_UNIT_PET )
2010-02-20 23:59:05 +01:00
continue ;
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ i ]. Effect == SPELL_EFFECT_HEAL )
2010-02-20 23:59:05 +01:00
{
2011-06-23 13:28:52 +02:00
if ( m_targets . GetUnitTarget () -> IsFullHealth ())
2010-02-20 23:59:05 +01:00
{
failReason = SPELL_FAILED_ALREADY_AT_FULL_HEALTH ;
continue ;
}
else
{
failReason = SPELL_CAST_OK ;
break ;
}
}
// Mana Potion, Rage Potion, Thistle Tea(Rogue), ...
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ i ]. Effect == SPELL_EFFECT_ENERGIZE )
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ i ]. MiscValue < 0 || m_spellInfo -> Effects [ i ]. MiscValue >= int8 ( MAX_POWERS ))
2010-02-20 23:59:05 +01:00
{
failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER ;
continue ;
}
2011-07-26 23:09:28 +02:00
Powers power = Powers ( m_spellInfo -> Effects [ i ]. MiscValue );
2011-06-23 13:28:52 +02:00
if ( m_targets . GetUnitTarget () -> GetPower ( power ) == m_targets . GetUnitTarget () -> GetMaxPower ( power ))
2010-02-20 23:59:05 +01:00
{
failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER ;
continue ;
}
else
{
failReason = SPELL_CAST_OK ;
break ;
}
}
}
if ( failReason != SPELL_CAST_OK )
return failReason ;
}
}
// check target item
2011-06-23 13:28:52 +02:00
if ( m_targets . GetItemTargetGUID ())
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
2011-06-23 13:28:52 +02:00
if ( ! m_targets . GetItemTarget ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ITEM_GONE ;
2011-06-23 13:28:52 +02:00
if ( ! m_targets . GetItemTarget () -> IsFitToSpellRequirements ( m_spellInfo ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_EQUIPPED_ITEM_CLASS ;
}
// if not item target then required item must be equipped
else
{
2010-12-25 04:03:04 +01:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER && ! m_caster -> ToPlayer () -> HasItemFitToSpellRequirements ( m_spellInfo ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_EQUIPPED_ITEM_CLASS ;
}
// check spell focus object
2010-04-07 19:14:10 +02:00
if ( m_spellInfo -> RequiresSpellFocus )
2010-02-20 23:59:05 +01:00
{
2011-10-18 10:53:34 -04:00
CellCoord p ( Trinity :: ComputeCellCoord ( m_caster -> GetPositionX (), m_caster -> GetPositionY ()));
2010-02-20 23:59:05 +01:00
Cell cell ( p );
GameObject * ok = NULL ;
2011-04-29 20:47:02 +02:00
Trinity :: GameObjectFocusCheck go_check ( m_caster , m_spellInfo -> RequiresSpellFocus );
2010-02-20 23:59:05 +01:00
Trinity :: GameObjectSearcher < Trinity :: GameObjectFocusCheck > checker ( m_caster , ok , go_check );
TypeContainerVisitor < Trinity :: GameObjectSearcher < Trinity :: GameObjectFocusCheck > , GridTypeMapContainer > object_checker ( checker );
Map & map = * m_caster -> GetMap ();
2010-11-13 17:18:09 +01:00
cell . Visit ( p , object_checker , map , * m_caster , m_caster -> GetVisibilityRange ());
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( ! ok )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_REQUIRES_SPELL_FOCUS ;
focusObject = ok ; // game object found in range
}
// do not take reagents for these item casts
2011-04-28 22:42:33 +02:00
if ( ! ( m_CastItem && m_CastItem -> GetTemplate () -> Flags & ITEM_PROTO_FLAG_TRIGGERED_CAST ))
2010-02-20 23:59:05 +01:00
{
2011-07-31 19:03:06 +02:00
bool checkReagents = ! ( _triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST ) && ! p_caster -> CanNoReagentCast ( m_spellInfo );
2011-03-22 16:09:55 +01:00
// Not own traded item (in trader trade slot) requires reagents even if triggered spell
if ( ! checkReagents )
2011-06-23 13:28:52 +02:00
if ( Item * targetItem = m_targets . GetItemTarget ())
2011-03-22 16:09:55 +01:00
if ( targetItem -> GetOwnerGUID () != m_caster -> GetGUID ())
checkReagents = true ;
2010-02-20 23:59:05 +01:00
// check reagents (ignore triggered spells with reagents processed by original spell) and special reagent ignore case.
2011-03-22 16:09:55 +01:00
if ( checkReagents )
2010-02-20 23:59:05 +01:00
{
2010-09-28 08:41:24 +03:00
for ( uint32 i = 0 ; i < MAX_SPELL_REAGENTS ; i ++ )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( m_spellInfo -> Reagent [ i ] <= 0 )
2010-02-20 23:59:05 +01:00
continue ;
uint32 itemid = m_spellInfo -> Reagent [ i ];
uint32 itemcount = m_spellInfo -> ReagentCount [ i ];
// if CastItem is also spell reagent
2010-04-07 22:59:46 +02:00
if ( m_CastItem && m_CastItem -> GetEntry () == itemid )
2010-02-20 23:59:05 +01:00
{
2011-09-15 14:08:17 +02:00
ItemTemplate const * proto = m_CastItem -> GetTemplate ();
2010-04-07 19:14:10 +02:00
if ( ! proto )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ITEM_NOT_READY ;
for ( int s = 0 ; s < MAX_ITEM_PROTO_SPELLS ; ++ s )
{
// CastItem will be used up and does not count as reagent
int32 charges = m_CastItem -> GetSpellCharges ( s );
if ( proto -> Spells [ s ]. SpellCharges < 0 && abs ( charges ) < 2 )
{
++ itemcount ;
break ;
}
}
}
2011-03-22 16:09:55 +01:00
if ( ! p_caster -> HasItemCount ( itemid , itemcount ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ITEM_NOT_READY ; //0x54
}
}
// check totem-item requirements (items presence in inventory)
uint32 totems = 2 ;
for ( int i = 0 ; i < 2 ; ++ i )
{
2010-04-07 19:14:10 +02:00
if ( m_spellInfo -> Totem [ i ] != 0 )
2010-02-20 23:59:05 +01:00
{
2011-04-29 20:47:02 +02:00
if ( p_caster -> HasItemCount ( m_spellInfo -> Totem [ i ], 1 ))
2010-02-20 23:59:05 +01:00
{
totems -= 1 ;
continue ;
}
} else
totems -= 1 ;
}
2010-04-07 19:14:10 +02:00
if ( totems != 0 )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_TOTEMS ; //0x7C
// Check items for TotemCategory (items presence in inventory)
uint32 TotemCategory = 2 ;
for ( int i = 0 ; i < 2 ; ++ i )
{
2010-04-07 19:14:10 +02:00
if ( m_spellInfo -> TotemCategory [ i ] != 0 )
2010-02-20 23:59:05 +01:00
{
2010-04-07 22:59:46 +02:00
if ( p_caster -> HasItemTotemCategory ( m_spellInfo -> TotemCategory [ i ]))
2010-02-20 23:59:05 +01:00
{
TotemCategory -= 1 ;
continue ;
}
}
else
TotemCategory -= 1 ;
}
2010-04-07 19:14:10 +02:00
if ( TotemCategory != 0 )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_TOTEM_CATEGORY ; //0x7B
}
// special checks for spell effects
2010-09-28 08:41:24 +03:00
for ( int i = 0 ; i < MAX_SPELL_EFFECTS ; i ++ )
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
switch ( m_spellInfo -> Effects [ i ]. Effect )
2010-02-20 23:59:05 +01:00
{
case SPELL_EFFECT_CREATE_ITEM :
2010-08-28 02:20:26 +03:00
case SPELL_EFFECT_CREATE_ITEM_2 :
2010-02-20 23:59:05 +01:00
{
2011-07-31 19:03:06 +02:00
if ( ! IsTriggered () && m_spellInfo -> Effects [ i ]. ItemType )
2010-02-20 23:59:05 +01:00
{
ItemPosCountVec dest ;
2011-07-26 23:09:28 +02:00
InventoryResult msg = p_caster -> CanStoreNewItem ( NULL_BAG , NULL_SLOT , dest , m_spellInfo -> Effects [ i ]. ItemType , 1 );
2010-04-07 22:59:46 +02:00
if ( msg != EQUIP_ERR_OK )
2010-02-20 23:59:05 +01:00
{
2011-09-15 14:08:17 +02:00
ItemTemplate const * pProto = sObjectMgr -> GetItemTemplate ( m_spellInfo -> Effects [ i ]. ItemType );
2010-08-05 22:08:07 +06:00
// TODO: Needs review
2010-02-20 23:59:05 +01:00
if ( pProto && ! ( pProto -> ItemLimitCategory ))
{
2011-07-26 23:09:28 +02:00
p_caster -> SendEquipError ( msg , NULL , NULL , m_spellInfo -> Effects [ i ]. ItemType );
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_DONT_REPORT ;
}
else
{
if ( ! ( m_spellInfo -> SpellFamilyName == SPELLFAMILY_MAGE && ( m_spellInfo -> SpellFamilyFlags [ 0 ] & 0x40000000 )))
return SPELL_FAILED_TOO_MANY_OF_ITEM ;
2011-07-26 23:09:28 +02:00
else if ( ! ( p_caster -> HasItemCount ( m_spellInfo -> Effects [ i ]. ItemType , 1 )))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_TOO_MANY_OF_ITEM ;
else
2011-07-26 23:09:28 +02:00
p_caster -> CastSpell ( m_caster , m_spellInfo -> Effects [ EFFECT_1 ]. CalcValue (), false ); // move this to anywhere
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_DONT_REPORT ;
}
}
}
break ;
}
case SPELL_EFFECT_ENCHANT_ITEM :
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ i ]. ItemType && m_targets . GetItemTarget ()
2011-06-23 13:28:52 +02:00
&& ( m_targets . GetItemTarget () -> IsWeaponVellum () || m_targets . GetItemTarget () -> IsArmorVellum ()))
2010-02-20 23:59:05 +01:00
{
// cannot enchant vellum for other player
2011-06-23 13:28:52 +02:00
if ( m_targets . GetItemTarget () -> GetOwner () != m_caster )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NOT_TRADEABLE ;
// do not allow to enchant vellum from scroll made by vellum-prevent exploit
2011-04-28 22:42:33 +02:00
if ( m_CastItem && m_CastItem -> GetTemplate () -> Flags & ITEM_PROTO_FLAG_TRIGGERED_CAST )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_TOTEM_CATEGORY ;
ItemPosCountVec dest ;
2011-07-26 23:09:28 +02:00
InventoryResult msg = p_caster -> CanStoreNewItem ( NULL_BAG , NULL_SLOT , dest , m_spellInfo -> Effects [ i ]. ItemType , 1 );
2010-04-07 22:59:46 +02:00
if ( msg != EQUIP_ERR_OK )
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
p_caster -> SendEquipError ( msg , NULL , NULL , m_spellInfo -> Effects [ i ]. ItemType );
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_DONT_REPORT ;
}
}
case SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC :
{
2011-06-23 13:28:52 +02:00
Item * targetItem = m_targets . GetItemTarget ();
2010-04-07 19:14:10 +02:00
if ( ! targetItem )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ITEM_NOT_FOUND ;
2011-07-26 23:09:28 +02:00
if ( targetItem -> GetTemplate () -> ItemLevel < m_spellInfo -> BaseLevel )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_LOWLEVEL ;
2010-09-28 18:50:38 +02:00
bool isItemUsable = false ;
2010-09-28 18:57:19 +02:00
for ( uint8 e = 0 ; e < MAX_ITEM_PROTO_SPELLS ; ++ e )
2010-09-28 18:50:38 +02:00
{
2011-09-15 14:08:17 +02:00
ItemTemplate const * proto = targetItem -> GetTemplate ();
2010-09-28 18:57:19 +02:00
if ( proto -> Spells [ e ]. SpellId && (
proto -> Spells [ e ]. SpellTrigger == ITEM_SPELLTRIGGER_ON_USE ||
proto -> Spells [ e ]. SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE ))
2010-09-28 18:50:38 +02:00
{
isItemUsable = true ;
break ;
}
}
2011-09-15 14:08:17 +02:00
SpellItemEnchantmentEntry const * pEnchant = sSpellItemEnchantmentStore . LookupEntry ( m_spellInfo -> Effects [ i ]. MiscValue );
2010-09-28 18:50:38 +02:00
// do not allow adding usable enchantments to items that have use effect already
if ( pEnchant && isItemUsable )
for ( uint8 s = 0 ; s < MAX_ITEM_ENCHANTMENT_EFFECTS ; ++ s )
if ( pEnchant -> type [ s ] == ITEM_ENCHANTMENT_TYPE_USE_SPELL )
return SPELL_FAILED_ON_USE_ENCHANT ;
2010-02-20 23:59:05 +01:00
// Not allow enchant in trade slot for some enchant type
2010-04-07 22:59:46 +02:00
if ( targetItem -> GetOwner () != m_caster )
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:14:10 +02:00
if ( ! pEnchant )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ERROR ;
if ( pEnchant -> slot & ENCHANTMENT_CAN_SOULBOUND )
return SPELL_FAILED_NOT_TRADEABLE ;
}
break ;
}
case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY :
{
2011-09-15 14:08:17 +02:00
Item * item = m_targets . GetItemTarget ();
2010-04-07 19:14:10 +02:00
if ( ! item )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ITEM_NOT_FOUND ;
// Not allow enchant in trade slot for some enchant type
2010-04-07 22:59:46 +02:00
if ( item -> GetOwner () != m_caster )
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
uint32 enchant_id = m_spellInfo -> Effects [ i ]. MiscValue ;
2011-09-15 14:08:17 +02:00
SpellItemEnchantmentEntry const * pEnchant = sSpellItemEnchantmentStore . LookupEntry ( enchant_id );
2010-04-07 19:14:10 +02:00
if ( ! pEnchant )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ERROR ;
if ( pEnchant -> slot & ENCHANTMENT_CAN_SOULBOUND )
return SPELL_FAILED_NOT_TRADEABLE ;
}
break ;
}
case SPELL_EFFECT_ENCHANT_HELD_ITEM :
// check item existence in effect code (not output errors at offhand hold item effect to main hand for example
break ;
case SPELL_EFFECT_DISENCHANT :
{
2011-06-23 13:28:52 +02:00
if ( ! m_targets . GetItemTarget ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_DISENCHANTED ;
// prevent disenchanting in trade slot
2011-06-23 13:28:52 +02:00
if ( m_targets . GetItemTarget () -> GetOwnerGUID () != m_caster -> GetGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_DISENCHANTED ;
2011-06-23 13:28:52 +02:00
ItemTemplate const * itemProto = m_targets . GetItemTarget () -> GetTemplate ();
2010-04-07 19:14:10 +02:00
if ( ! itemProto )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_DISENCHANTED ;
uint32 item_quality = itemProto -> Quality ;
// 2.0.x addon: Check player enchanting level against the item disenchanting requirements
uint32 item_disenchantskilllevel = itemProto -> RequiredDisenchantSkill ;
if ( item_disenchantskilllevel == uint32 ( - 1 ))
return SPELL_FAILED_CANT_BE_DISENCHANTED ;
if ( item_disenchantskilllevel > p_caster -> GetSkillValue ( SKILL_ENCHANTING ))
return SPELL_FAILED_LOW_CASTLEVEL ;
2010-04-07 19:14:10 +02:00
if ( item_quality > 4 || item_quality < 2 )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_DISENCHANTED ;
2010-04-07 19:14:10 +02:00
if ( itemProto -> Class != ITEM_CLASS_WEAPON && itemProto -> Class != ITEM_CLASS_ARMOR )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_DISENCHANTED ;
if ( ! itemProto -> DisenchantID )
return SPELL_FAILED_CANT_BE_DISENCHANTED ;
break ;
}
case SPELL_EFFECT_PROSPECTING :
{
2011-06-23 13:28:52 +02:00
if ( ! m_targets . GetItemTarget ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_PROSPECTED ;
//ensure item is a prospectable ore
2011-06-23 13:28:52 +02:00
if ( ! ( m_targets . GetItemTarget () -> GetTemplate () -> Flags & ITEM_PROTO_FLAG_PROSPECTABLE ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_PROSPECTED ;
//prevent prospecting in trade slot
2011-06-23 13:28:52 +02:00
if ( m_targets . GetItemTarget () -> GetOwnerGUID () != m_caster -> GetGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_PROSPECTED ;
//Check for enough skill in jewelcrafting
2011-06-23 13:28:52 +02:00
uint32 item_prospectingskilllevel = m_targets . GetItemTarget () -> GetTemplate () -> RequiredSkillRank ;
2010-04-07 19:14:10 +02:00
if ( item_prospectingskilllevel > p_caster -> GetSkillValue ( SKILL_JEWELCRAFTING ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_LOW_CASTLEVEL ;
//make sure the player has the required ores in inventory
2011-06-23 13:28:52 +02:00
if ( m_targets . GetItemTarget () -> GetCount () < 5 )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NEED_MORE_ITEMS ;
2011-06-23 13:28:52 +02:00
if ( ! LootTemplates_Prospecting . HaveLootFor ( m_targets . GetItemTargetEntry ()))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_PROSPECTED ;
break ;
}
case SPELL_EFFECT_MILLING :
{
2011-06-23 13:28:52 +02:00
if ( ! m_targets . GetItemTarget ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_MILLED ;
//ensure item is a millable herb
2011-06-23 13:28:52 +02:00
if ( ! ( m_targets . GetItemTarget () -> GetTemplate () -> Flags & ITEM_PROTO_FLAG_MILLABLE ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_MILLED ;
//prevent milling in trade slot
2011-06-23 13:28:52 +02:00
if ( m_targets . GetItemTarget () -> GetOwnerGUID () != m_caster -> GetGUID ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_MILLED ;
//Check for enough skill in inscription
2011-06-23 13:28:52 +02:00
uint32 item_millingskilllevel = m_targets . GetItemTarget () -> GetTemplate () -> RequiredSkillRank ;
2010-04-07 19:14:10 +02:00
if ( item_millingskilllevel > p_caster -> GetSkillValue ( SKILL_INSCRIPTION ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_LOW_CASTLEVEL ;
//make sure the player has the required herbs in inventory
2011-06-23 13:28:52 +02:00
if ( m_targets . GetItemTarget () -> GetCount () < 5 )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NEED_MORE_ITEMS ;
2011-06-23 13:28:52 +02:00
if ( ! LootTemplates_Milling . HaveLootFor ( m_targets . GetItemTargetEntry ()))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_CANT_BE_MILLED ;
break ;
}
case SPELL_EFFECT_WEAPON_DAMAGE :
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL :
{
2010-04-07 19:14:10 +02:00
if ( m_caster -> GetTypeId () != TYPEID_PLAYER ) return SPELL_FAILED_TARGET_NOT_PLAYER ;
2010-04-07 22:59:46 +02:00
if ( m_attackType != RANGED_ATTACK )
2010-02-20 23:59:05 +01:00
break ;
2011-09-15 14:08:17 +02:00
Item * pItem = m_caster -> ToPlayer () -> GetWeaponForAttack ( m_attackType );
2010-04-07 19:14:10 +02:00
if ( ! pItem || pItem -> IsBroken ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_EQUIPPED_ITEM ;
2011-09-05 14:01:50 +02:00
switch ( pItem -> GetTemplate () -> SubClass )
2010-02-20 23:59:05 +01:00
{
case ITEM_SUBCLASS_WEAPON_THROWN :
{
uint32 ammo = pItem -> GetEntry ();
2010-04-07 22:59:46 +02:00
if ( ! m_caster -> ToPlayer () -> HasItemCount ( ammo , 1 ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_AMMO ;
}; break ;
case ITEM_SUBCLASS_WEAPON_GUN :
case ITEM_SUBCLASS_WEAPON_BOW :
case ITEM_SUBCLASS_WEAPON_CROSSBOW :
{
2010-03-07 15:20:19 +01:00
uint32 ammo = m_caster -> ToPlayer () -> GetUInt32Value ( PLAYER_AMMO_ID );
2010-04-07 19:14:10 +02:00
if ( ! ammo )
2010-02-20 23:59:05 +01:00
{
// Requires No Ammo
2010-04-07 19:14:10 +02:00
if ( m_caster -> HasAura ( 46699 ))
2010-02-20 23:59:05 +01:00
break ; // skip other checks
return SPELL_FAILED_NO_AMMO ;
}
2011-09-15 14:08:17 +02:00
ItemTemplate const * ammoProto = sObjectMgr -> GetItemTemplate ( ammo );
2010-04-07 19:14:10 +02:00
if ( ! ammoProto )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_AMMO ;
2010-04-07 19:14:10 +02:00
if ( ammoProto -> Class != ITEM_CLASS_PROJECTILE )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_AMMO ;
// check ammo ws. weapon compatibility
2011-09-05 14:01:50 +02:00
switch ( pItem -> GetTemplate () -> SubClass )
2010-02-20 23:59:05 +01:00
{
case ITEM_SUBCLASS_WEAPON_BOW :
case ITEM_SUBCLASS_WEAPON_CROSSBOW :
2010-04-07 19:14:10 +02:00
if ( ammoProto -> SubClass != ITEM_SUBCLASS_ARROW )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_AMMO ;
break ;
case ITEM_SUBCLASS_WEAPON_GUN :
2010-04-07 19:14:10 +02:00
if ( ammoProto -> SubClass != ITEM_SUBCLASS_BULLET )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_AMMO ;
break ;
default :
return SPELL_FAILED_NO_AMMO ;
}
2010-04-07 22:59:46 +02:00
if ( ! m_caster -> ToPlayer () -> HasItemCount ( ammo , 1 ))
2010-09-08 05:39:24 +03:00
{
m_caster -> ToPlayer () -> SetUInt32Value ( PLAYER_AMMO_ID , 0 );
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_NO_AMMO ;
2010-09-08 05:39:24 +03:00
}
2010-02-20 23:59:05 +01:00
}; break ;
case ITEM_SUBCLASS_WEAPON_WAND :
break ;
default :
break ;
}
break ;
}
case SPELL_EFFECT_CREATE_MANA_GEM :
{
2011-07-26 23:09:28 +02:00
uint32 item_id = m_spellInfo -> Effects [ i ]. ItemType ;
2011-09-15 14:08:17 +02:00
ItemTemplate const * pProto = sObjectMgr -> GetItemTemplate ( item_id );
2010-02-20 23:59:05 +01:00
if ( ! pProto )
return SPELL_FAILED_ITEM_AT_MAX_CHARGES ;
if ( Item * pitem = p_caster -> GetItemByEntry ( item_id ))
{
2010-04-07 19:12:44 +02:00
for ( int x = 0 ; x < MAX_ITEM_PROTO_SPELLS ; ++ x )
2010-02-20 23:59:05 +01:00
if ( pProto -> Spells [ x ]. SpellCharges != 0 && pitem -> GetSpellCharges ( x ) == pProto -> Spells [ x ]. SpellCharges )
return SPELL_FAILED_ITEM_AT_MAX_CHARGES ;
}
2010-04-07 18:09:10 +02:00
break ;
2010-02-20 23:59:05 +01:00
}
default :
break ;
}
}
// check weapon presence in slots for main/offhand weapons
2010-04-07 19:14:10 +02:00
if ( m_spellInfo -> EquippedItemClass >= 0 )
2010-02-20 23:59:05 +01:00
{
// main hand weapon required
2010-12-19 05:15:47 +01:00
if ( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_MAIN_HAND )
2010-02-20 23:59:05 +01:00
{
2010-03-07 15:20:19 +01:00
Item * item = m_caster -> ToPlayer () -> GetWeaponForAttack ( BASE_ATTACK );
2010-02-20 23:59:05 +01:00
// skip spell if no weapon in slot or broken
2010-04-07 22:59:46 +02:00
if ( ! item || item -> IsBroken ())
2011-07-31 19:03:06 +02:00
return ( _triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR ) ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_EQUIPPED_ITEM_CLASS ;
2010-02-20 23:59:05 +01:00
// skip spell if weapon not fit to triggered spell
2010-04-07 19:14:10 +02:00
if ( ! item -> IsFitToSpellRequirements ( m_spellInfo ))
2011-07-31 19:03:06 +02:00
return ( _triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR ) ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_EQUIPPED_ITEM_CLASS ;
2010-02-20 23:59:05 +01:00
}
// offhand hand weapon required
2010-12-19 05:15:47 +01:00
if ( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_REQ_OFFHAND )
2010-02-20 23:59:05 +01:00
{
2010-03-07 15:20:19 +01:00
Item * item = m_caster -> ToPlayer () -> GetWeaponForAttack ( OFF_ATTACK );
2010-02-20 23:59:05 +01:00
// skip spell if no weapon in slot or broken
2010-04-07 22:59:46 +02:00
if ( ! item || item -> IsBroken ())
2011-07-31 19:03:06 +02:00
return ( _triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR ) ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_EQUIPPED_ITEM_CLASS ;
2010-02-20 23:59:05 +01:00
// skip spell if weapon not fit to triggered spell
2010-04-07 19:14:10 +02:00
if ( ! item -> IsFitToSpellRequirements ( m_spellInfo ))
2011-07-31 19:03:06 +02:00
return ( _triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR ) ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_EQUIPPED_ITEM_CLASS ;
2010-02-20 23:59:05 +01:00
}
}
return SPELL_CAST_OK ;
}
void Spell :: Delayed () // only called in DealDamage()
{
2010-04-07 19:14:10 +02:00
if ( ! m_caster ) // || m_caster->GetTypeId() != TYPEID_PLAYER)
2010-02-20 23:59:05 +01:00
return ;
//if (m_spellState == SPELL_STATE_DELAYED)
// return; // spell is active and can't be time-backed
2010-04-07 19:14:10 +02:00
if ( isDelayableNoMore ()) // Spells may only be delayed twice
2010-02-20 23:59:05 +01:00
return ;
2010-04-07 22:59:46 +02:00
// spells not loosing casting time (slam, dynamites, bombs..)
2010-04-07 19:14:10 +02:00
//if (!(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_DAMAGE))
2010-02-20 23:59:05 +01:00
// return;
//check pushback reduce
int32 delaytime = 500 ; // spellcasting delay is normally 500ms
int32 delayReduce = 100 ; // must be initialized to 100 for percent modifiers
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_NOT_LOSE_CASTING_TIME , delayReduce , this );
2010-02-20 23:59:05 +01:00
delayReduce += m_caster -> GetTotalAuraModifier ( SPELL_AURA_REDUCE_PUSHBACK ) - 100 ;
2010-04-07 19:14:10 +02:00
if ( delayReduce >= 100 )
2010-02-20 23:59:05 +01:00
return ;
2010-12-11 20:37:38 +06:00
AddPctN ( delaytime , - delayReduce );
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( int32 ( m_timer ) + delaytime > m_casttime )
2010-02-20 23:59:05 +01:00
{
delaytime = m_casttime - m_timer ;
m_timer = m_casttime ;
}
else
m_timer += delaytime ;
2010-12-23 23:25:44 +01:00
sLog -> outDetail ( "Spell %u partially interrupted for (%d) ms at damage" , m_spellInfo -> Id , delaytime );
2010-02-20 23:59:05 +01:00
WorldPacket data ( SMSG_SPELL_DELAYED , 8 + 4 );
data . append ( m_caster -> GetPackGUID ());
data << uint32 ( delaytime );
m_caster -> SendMessageToSet ( & data , true );
}
void Spell :: DelayedChannel ()
{
if ( ! m_caster || m_caster -> GetTypeId () != TYPEID_PLAYER || getState () != SPELL_STATE_CASTING )
return ;
if ( isDelayableNoMore ()) // Spells may only be delayed twice
return ;
//check pushback reduce
2011-07-26 23:09:28 +02:00
int32 delaytime = CalculatePctN ( m_spellInfo -> GetDuration (), 25 ); // channeling delay is normally 25% of its time per hit
2010-02-20 23:59:05 +01:00
int32 delayReduce = 100 ; // must be initialized to 100 for percent modifiers
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_NOT_LOSE_CASTING_TIME , delayReduce , this );
2010-02-20 23:59:05 +01:00
delayReduce += m_caster -> GetTotalAuraModifier ( SPELL_AURA_REDUCE_PUSHBACK ) - 100 ;
2010-04-07 19:14:10 +02:00
if ( delayReduce >= 100 )
2010-02-20 23:59:05 +01:00
return ;
2010-12-11 20:37:38 +06:00
AddPctN ( delaytime , - delayReduce );
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( int32 ( m_timer ) <= delaytime )
2010-02-20 23:59:05 +01:00
{
delaytime = m_timer ;
m_timer = 0 ;
}
else
m_timer -= delaytime ;
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell %u partially interrupted for %i ms, new duration: %u ms" , m_spellInfo -> Id , delaytime , m_timer );
2010-02-20 23:59:05 +01:00
for ( std :: list < TargetInfo >:: const_iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
if (( * ihit ). missCondition == SPELL_MISS_NONE )
if ( Unit * unit = ( m_caster -> GetGUID () == ihit -> targetGUID ) ? m_caster : ObjectAccessor :: GetUnit ( * m_caster , ihit -> targetGUID ))
unit -> DelayOwnedAuras ( m_spellInfo -> Id , m_originalCasterGUID , delaytime );
// partially interrupt persistent area auras
2010-04-07 19:14:10 +02:00
if ( DynamicObject * dynObj = m_caster -> GetDynObject ( m_spellInfo -> Id ))
2010-02-20 23:59:05 +01:00
dynObj -> Delay ( delaytime );
SendChannelUpdate ( m_timer );
}
void Spell :: UpdatePointers ()
{
2010-04-07 19:14:10 +02:00
if ( m_originalCasterGUID == m_caster -> GetGUID ())
2010-02-20 23:59:05 +01:00
m_originalCaster = m_caster ;
else
{
2011-04-29 20:47:02 +02:00
m_originalCaster = ObjectAccessor :: GetUnit ( * m_caster , m_originalCasterGUID );
2010-02-20 23:59:05 +01:00
if ( m_originalCaster && ! m_originalCaster -> IsInWorld ())
m_originalCaster = NULL ;
}
if ( m_castItemGUID && m_caster -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
m_CastItem = m_caster -> ToPlayer () -> GetItemByGuid ( m_castItemGUID );
2010-02-20 23:59:05 +01:00
m_targets . Update ( m_caster );
}
2011-08-21 13:57:15 +02:00
CurrentSpellTypes Spell :: GetCurrentContainer () const
2010-02-20 23:59:05 +01:00
{
if ( IsNextMeleeSwingSpell ())
return ( CURRENT_MELEE_SPELL );
else if ( IsAutoRepeat ())
return ( CURRENT_AUTOREPEAT_SPELL );
2011-07-26 23:09:28 +02:00
else if ( m_spellInfo -> IsChanneled ())
2010-02-20 23:59:05 +01:00
return ( CURRENT_CHANNELED_SPELL );
else
return ( CURRENT_GENERIC_SPELL );
}
2011-08-19 14:53:40 +02:00
bool Spell :: CheckEffectTarget ( Unit const * target , uint32 eff ) const
2010-02-20 23:59:05 +01:00
{
2011-09-05 14:01:50 +02:00
switch ( m_spellInfo -> Effects [ eff ]. ApplyAuraName )
2010-02-20 23:59:05 +01:00
{
case SPELL_AURA_MOD_POSSESS :
case SPELL_AURA_MOD_CHARM :
case SPELL_AURA_MOD_POSSESS_PET :
case SPELL_AURA_AOE_CHARM :
2010-04-07 19:14:10 +02:00
if ( target -> GetTypeId () == TYPEID_UNIT && target -> IsVehicle ())
2010-02-20 23:59:05 +01:00
return false ;
2010-07-20 01:42:14 +02:00
if ( target -> IsMounted ())
return false ;
2010-04-07 19:14:10 +02:00
if ( target -> GetCharmerGUID ())
2010-02-20 23:59:05 +01:00
return false ;
2011-08-21 13:01:04 +02:00
if ( int32 damage = CalculateDamage ( eff , target ))
2010-04-07 19:14:10 +02:00
if (( int32 ) target -> getLevel () > damage )
2010-02-20 23:59:05 +01:00
return false ;
break ;
2011-08-19 14:53:40 +02:00
default :
break ;
2010-02-20 23:59:05 +01:00
}
2011-08-30 00:13:53 +02:00
if ( IsTriggered () || m_spellInfo -> AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS )
2010-02-20 23:59:05 +01:00
return true ;
2011-08-19 14:53:40 +02:00
// todo: shit below shouldn't be here, but it's temporary
2010-04-07 22:59:46 +02:00
//Check targets for LOS visibility (except spells without range limitations)
2011-09-05 14:01:50 +02:00
switch ( m_spellInfo -> Effects [ eff ]. Effect )
2010-02-20 23:59:05 +01:00
{
case SPELL_EFFECT_RESURRECT_NEW :
// player far away, maybe his corpse near?
2010-04-07 19:14:10 +02:00
if ( target != m_caster && ! target -> IsWithinLOSInMap ( m_caster ))
2010-02-20 23:59:05 +01:00
{
2011-06-23 13:28:52 +02:00
if ( ! m_targets . GetCorpseTargetGUID ())
2010-02-20 23:59:05 +01:00
return false ;
2011-09-15 14:08:17 +02:00
Corpse * corpse = ObjectAccessor :: GetCorpse ( * m_caster , m_targets . GetCorpseTargetGUID ());
2010-04-07 19:14:10 +02:00
if ( ! corpse )
2010-02-20 23:59:05 +01:00
return false ;
2010-04-07 19:14:10 +02:00
if ( target -> GetGUID () != corpse -> GetOwnerGUID ())
2010-02-20 23:59:05 +01:00
return false ;
2010-04-07 19:14:10 +02:00
if ( ! corpse -> IsWithinLOSInMap ( m_caster ))
2010-02-20 23:59:05 +01:00
return false ;
}
// all ok by some way or another, skip normal check
break ;
default : // normal case
// Get GO cast coordinates if original caster -> GO
2011-09-15 14:08:17 +02:00
WorldObject * caster = NULL ;
2010-02-20 23:59:05 +01:00
if ( IS_GAMEOBJECT_GUID ( m_originalCasterGUID ))
caster = m_caster -> GetMap () -> GetGameObject ( m_originalCasterGUID );
if ( ! caster )
caster = m_caster ;
2010-04-07 19:14:10 +02:00
if ( target != m_caster && ! target -> IsWithinLOSInMap ( caster ))
2010-02-20 23:59:05 +01:00
return false ;
break ;
}
return true ;
}
2011-07-26 23:09:28 +02:00
bool Spell :: IsNextMeleeSwingSpell () const
{
return m_spellInfo -> Attributes & SPELL_ATTR0_ON_NEXT_SWING ;
}
2011-07-27 12:35:59 +02:00
bool Spell :: IsAutoActionResetSpell () const
2011-07-26 23:09:28 +02:00
{
2011-07-31 19:03:06 +02:00
return ! IsTriggered () && ( m_spellInfo -> InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK );
2011-07-26 23:09:28 +02:00
}
2010-02-20 23:59:05 +01:00
bool Spell :: IsNeedSendToClient () const
{
2011-07-26 23:09:28 +02:00
return m_spellInfo -> SpellVisual [ 0 ] || m_spellInfo -> SpellVisual [ 1 ] || m_spellInfo -> IsChanneled () ||
2011-07-31 19:03:06 +02:00
m_spellInfo -> Speed > 0.0f || ( ! m_triggeredByAuraSpell && ! IsTriggered ());
2010-02-20 23:59:05 +01:00
}
2010-04-07 22:59:46 +02:00
bool Spell :: HaveTargetsForEffect ( uint8 effect ) const
2010-02-20 23:59:05 +01:00
{
for ( std :: list < TargetInfo >:: const_iterator itr = m_UniqueTargetInfo . begin (); itr != m_UniqueTargetInfo . end (); ++ itr )
2010-04-07 19:14:10 +02:00
if ( itr -> effectMask & ( 1 << effect ))
2010-02-20 23:59:05 +01:00
return true ;
for ( std :: list < GOTargetInfo >:: const_iterator itr = m_UniqueGOTargetInfo . begin (); itr != m_UniqueGOTargetInfo . end (); ++ itr )
2010-04-07 19:14:10 +02:00
if ( itr -> effectMask & ( 1 << effect ))
2010-02-20 23:59:05 +01:00
return true ;
for ( std :: list < ItemTargetInfo >:: const_iterator itr = m_UniqueItemInfo . begin (); itr != m_UniqueItemInfo . end (); ++ itr )
2010-04-07 19:14:10 +02:00
if ( itr -> effectMask & ( 1 << effect ))
2010-02-20 23:59:05 +01:00
return true ;
return false ;
}
SpellEvent :: SpellEvent ( Spell * spell ) : BasicEvent ()
{
m_Spell = spell ;
}
SpellEvent ::~ SpellEvent ()
{
if ( m_Spell -> getState () != SPELL_STATE_FINISHED )
m_Spell -> cancel ();
if ( m_Spell -> IsDeletable ())
{
delete m_Spell ;
}
else
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "~SpellEvent: %s %u tried to delete non-deletable spell %u. Was not deleted, causes memory leak." ,
2010-02-20 23:59:05 +01:00
( m_Spell -> GetCaster () -> GetTypeId () == TYPEID_PLAYER ? "Player" : "Creature" ), m_Spell -> GetCaster () -> GetGUIDLow (), m_Spell -> m_spellInfo -> Id );
2010-07-30 03:07:34 +02:00
ASSERT ( false );
2010-02-20 23:59:05 +01:00
}
}
bool SpellEvent :: Execute ( uint64 e_time , uint32 p_time )
{
// update spell if it is not finished
if ( m_Spell -> getState () != SPELL_STATE_FINISHED )
m_Spell -> update ( p_time );
// check spell state to process
switch ( m_Spell -> getState ())
{
case SPELL_STATE_FINISHED :
{
// spell was finished, check deletable state
if ( m_Spell -> IsDeletable ())
{
// check, if we do have unfinished triggered spells
return true ; // spell is deletable, finish event
}
// event will be re-added automatically at the end of routine)
} break ;
case SPELL_STATE_DELAYED :
{
// first, check, if we have just started
if ( m_Spell -> GetDelayStart () != 0 )
{
// no, we aren't, do the typical update
// check, if we have channeled spell on our hands
/*
if (IsChanneledSpell(m_Spell->m_spellInfo))
{
// evented channeled spell is processed separately, casted once after delay, and not destroyed till finish
// check, if we have casting anything else except this channeled spell and autorepeat
if (m_Spell->GetCaster()->IsNonMeleeSpellCasted(false, true, true))
{
// another non-melee non-delayed spell is casted now, abort
m_Spell->cancel();
}
else
{
// Set last not triggered spell for apply spellmods
((Player*)m_Spell->GetCaster())->SetSpellModTakingSpell(m_Spell, true);
// do the action (pass spell to channeling state)
m_Spell->handle_immediate();
// And remove after effect handling
((Player*)m_Spell->GetCaster())->SetSpellModTakingSpell(m_Spell, false);
}
// event will be re-added automatically at the end of routine)
}
else
*/
{
// run the spell handler and think about what we can do next
uint64 t_offset = e_time - m_Spell -> GetDelayStart ();
uint64 n_offset = m_Spell -> handle_delayed ( t_offset );
if ( n_offset )
{
// re-add us to the queue
m_Spell -> GetCaster () -> m_Events . AddEvent ( this , m_Spell -> GetDelayStart () + n_offset , false );
return false ; // event not complete
}
// event complete
// finish update event will be re-added automatically at the end of routine)
}
}
else
{
// delaying had just started, record the moment
m_Spell -> SetDelayStart ( e_time );
// re-plan the event for the delay moment
m_Spell -> GetCaster () -> m_Events . AddEvent ( this , e_time + m_Spell -> GetDelayMoment (), false );
return false ; // event not complete
}
} break ;
default :
{
// all other states
// event will be re-added automatically at the end of routine)
} break ;
}
// spell processing not complete, plan event on the next update interval
m_Spell -> GetCaster () -> m_Events . AddEvent ( this , e_time + 1 , false );
return false ; // event not complete
}
void SpellEvent :: Abort ( uint64 /*e_time*/ )
{
// oops, the spell we try to do is aborted
if ( m_Spell -> getState () != SPELL_STATE_FINISHED )
m_Spell -> cancel ();
}
bool SpellEvent :: IsDeletable () const
{
return m_Spell -> IsDeletable ();
}
2010-08-30 17:32:51 +02:00
bool Spell :: IsValidDeadOrAliveTarget ( Unit const * target ) const
{
if ( target -> isAlive ())
2011-07-26 23:09:28 +02:00
return ! m_spellInfo -> IsRequiringDeadTarget ();
if ( m_spellInfo -> IsAllowingDeadTarget ())
2010-08-30 17:32:51 +02:00
return true ;
return false ;
}
2011-09-25 13:29:17 +02:00
void Spell :: HandleLaunchPhase ()
2010-02-20 23:59:05 +01:00
{
2011-09-25 13:29:17 +02:00
// handle effects with SPELL_EFFECT_HANDLE_LAUNCH mode
for ( uint32 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
{
// don't do anything for empty effect
if ( ! m_spellInfo -> Effects [ i ]. IsEffect ())
continue ;
HandleEffects ( NULL , NULL , NULL , i , SPELL_EFFECT_HANDLE_LAUNCH );
}
2010-08-26 19:07:55 +02:00
float multiplier [ MAX_SPELL_EFFECTS ];
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2010-12-04 10:31:14 +01:00
if ( m_applyMultiplierMask & ( 1 << i ))
2011-07-26 23:09:28 +02:00
multiplier [ i ] = m_spellInfo -> Effects [ i ]. CalcDamageMultiplier ( m_originalCaster , this );
2010-02-20 23:59:05 +01:00
2011-09-25 13:29:17 +02:00
bool usesAmmo = m_spellInfo -> AttributesCu & SPELL_ATTR0_CU_DIRECT_DAMAGE ;
2010-02-20 23:59:05 +01:00
Unit :: AuraEffectList const & Auras = m_caster -> GetAuraEffectsByType ( SPELL_AURA_ABILITY_CONSUME_NO_AMMO );
for ( Unit :: AuraEffectList :: const_iterator j = Auras . begin (); j != Auras . end (); ++ j )
{
2010-04-07 19:14:10 +02:00
if (( * j ) -> IsAffectedOnSpell ( m_spellInfo ))
2010-02-20 23:59:05 +01:00
usesAmmo = false ;
}
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
{
2011-09-25 13:29:17 +02:00
TargetInfo & target = * ihit ;
2010-02-20 23:59:05 +01:00
uint32 mask = target . effectMask ;
if ( ! mask )
continue ;
2011-08-25 00:32:46 +02:00
// do not consume ammo anymore for Hunter's volley spell
if ( IsTriggered () && m_spellInfo -> SpellFamilyName == SPELLFAMILY_HUNTER && m_spellInfo -> IsAOE ())
usesAmmo = false ;
2011-08-24 23:26:25 +02:00
2010-02-20 23:59:05 +01:00
if ( usesAmmo )
{
2010-09-28 08:41:24 +03:00
bool ammoTaken = false ;
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; i ++ )
2010-02-20 23:59:05 +01:00
{
if ( ! ( mask & 1 << i ))
continue ;
2011-07-26 23:09:28 +02:00
switch ( m_spellInfo -> Effects [ i ]. Effect )
2010-02-20 23:59:05 +01:00
{
case SPELL_EFFECT_SCHOOL_DAMAGE :
case SPELL_EFFECT_WEAPON_DAMAGE :
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL :
case SPELL_EFFECT_NORMALIZED_WEAPON_DMG :
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE :
ammoTaken = true ;
TakeAmmo ();
}
if ( ammoTaken )
break ;
}
}
2011-09-25 13:29:17 +02:00
DoAllEffectOnLaunchTarget ( target , multiplier );
2010-02-20 23:59:05 +01:00
}
}
2011-09-25 13:29:17 +02:00
void Spell :: DoAllEffectOnLaunchTarget ( TargetInfo & targetInfo , float * multiplier )
2010-02-20 23:59:05 +01:00
{
2011-09-25 13:29:17 +02:00
Unit * unit = NULL ;
// In case spell hit target, do all effect on that target
if ( targetInfo . missCondition == SPELL_MISS_NONE )
unit = m_caster -> GetGUID () == targetInfo . targetGUID ? m_caster : ObjectAccessor :: GetUnit ( * m_caster , targetInfo . targetGUID );
// In case spell reflect from target, do all effect on caster (if hit)
else if ( targetInfo . missCondition == SPELL_MISS_REFLECT && targetInfo . reflectResult == SPELL_MISS_NONE )
unit = m_caster ;
if ( ! unit )
return ;
2010-09-28 08:41:24 +03:00
for ( uint32 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2010-02-20 23:59:05 +01:00
{
2011-09-25 13:29:17 +02:00
if ( targetInfo . effectMask & ( 1 << i ))
2010-02-20 23:59:05 +01:00
{
m_damage = 0 ;
2011-09-25 13:29:17 +02:00
m_healing = 0 ;
2010-02-20 23:59:05 +01:00
2011-09-25 13:29:17 +02:00
HandleEffects ( unit , NULL , NULL , i , SPELL_EFFECT_HANDLE_LAUNCH_TARGET );
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( m_damage > 0 )
2010-02-20 23:59:05 +01:00
{
2011-07-26 23:09:28 +02:00
if ( m_spellInfo -> Effects [ i ]. IsArea ())
2010-02-20 23:59:05 +01:00
{
2010-08-22 12:39:39 -07:00
m_damage = int32 ( float ( m_damage ) * unit -> GetTotalAuraMultiplierByMiscMask ( SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE , m_spellInfo -> SchoolMask ));
2010-07-16 13:20:50 +02:00
if ( m_caster -> GetTypeId () == TYPEID_UNIT )
2010-08-22 12:39:39 -07:00
m_damage = int32 ( float ( m_damage ) * unit -> GetTotalAuraMultiplierByMiscMask ( SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE , m_spellInfo -> SchoolMask ));
2010-07-16 13:20:50 +02:00
2010-02-20 23:59:05 +01:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
{
uint32 targetAmount = m_UniqueTargetInfo . size ();
if ( targetAmount > 10 )
m_damage = m_damage * 10 / targetAmount ;
}
}
}
2010-12-04 10:31:14 +01:00
if ( m_applyMultiplierMask & ( 1 << i ))
{
m_damage = int32 ( m_damage * m_damageMultipliers [ i ]);
m_damageMultipliers [ i ] *= multiplier [ i ];
}
2011-09-25 13:29:17 +02:00
targetInfo . damage += m_damage ;
2010-02-20 23:59:05 +01:00
}
}
2011-09-25 13:29:17 +02:00
targetInfo . crit = m_caster -> isSpellCrit ( unit , m_spellInfo , m_spellSchoolMask , m_attackType );
2010-02-20 23:59:05 +01:00
}
SpellCastResult Spell :: CanOpenLock ( uint32 effIndex , uint32 lockId , SkillType & skillId , int32 & reqSkillValue , int32 & skillValue )
{
2010-04-07 19:14:10 +02:00
if ( ! lockId ) // possible case for GO and maybe for items.
2010-02-20 23:59:05 +01:00
return SPELL_CAST_OK ;
// Get LockInfo
2011-09-15 14:08:17 +02:00
LockEntry const * lockInfo = sLockStore . LookupEntry ( lockId );
2010-02-20 23:59:05 +01:00
if ( ! lockInfo )
return SPELL_FAILED_BAD_TARGETS ;
bool reqKey = false ; // some locks not have reqs
2010-09-28 08:41:24 +03:00
for ( int j = 0 ; j < MAX_LOCK_CASE ; ++ j )
2010-02-20 23:59:05 +01:00
{
2011-09-05 14:01:50 +02:00
switch ( lockInfo -> Type [ j ])
2010-02-20 23:59:05 +01:00
{
// check key item (many fit cases can be)
case LOCK_KEY_ITEM :
2010-04-07 23:25:02 +02:00
if ( lockInfo -> Index [ j ] && m_CastItem && m_CastItem -> GetEntry () == lockInfo -> Index [ j ])
2010-02-20 23:59:05 +01:00
return SPELL_CAST_OK ;
reqKey = true ;
break ;
// check key skill (only single first fit case can be)
case LOCK_KEY_SKILL :
{
reqKey = true ;
// wrong locktype, skip
2011-07-26 23:09:28 +02:00
if ( uint32 ( m_spellInfo -> Effects [ effIndex ]. MiscValue ) != lockInfo -> Index [ j ])
2010-02-20 23:59:05 +01:00
continue ;
skillId = SkillByLockType ( LockType ( lockInfo -> Index [ j ]));
2010-04-07 22:59:46 +02:00
if ( skillId != SKILL_NONE )
2010-02-20 23:59:05 +01:00
{
reqSkillValue = lockInfo -> Skill [ j ];
// castitem check: rogue using skeleton keys. the skill values should not be added in this case.
skillValue = m_CastItem || m_caster -> GetTypeId () != TYPEID_PLAYER ?
2010-03-07 15:20:19 +01:00
0 : m_caster -> ToPlayer () -> GetSkillValue ( skillId );
2010-02-20 23:59:05 +01:00
2011-03-01 17:47:53 +02:00
// skill bonus provided by casting spell (mostly item spells)
// add the damage modifier from the spell casted (cheat lock / skeleton key etc.)
2011-08-16 19:44:18 +02:00
if ( m_spellInfo -> Effects [ effIndex ]. TargetA . GetTarget () == TARGET_GAMEOBJECT_ITEM_TARGET || m_spellInfo -> Effects [ effIndex ]. TargetB . GetTarget () == TARGET_GAMEOBJECT_ITEM_TARGET )
2011-03-01 17:47:53 +02:00
skillValue += uint32 ( CalculateDamage ( effIndex , NULL ));
2010-02-20 23:59:05 +01:00
if ( skillValue < reqSkillValue )
return SPELL_FAILED_LOW_CASTLEVEL ;
}
return SPELL_CAST_OK ;
}
}
}
2010-04-07 19:14:10 +02:00
if ( reqKey )
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_BAD_TARGETS ;
return SPELL_CAST_OK ;
}
void Spell :: SetSpellValue ( SpellValueMod mod , int32 value )
{
2011-05-21 21:36:37 +02:00
switch ( mod )
2010-02-20 23:59:05 +01:00
{
case SPELLVALUE_BASE_POINT0 :
2011-07-26 23:09:28 +02:00
m_spellValue -> EffectBasePoints [ 0 ] = m_spellInfo -> Effects [ EFFECT_0 ]. CalcBaseValue ( value );
2010-02-20 23:59:05 +01:00
break ;
case SPELLVALUE_BASE_POINT1 :
2011-07-26 23:09:28 +02:00
m_spellValue -> EffectBasePoints [ 1 ] = m_spellInfo -> Effects [ EFFECT_1 ]. CalcBaseValue ( value );
2010-02-20 23:59:05 +01:00
break ;
case SPELLVALUE_BASE_POINT2 :
2011-07-26 23:09:28 +02:00
m_spellValue -> EffectBasePoints [ 2 ] = m_spellInfo -> Effects [ EFFECT_2 ]. CalcBaseValue ( value );
2010-02-20 23:59:05 +01:00
break ;
case SPELLVALUE_RADIUS_MOD :
m_spellValue -> RadiusMod = ( float ) value / 10000 ;
break ;
case SPELLVALUE_MAX_TARGETS :
m_spellValue -> MaxAffectedTargets = ( uint32 ) value ;
break ;
2011-05-21 21:36:37 +02:00
case SPELLVALUE_AURA_STACK :
m_spellValue -> AuraStackAmount = uint8 ( value );
break ;
2010-02-20 23:59:05 +01:00
}
}
float tangent ( float x )
{
x = tan ( x );
2010-04-07 19:14:10 +02:00
//if (x < std::numeric_limits<float>::max() && x > -std::numeric_limits<float>::max()) return x;
//if (x >= std::numeric_limits<float>::max()) return std::numeric_limits<float>::max();
//if (x <= -std::numeric_limits<float>::max()) return -std::numeric_limits<float>::max();
if ( x < 100000.0f && x > - 100000.0f ) return x ;
if ( x >= 100000.0f ) return 100000.0f ;
if ( x <= 100000.0f ) return - 100000.0f ;
2010-02-20 23:59:05 +01:00
return 0.0f ;
}
#define DEBUG_TRAJ(a) //a
void Spell :: SelectTrajTargets ()
{
2010-04-07 19:14:10 +02:00
if ( ! m_targets . HasTraj ())
2010-02-20 23:59:05 +01:00
return ;
float dist2d = m_targets . GetDist2d ();
2010-04-07 19:14:10 +02:00
if ( ! dist2d )
2010-02-20 23:59:05 +01:00
return ;
2011-06-23 13:28:52 +02:00
float dz = m_targets . GetDst () -> m_positionZ - m_targets . GetSrc () -> m_positionZ ;
2010-02-20 23:59:05 +01:00
UnitList unitList ;
SearchAreaTarget ( unitList , dist2d , PUSH_IN_THIN_LINE , SPELL_TARGETS_ANY );
2010-04-07 19:14:10 +02:00
if ( unitList . empty ())
2010-02-20 23:59:05 +01:00
return ;
2010-05-30 04:23:27 +02:00
unitList . sort ( Trinity :: ObjectDistanceOrderPred ( m_caster ));
2010-02-20 23:59:05 +01:00
2011-06-23 13:28:52 +02:00
float b = tangent ( m_targets . GetElevation ());
2010-02-20 23:59:05 +01:00
float a = ( dz - dist2d * b ) / ( dist2d * dist2d );
2010-04-07 19:14:10 +02:00
if ( a > - 0.0001f ) a = 0 ;
2010-12-23 23:25:44 +01:00
DEBUG_TRAJ ( sLog -> outError ( "Spell::SelectTrajTargets: a %f b %f" , a , b );)
2010-02-20 23:59:05 +01:00
2011-07-26 23:09:28 +02:00
float bestDist = m_spellInfo -> GetMaxRange ( false );
2010-02-20 23:59:05 +01:00
UnitList :: const_iterator itr = unitList . begin ();
for (; itr != unitList . end (); ++ itr )
{
2010-04-07 19:14:10 +02:00
if ( m_caster == * itr || m_caster -> IsOnVehicle ( * itr ) || ( * itr ) -> GetVehicle ()) //(*itr)->IsOnVehicle(m_caster))
2010-02-20 23:59:05 +01:00
continue ;
const float size = std :: max (( * itr ) -> GetObjectSize () * 0.7f , 1.0f ); // 1/sqrt(3)
// TODO: all calculation should be based on src instead of m_caster
2011-06-23 13:28:52 +02:00
const float objDist2d = m_targets . GetSrc () -> GetExactDist2d ( * itr ) * cos ( m_targets . GetSrc () -> GetRelativeAngle ( * itr ));
const float dz = ( * itr ) -> GetPositionZ () - m_targets . GetSrc () -> m_positionZ ;
2010-02-20 23:59:05 +01:00
2010-12-23 23:25:44 +01:00
DEBUG_TRAJ ( sLog -> outError ( "Spell::SelectTrajTargets: check %u, dist between %f %f, height between %f %f." , ( * itr ) -> GetEntry (), objDist2d - size , objDist2d + size , dz - size , dz + size );)
2010-02-20 23:59:05 +01:00
float dist = objDist2d - size ;
float height = dist * ( a * dist + b );
2010-12-23 23:25:44 +01:00
DEBUG_TRAJ ( sLog -> outError ( "Spell::SelectTrajTargets: dist %f, height %f." , dist , height );)
2010-04-07 19:14:10 +02:00
if ( dist < bestDist && height < dz + size && height > dz - size )
2010-02-20 23:59:05 +01:00
{
bestDist = dist > 0 ? dist : 0 ;
break ;
}
#define CHECK_DIST {\
2010-12-23 23:25:44 +01:00
DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: dist %f, height %f.", dist, height);)\
2010-04-07 19:14:10 +02:00
if (dist > bestDist) continue;\
if (dist < objDist2d + size && dist > objDist2d - size) { bestDist = dist; break; }\
2010-02-20 23:59:05 +01:00
}
2010-04-07 19:14:10 +02:00
if ( ! a )
2010-02-20 23:59:05 +01:00
{
height = dz - size ;
dist = height / b ;
CHECK_DIST ;
height = dz + size ;
dist = height / b ;
CHECK_DIST ;
continue ;
}
height = dz - size ;
float sqrt1 = b * b + 4 * a * height ;
2010-04-07 19:14:10 +02:00
if ( sqrt1 > 0 )
2010-02-20 23:59:05 +01:00
{
sqrt1 = sqrt ( sqrt1 );
dist = ( sqrt1 - b ) / ( 2 * a );
CHECK_DIST ;
}
height = dz + size ;
float sqrt2 = b * b + 4 * a * height ;
2010-04-07 19:14:10 +02:00
if ( sqrt2 > 0 )
2010-02-20 23:59:05 +01:00
{
sqrt2 = sqrt ( sqrt2 );
dist = ( sqrt2 - b ) / ( 2 * a );
CHECK_DIST ;
dist = ( - sqrt2 - b ) / ( 2 * a );
CHECK_DIST ;
}
2010-04-07 19:14:10 +02:00
if ( sqrt1 > 0 )
2010-02-20 23:59:05 +01:00
{
dist = ( - sqrt1 - b ) / ( 2 * a );
CHECK_DIST ;
}
}
2011-06-23 13:28:52 +02:00
if ( m_targets . GetSrc () -> GetExactDist2d ( m_targets . GetDst ()) > bestDist )
2010-02-20 23:59:05 +01:00
{
2011-06-23 13:28:52 +02:00
float x = m_targets . GetSrc () -> m_positionX + cos ( m_caster -> GetOrientation ()) * bestDist ;
float y = m_targets . GetSrc () -> m_positionY + sin ( m_caster -> GetOrientation ()) * bestDist ;
float z = m_targets . GetSrc () -> m_positionZ + bestDist * ( a * bestDist + b );
2010-02-20 23:59:05 +01:00
2010-04-07 19:14:10 +02:00
if ( itr != unitList . end ())
2010-02-20 23:59:05 +01:00
{
float distSq = ( * itr ) -> GetExactDistSq ( x , y , z );
float sizeSq = ( * itr ) -> GetObjectSize ();
sizeSq *= sizeSq ;
2010-12-23 23:25:44 +01:00
DEBUG_TRAJ ( sLog -> outError ( "Initial %f %f %f %f %f" , x , y , z , distSq , sizeSq );)
2010-04-07 19:14:10 +02:00
if ( distSq > sizeSq )
2010-02-20 23:59:05 +01:00
{
float factor = 1 - sqrt ( sizeSq / distSq );
x += factor * (( * itr ) -> GetPositionX () - x );
y += factor * (( * itr ) -> GetPositionY () - y );
z += factor * (( * itr ) -> GetPositionZ () - z );
distSq = ( * itr ) -> GetExactDistSq ( x , y , z );
2010-12-23 23:25:44 +01:00
DEBUG_TRAJ ( sLog -> outError ( "Initial %f %f %f %f %f" , x , y , z , distSq , sizeSq );)
2010-02-20 23:59:05 +01:00
}
}
2010-08-08 20:32:14 +02:00
Position trajDst ;
trajDst . Relocate ( x , y , z , m_caster -> GetOrientation ());
2011-06-23 13:28:52 +02:00
m_targets . ModDst ( trajDst );
2010-02-20 23:59:05 +01:00
}
}
2010-07-24 22:41:42 +02:00
2010-08-27 17:49:32 +02:00
void Spell :: PrepareTargetProcessing ()
{
CheckEffectExecuteData ();
}
void Spell :: FinishTargetProcessing ()
{
SendLogExecute ();
}
void Spell :: InitEffectExecuteData ( uint8 effIndex )
{
ASSERT ( effIndex < MAX_SPELL_EFFECTS );
if ( ! m_effectExecuteData [ effIndex ])
{
2010-08-27 23:12:52 +02:00
m_effectExecuteData [ effIndex ] = new ByteBuffer ( 0x20 );
2010-08-27 17:49:32 +02:00
// first dword - target counter
* m_effectExecuteData [ effIndex ] << uint32 ( 1 );
}
else
{
// increase target counter by one
uint32 count = ( * m_effectExecuteData [ effIndex ]). read < uint32 > ( 0 );
( * m_effectExecuteData [ effIndex ]). put < uint32 > ( 0 , ++ count );
}
}
void Spell :: CleanupEffectExecuteData ()
{
2011-01-22 17:21:24 +01:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2010-08-27 17:49:32 +02:00
m_effectExecuteData [ i ] = NULL ;
}
void Spell :: CheckEffectExecuteData ()
{
2011-01-22 17:21:24 +01:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2010-08-27 17:49:32 +02:00
ASSERT ( ! m_effectExecuteData [ i ]);
}
2010-07-24 22:41:42 +02:00
void Spell :: LoadScripts ()
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell::LoadScripts" );
2010-12-22 21:25:23 +01:00
sScriptMgr -> CreateSpellScripts ( m_spellInfo -> Id , m_loadedScripts );
2011-09-15 14:08:17 +02:00
for ( std :: list < SpellScript *>:: iterator itr = m_loadedScripts . begin (); itr != m_loadedScripts . end () ;)
2010-07-24 22:41:42 +02:00
{
if ( ! ( * itr ) -> _Load ( this ))
{
2011-09-15 14:08:17 +02:00
std :: list < SpellScript *>:: iterator bitr = itr ;
2010-07-24 22:41:42 +02:00
++ itr ;
m_loadedScripts . erase ( bitr );
continue ;
}
( * itr ) -> Register ();
++ itr ;
}
}
2010-08-19 14:31:31 +02:00
2010-08-21 20:18:54 +02:00
void Spell :: PrepareScriptHitHandlers ()
2010-08-19 14:31:31 +02:00
{
2011-09-15 14:08:17 +02:00
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end () ; ++ scritr )
2010-08-19 14:31:31 +02:00
( * scritr ) -> _InitHit ();
}
2010-08-21 20:18:54 +02:00
2011-03-04 21:18:38 +01:00
SpellCastResult Spell :: CallScriptCheckCastHandlers ()
{
SpellCastResult retVal = SPELL_CAST_OK ;
2011-09-15 14:08:17 +02:00
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end () ; ++ scritr )
2011-03-04 21:18:38 +01:00
{
( * scritr ) -> _PrepareScriptCall ( SPELL_SCRIPT_HOOK_CHECK_CAST );
std :: list < SpellScript :: CheckCastHandler >:: iterator hookItrEnd = ( * scritr ) -> OnCheckCast . end (), hookItr = ( * scritr ) -> OnCheckCast . begin ();
for (; hookItr != hookItrEnd ; ++ hookItr )
{
SpellCastResult tempResult = ( * hookItr ). Call ( * scritr );
if ( retVal == SPELL_CAST_OK )
retVal = tempResult ;
}
( * scritr ) -> _FinishScriptCall ();
}
return retVal ;
}
2011-09-25 13:29:17 +02:00
bool Spell :: CallScriptEffectHandlers ( SpellEffIndex effIndex , SpellEffectHandleMode mode )
2010-08-21 20:18:54 +02:00
{
// execute script effect handler hooks and check if effects was prevented
bool preventDefault = false ;
2011-09-15 14:08:17 +02:00
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end () ; ++ scritr )
2010-08-21 20:18:54 +02:00
{
2011-09-25 13:29:17 +02:00
std :: list < SpellScript :: EffectHandler >:: iterator effItr , effEndItr ;
SpellScriptHookType hookType ;
switch ( mode )
{
case SPELL_EFFECT_HANDLE_LAUNCH :
effItr = ( * scritr ) -> OnEffectLaunch . begin ();
effEndItr = ( * scritr ) -> OnEffectLaunch . end ();
hookType = SPELL_SCRIPT_HOOK_EFFECT_LAUNCH ;
break ;
case SPELL_EFFECT_HANDLE_LAUNCH_TARGET :
effItr = ( * scritr ) -> OnEffectLaunchTarget . begin ();
effEndItr = ( * scritr ) -> OnEffectLaunchTarget . end ();
hookType = SPELL_SCRIPT_HOOK_EFFECT_LAUNCH_TARGET ;
break ;
case SPELL_EFFECT_HANDLE_HIT :
effItr = ( * scritr ) -> OnEffectHit . begin ();
effEndItr = ( * scritr ) -> OnEffectHit . end ();
hookType = SPELL_SCRIPT_HOOK_EFFECT_HIT ;
break ;
case SPELL_EFFECT_HANDLE_HIT_TARGET :
effItr = ( * scritr ) -> OnEffectHitTarget . begin ();
effEndItr = ( * scritr ) -> OnEffectHitTarget . end ();
hookType = SPELL_SCRIPT_HOOK_EFFECT_HIT_TARGET ;
break ;
default :
ASSERT ( false );
break ;
}
( * scritr ) -> _PrepareScriptCall ( hookType );
2011-01-22 17:21:24 +01:00
for (; effItr != effEndItr ; ++ effItr )
2010-08-21 20:18:54 +02:00
// effect execution can be prevented
if ( ! ( * scritr ) -> _IsEffectPrevented ( effIndex ) && ( * effItr ). IsEffectAffected ( m_spellInfo , effIndex ))
( * effItr ). Call ( * scritr , effIndex );
2011-01-22 17:21:24 +01:00
2010-08-21 20:18:54 +02:00
if ( ! preventDefault )
preventDefault = ( * scritr ) -> _IsDefaultEffectPrevented ( effIndex );
2011-01-22 17:21:24 +01:00
2010-10-05 08:17:10 +02:00
( * scritr ) -> _FinishScriptCall ();
2010-08-21 20:18:54 +02:00
}
return preventDefault ;
}
void Spell :: CallScriptBeforeHitHandlers ()
{
2011-09-15 14:08:17 +02:00
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end () ; ++ scritr )
2010-08-21 20:18:54 +02:00
{
2010-10-05 08:17:10 +02:00
( * scritr ) -> _PrepareScriptCall ( SPELL_SCRIPT_HOOK_BEFORE_HIT );
2010-08-21 20:18:54 +02:00
std :: list < SpellScript :: HitHandler >:: iterator hookItrEnd = ( * scritr ) -> BeforeHit . end (), hookItr = ( * scritr ) -> BeforeHit . begin ();
2011-01-22 17:21:24 +01:00
for (; hookItr != hookItrEnd ; ++ hookItr )
2010-10-08 21:33:44 +02:00
( * hookItr ). Call ( * scritr );
2011-01-22 17:21:24 +01:00
2010-10-05 08:17:10 +02:00
( * scritr ) -> _FinishScriptCall ();
2010-08-21 20:18:54 +02:00
}
}
void Spell :: CallScriptOnHitHandlers ()
{
2011-09-15 14:08:17 +02:00
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end () ; ++ scritr )
2010-08-21 20:18:54 +02:00
{
2010-10-05 08:17:10 +02:00
( * scritr ) -> _PrepareScriptCall ( SPELL_SCRIPT_HOOK_HIT );
2010-08-21 20:18:54 +02:00
std :: list < SpellScript :: HitHandler >:: iterator hookItrEnd = ( * scritr ) -> OnHit . end (), hookItr = ( * scritr ) -> OnHit . begin ();
2011-01-22 17:21:24 +01:00
for (; hookItr != hookItrEnd ; ++ hookItr )
2010-10-08 21:33:44 +02:00
( * hookItr ). Call ( * scritr );
2011-01-22 17:21:24 +01:00
2010-10-05 08:17:10 +02:00
( * scritr ) -> _FinishScriptCall ();
2010-08-21 20:18:54 +02:00
}
}
void Spell :: CallScriptAfterHitHandlers ()
{
2011-09-15 14:08:17 +02:00
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end () ; ++ scritr )
2010-08-21 20:18:54 +02:00
{
2010-10-05 08:17:10 +02:00
( * scritr ) -> _PrepareScriptCall ( SPELL_SCRIPT_HOOK_AFTER_HIT );
2010-08-21 20:18:54 +02:00
std :: list < SpellScript :: HitHandler >:: iterator hookItrEnd = ( * scritr ) -> AfterHit . end (), hookItr = ( * scritr ) -> AfterHit . begin ();
2011-01-22 17:21:24 +01:00
for (; hookItr != hookItrEnd ; ++ hookItr )
2010-10-08 21:33:44 +02:00
( * hookItr ). Call ( * scritr );
2011-01-22 17:21:24 +01:00
2010-10-05 08:17:10 +02:00
( * scritr ) -> _FinishScriptCall ();
2010-08-21 20:18:54 +02:00
}
}
2011-01-21 23:42:51 +01:00
void Spell :: CallScriptAfterUnitTargetSelectHandlers ( std :: list < Unit *>& unitTargets , SpellEffIndex effIndex )
{
2011-09-15 14:08:17 +02:00
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end () ; ++ scritr )
2011-01-21 23:42:51 +01:00
{
( * scritr ) -> _PrepareScriptCall ( SPELL_SCRIPT_HOOK_UNIT_TARGET_SELECT );
std :: list < SpellScript :: UnitTargetHandler >:: iterator hookItrEnd = ( * scritr ) -> OnUnitTargetSelect . end (), hookItr = ( * scritr ) -> OnUnitTargetSelect . begin ();
2011-01-22 17:21:24 +01:00
for (; hookItr != hookItrEnd ; ++ hookItr )
2011-01-21 23:42:51 +01:00
if (( * hookItr ). IsEffectAffected ( m_spellInfo , effIndex ))
2011-01-22 17:21:24 +01:00
( * hookItr ). Call ( * scritr , unitTargets );
2011-01-21 23:42:51 +01:00
( * scritr ) -> _FinishScriptCall ();
}
}
2011-02-22 17:02:47 +06:00
2011-10-19 22:08:54 +02:00
bool Spell :: CanExecuteTriggersOnHit ( uint8 effMask , SpellInfo const * spellInfo ) const
2011-06-26 00:29:12 +02:00
{
2011-10-19 22:08:54 +02:00
bool only_on_dummy = ( spellInfo && ( spellInfo -> AttributesEx4 & SPELL_ATTR4_PROC_ONLY_ON_DUMMY ));
// If triggered spell has SPELL_ATTR4_PROC_ONLY_ON_DUMMY then it can only proc on a casted spell with SPELL_EFFECT_DUMMY
// If triggered spell doesn't have SPELL_ATTR4_PROC_ONLY_ON_DUMMY then it can NOT proc on SPELL_EFFECT_DUMMY (needs confirmation)
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2011-06-26 00:29:12 +02:00
{
2011-10-19 22:08:54 +02:00
if (( effMask & ( 1 << i )) && ( only_on_dummy == ( m_spellInfo -> Effects [ i ]. Effect == SPELL_EFFECT_DUMMY )))
return true ;
2011-06-26 00:29:12 +02:00
}
2011-10-19 22:08:54 +02:00
return false ;
2011-06-26 00:29:12 +02:00
}
void Spell :: PrepareTriggersExecutedOnHit ()
{
// todo: move this to scripts
if ( m_spellInfo -> SpellFamilyName )
{
2011-07-26 23:09:28 +02:00
SpellInfo const * excludeCasterSpellInfo = sSpellMgr -> GetSpellInfo ( m_spellInfo -> ExcludeCasterAuraSpell );
if ( excludeCasterSpellInfo && ! excludeCasterSpellInfo -> IsPositive ())
m_preCastSpell = m_spellInfo -> ExcludeCasterAuraSpell ;
SpellInfo const * excludeTargetSpellInfo = sSpellMgr -> GetSpellInfo ( m_spellInfo -> ExcludeTargetAuraSpell );
if ( excludeTargetSpellInfo && ! excludeTargetSpellInfo -> IsPositive ())
m_preCastSpell = m_spellInfo -> ExcludeTargetAuraSpell ;
2011-06-26 00:29:12 +02:00
}
// todo: move this to scripts
switch ( m_spellInfo -> SpellFamilyName )
{
case SPELLFAMILY_GENERIC :
{
if ( m_spellInfo -> Mechanic == MECHANIC_BANDAGE ) // Bandages
m_preCastSpell = 11196 ; // Recently Bandaged
break ;
}
case SPELLFAMILY_MAGE :
{
// Permafrost
if ( m_spellInfo -> SpellFamilyFlags [ 1 ] & 0x00001000 || m_spellInfo -> SpellFamilyFlags [ 0 ] & 0x00100220 )
m_preCastSpell = 68391 ;
break ;
}
}
// handle SPELL_AURA_ADD_TARGET_TRIGGER auras:
// save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster
// and to correctly calculate proc chance when combopoints are present
Unit :: AuraEffectList const & targetTriggers = m_caster -> GetAuraEffectsByType ( SPELL_AURA_ADD_TARGET_TRIGGER );
for ( Unit :: AuraEffectList :: const_iterator i = targetTriggers . begin (); i != targetTriggers . end (); ++ i )
{
if ( ! ( * i ) -> IsAffectedOnSpell ( m_spellInfo ))
continue ;
2011-09-15 14:08:17 +02:00
SpellInfo const * auraSpellInfo = ( * i ) -> GetSpellInfo ();
2011-06-26 00:29:12 +02:00
uint32 auraSpellIdx = ( * i ) -> GetEffIndex ();
2011-09-15 14:08:17 +02:00
if ( SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( auraSpellInfo -> Effects [ auraSpellIdx ]. TriggerSpell ))
2011-06-26 00:29:12 +02:00
{
// calculate the chance using spell base amount, because aura amount is not updated on combo-points change
// this possibly needs fixing
int32 auraBaseAmount = ( * i ) -> GetBaseAmount ();
int32 chance = m_caster -> CalculateSpellDamage ( NULL , auraSpellInfo , auraSpellIdx , & auraBaseAmount );
// proc chance is stored in effect amount
m_hitTriggerSpells . push_back ( std :: make_pair ( spellInfo , chance * ( * i ) -> GetBase () -> GetStackAmount ()));
}
}
}
2011-02-22 23:20:21 +06:00
// Global cooldowns management
enum GCDLimits
{
2011-02-22 17:02:47 +06:00
MIN_GCD = 1000 ,
MAX_GCD = 1500
};
2011-08-21 13:57:15 +02:00
bool Spell :: HasGlobalCooldown () const
2011-02-22 17:02:47 +06:00
{
// Only player or controlled units have global cooldown
if ( m_caster -> GetCharmInfo ())
return m_caster -> GetCharmInfo () -> GetGlobalCooldownMgr (). HasGlobalCooldown ( m_spellInfo );
else if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
return m_caster -> ToPlayer () -> GetGlobalCooldownMgr (). HasGlobalCooldown ( m_spellInfo );
else
return false ;
}
void Spell :: TriggerGlobalCooldown ()
{
int32 gcd = m_spellInfo -> StartRecoveryTime ;
if ( ! gcd )
return ;
// Global cooldown can't leave range 1..1.5 secs
// There are some spells (mostly not casted directly by player) that have < 1 sec and > 1.5 sec global cooldowns
// but as tests show are not affected by any spell mods.
if ( m_spellInfo -> StartRecoveryTime >= MIN_GCD && m_spellInfo -> StartRecoveryTime <= MAX_GCD )
{
// gcd modifier auras are applied only to own spells and only players have such mods
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
m_caster -> ToPlayer () -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_GLOBAL_COOLDOWN , gcd , this );
// Apply haste rating
gcd = int32 ( float ( gcd ) * m_caster -> GetFloatValue ( UNIT_MOD_CAST_SPEED ));
if ( gcd < MIN_GCD )
gcd = MIN_GCD ;
else if ( gcd > MAX_GCD )
gcd = MAX_GCD ;
}
// Only players or controlled units have global cooldown
if ( m_caster -> GetCharmInfo ())
m_caster -> GetCharmInfo () -> GetGlobalCooldownMgr (). AddGlobalCooldown ( m_spellInfo , gcd );
else if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
m_caster -> ToPlayer () -> GetGlobalCooldownMgr (). AddGlobalCooldown ( m_spellInfo , gcd );
}
void Spell :: CancelGlobalCooldown ()
{
if ( ! m_spellInfo -> StartRecoveryTime )
return ;
// Cancel global cooldown when interrupting current cast
if ( m_caster -> GetCurrentSpell ( CURRENT_GENERIC_SPELL ) != this )
return ;
// Only players or controlled units have global cooldown
if ( m_caster -> GetCharmInfo ())
m_caster -> GetCharmInfo () -> GetGlobalCooldownMgr (). CancelGlobalCooldown ( m_spellInfo );
else if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
m_caster -> ToPlayer () -> GetGlobalCooldownMgr (). CancelGlobalCooldown ( m_spellInfo );
}