2010-10-07 15:35:36 +02:00
/*
2012-01-01 00:32:13 +01:00
* Copyright (C) 2008-2012 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"
2012-08-20 16:23:24 -04:00
#include "Battlefield.h"
#include "BattlefieldMgr.h"
2010-02-20 23:59:05 +01:00
extern pEffect SpellEffects [ TOTAL_SPELL_EFFECTS ];
2012-03-03 00:19:00 +01:00
SpellDestination :: SpellDestination ()
{
_position . Relocate ( 0 , 0 , 0 , 0 );
_transportGUID = 0 ;
_transportOffset . Relocate ( 0 , 0 , 0 , 0 );
}
SpellDestination :: SpellDestination ( float x , float y , float z , float orientation , uint32 mapId )
{
_position . Relocate ( x , y , z , orientation );
_transportGUID = 0 ;
_position . m_mapId = mapId ;
}
SpellDestination :: SpellDestination ( Position const & pos )
{
_position . Relocate ( pos );
_transportGUID = 0 ;
}
SpellDestination :: SpellDestination ( WorldObject const & wObj )
{
_transportGUID = wObj . GetTransGUID ();
_transportOffset . Relocate ( wObj . GetTransOffsetX (), wObj . GetTransOffsetY (), wObj . GetTransOffsetZ (), wObj . GetTransOffsetO ());
_position . Relocate ( wObj );
_position . SetOrientation ( wObj . GetOrientation ());
}
2012-08-30 22:44:33 +01:00
SpellCastTargets :: SpellCastTargets () : m_elevation ( 0 ), m_speed ( 0 ), m_strTarget ()
2010-02-20 23:59:05 +01:00
{
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 ;
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 )
{
2012-03-03 00:19:00 +01:00
data . readPackGUID ( m_src . _transportGUID );
if ( m_src . _transportGUID )
data >> m_src . _transportOffset . PositionXYZStream ();
2011-06-23 13:28:52 +02:00
else
2012-03-03 00:19:00 +01:00
data >> m_src . _position . PositionXYZStream ();
2011-06-23 13:28:52 +02:00
}
else
{
2012-03-03 00:19:00 +01:00
m_src . _transportGUID = caster -> GetTransGUID ();
if ( m_src . _transportGUID )
m_src . _transportOffset . Relocate ( caster -> GetTransOffsetX (), caster -> GetTransOffsetY (), caster -> GetTransOffsetZ (), caster -> GetTransOffsetO ());
2011-06-23 13:28:52 +02:00
else
2012-03-03 00:19:00 +01:00
m_src . _position . Relocate ( caster );
2011-06-23 13:28:52 +02:00
}
if ( m_targetMask & TARGET_FLAG_DEST_LOCATION )
{
2012-03-03 00:19:00 +01:00
data . readPackGUID ( m_dst . _transportGUID );
if ( m_dst . _transportGUID )
data >> m_dst . _transportOffset . PositionXYZStream ();
2011-06-23 13:28:52 +02:00
else
2012-03-03 00:19:00 +01:00
data >> m_dst . _position . PositionXYZStream ();
2011-06-23 13:28:52 +02:00
}
else
{
2012-03-03 00:19:00 +01:00
m_dst . _transportGUID = caster -> GetTransGUID ();
if ( m_dst . _transportGUID )
m_dst . _transportOffset . Relocate ( caster -> GetTransOffsetX (), caster -> GetTransOffsetY (), caster -> GetTransOffsetZ (), caster -> GetTransOffsetO ());
2011-06-23 13:28:52 +02:00
else
2012-03-03 00:19:00 +01:00
m_dst . _position . Relocate ( caster );
2011-06-23 13:28:52 +02:00
}
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 )
{
2012-03-03 00:19:00 +01:00
data . appendPackGUID ( m_src . _transportGUID ); // relative position guid here - transport for example
if ( m_src . _transportGUID )
data << m_src . _transportOffset . PositionXYZStream ();
2011-06-23 13:28:52 +02:00
else
2012-03-03 00:19:00 +01:00
data << m_src . _position . PositionXYZStream ();
2011-06-23 13:28:52 +02:00
}
if ( m_targetMask & TARGET_FLAG_DEST_LOCATION )
{
2012-03-03 00:19:00 +01:00
data . appendPackGUID ( m_dst . _transportGUID ); // relative position guid here - transport for example
if ( m_dst . _transportGUID )
data << m_dst . _transportOffset . PositionXYZStream ();
2011-06-23 13:28:52 +02:00
else
2012-03-03 00:19:00 +01:00
data << m_dst . _position . PositionXYZStream ();
2011-06-23 13:28:52 +02:00
}
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 ();
}
}
2012-03-03 00:19:00 +01:00
SpellDestination const * SpellCastTargets :: GetSrc () const
{
return & m_src ;
}
Position const * SpellCastTargets :: GetSrcPos () const
2011-06-23 13:28:52 +02:00
{
2012-03-03 00:19:00 +01:00
return & m_src . _position ;
2011-06-23 13:28:52 +02:00
}
void SpellCastTargets :: SetSrc ( float x , float y , float z )
2010-02-20 23:59:05 +01:00
{
2012-03-03 00:19:00 +01:00
m_src = SpellDestination ( x , y , z );
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
{
2012-03-03 00:19:00 +01:00
m_src = SpellDestination ( pos );
2010-08-08 20:32:14 +02:00
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
{
2012-03-03 00:19:00 +01:00
m_src = SpellDestination ( wObj );
2010-08-08 20:32:14 +02:00
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 );
2012-03-03 00:19:00 +01:00
if ( m_src . _transportGUID )
2010-02-20 23:59:05 +01:00
{
2010-08-08 20:32:14 +02:00
Position offset ;
2012-03-03 00:19:00 +01:00
m_src . _position . GetPositionOffsetTo ( pos , offset );
m_src . _transportOffset . RelocateOffset ( offset );
2010-02-20 23:59:05 +01:00
}
2012-03-03 00:19:00 +01:00
m_src . _position . 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 );
}
2012-03-03 00:19:00 +01:00
SpellDestination const * SpellCastTargets :: GetDst () const
2011-06-23 13:28:52 +02:00
{
2012-03-03 00:19:00 +01:00
return & m_dst ;
}
WorldLocation const * SpellCastTargets :: GetDstPos () const
{
return & m_dst . _position ;
2011-06-23 13:28:52 +02:00
}
void SpellCastTargets :: SetDst ( float x , float y , float z , float orientation , uint32 mapId )
2010-02-20 23:59:05 +01:00
{
2012-03-03 00:19:00 +01:00
m_dst = SpellDestination ( x , y , z , orientation , mapId );
2010-08-02 20:05:22 +02:00
m_targetMask |= TARGET_FLAG_DEST_LOCATION ;
2010-02-20 23:59:05 +01:00
}
2011-06-23 13:28:52 +02:00
void SpellCastTargets :: SetDst ( Position const & pos )
2010-08-08 20:32:14 +02:00
{
2012-03-03 00:19:00 +01:00
m_dst = SpellDestination ( pos );
2010-08-08 20:32:14 +02:00
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
{
2012-03-03 00:19:00 +01:00
m_dst = SpellDestination ( wObj );
2010-08-08 20:32:14 +02:00
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
{
2012-03-03 00:19:00 +01:00
m_dst = spellTargets . m_dst ;
2011-09-05 14:01:50 +02:00
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 );
2012-03-03 00:19:00 +01:00
if ( m_dst . _transportGUID )
2010-02-20 23:59:05 +01:00
{
2010-08-08 20:32:14 +02:00
Position offset ;
2012-03-03 00:19:00 +01:00
m_dst . _position . GetPositionOffsetTo ( pos , offset );
m_dst . _transportOffset . RelocateOffset ( offset );
2010-02-20 23:59:05 +01:00
}
2012-03-03 00:19:00 +01:00
m_dst . _position . 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
2012-03-03 00:19:00 +01:00
if ( HasSrc () && m_src . _transportGUID )
2010-08-08 20:32:14 +02:00
{
2012-03-03 00:19:00 +01:00
if ( WorldObject * transport = ObjectAccessor :: GetWorldObject ( * caster , m_src . _transportGUID ))
2010-08-08 20:32:14 +02:00
{
2012-03-03 00:19:00 +01:00
m_src . _position . Relocate ( transport );
m_src . _position . RelocateOffset ( m_src . _transportOffset );
2010-08-08 20:32:14 +02:00
}
}
2011-05-22 16:01:53 -07:00
2012-03-03 00:19:00 +01:00
if ( HasDst () && m_dst . _transportGUID )
2010-08-08 20:32:14 +02:00
{
2012-03-03 00:19:00 +01:00
if ( WorldObject * transport = ObjectAccessor :: GetWorldObject ( * caster , m_dst . _transportGUID ))
2010-08-08 20:32:14 +02:00
{
2012-03-03 00:19:00 +01:00
m_dst . _position . Relocate ( transport );
m_dst . _position . RelocateOffset ( m_dst . _transportOffset );
2010-08-08 20:32:14 +02:00
}
}
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 )
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_SPELLS_AURAS , "No targets" );
2011-08-26 12:05:47 +02:00
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_SPELLS_AURAS , "target mask: %u" , m_targetMask );
2011-08-26 12:05:47 +02:00
if ( m_targetMask & ( TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK ))
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_SPELLS_AURAS , "Object target: " UI64FMTD , m_objectTargetGUID );
2010-08-08 20:32:14 +02:00
if ( m_targetMask & TARGET_FLAG_ITEM )
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_SPELLS_AURAS , "Item target: " UI64FMTD , m_itemTargetGUID );
2010-08-08 20:32:14 +02:00
if ( m_targetMask & TARGET_FLAG_TRADE_ITEM )
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_SPELLS_AURAS , "Trade item target: " UI64FMTD , m_itemTargetGUID );
2010-08-08 20:32:14 +02:00
if ( m_targetMask & TARGET_FLAG_SOURCE_LOCATION )
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_SPELLS_AURAS , "Source location: transport guid:" UI64FMTD " trans offset: %s position: %s" , m_src . _transportGUID , m_src . _transportOffset . ToString (). c_str (), m_src . _position . ToString (). c_str ());
2010-08-08 20:32:14 +02:00
if ( m_targetMask & TARGET_FLAG_DEST_LOCATION )
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_SPELLS_AURAS , "Destination location: transport guid:" UI64FMTD " trans offset: %s position: %s" , m_dst . _transportGUID , m_dst . _transportOffset . ToString (). c_str (), m_dst . _position . ToString (). c_str ());
2010-08-08 20:32:14 +02:00
if ( m_targetMask & TARGET_FLAG_STRING )
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_SPELLS_AURAS , "String: %s" , m_strTarget . c_str ());
sLog -> outInfo ( LOG_FILTER_SPELLS_AURAS , "speed: %f" , m_speed );
sLog -> outInfo ( LOG_FILTER_SPELLS_AURAS , "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 )
2012-03-14 18:51:51 +01:00
if ( Item * pItem = m_caster -> ToPlayer () -> GetWeaponForAttack ( RANGED_ATTACK ))
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 ();
2012-09-04 22:38:59 -04:00
memset ( m_effectExecuteData , NULL , MAX_SPELL_EFFECTS * sizeof ( ByteBuffer * ));
2012-03-03 00:19:00 +01:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
m_destTargets [ i ] = SpellDestination ( * m_caster );
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.
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SPELLS_AURAS , "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
}
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-11-23 19:17:33 +01:00
Unit * unit = 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-11-23 19:17:33 +01:00
unit = selectedUnit ;
2011-08-24 08:07:59 +02:00
}
// try to use attacked unit as a target
else if (( m_caster -> GetTypeId () == TYPEID_UNIT ) && neededTargets & ( TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT ))
2011-11-23 19:17:33 +01:00
unit = m_caster -> getVictim ();
2011-08-24 08:07:59 +02:00
// didn't find anything - let's use self as target
2011-11-23 19:17:33 +01:00
if ( ! unit && neededTargets & ( TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_ALLY ))
unit = m_caster ;
2011-08-26 12:05:47 +02:00
2011-11-23 19:17:33 +01:00
m_targets . SetUnitTarget ( unit );
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 ();
}
2012-02-19 00:40:22 +01:00
void Spell :: SelectExplicitTargets ()
{
// here go all explicit target changes made to explicit targets after spell prepare phase is finished
if ( Unit * target = m_targets . GetUnitTarget ())
{
// check for explicit target redirection, for Grounding Totem for example
if ( m_spellInfo -> GetExplicitTargetMask () & TARGET_FLAG_UNIT_ENEMY
|| ( m_spellInfo -> GetExplicitTargetMask () & TARGET_FLAG_UNIT && ! m_spellInfo -> IsPositive ()))
{
Unit * redirect ;
switch ( m_spellInfo -> DmgClass )
{
case SPELL_DAMAGE_CLASS_MAGIC :
redirect = m_caster -> GetMagicHitRedirectTarget ( target , m_spellInfo );
break ;
case SPELL_DAMAGE_CLASS_MELEE :
case SPELL_DAMAGE_CLASS_RANGED :
redirect = m_caster -> GetMeleeHitRedirectTarget ( target , m_spellInfo );
break ;
default :
redirect = NULL ;
break ;
}
if ( redirect && ( redirect != target ))
m_targets . SetUnitTarget ( redirect );
}
}
}
2010-02-20 23:59:05 +01:00
void Spell :: SelectSpellTargets ()
{
2012-02-19 00:40:22 +01:00
// select targets for cast phase
SelectExplicitTargets ();
2012-02-21 20:03:27 +01:00
uint32 processedAreaEffectsMask = 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 ;
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 );
2012-02-21 20:03:27 +01:00
SelectEffectImplicitTargets ( SpellEffIndex ( i ), m_spellInfo -> Effects [ i ]. TargetA , processedAreaEffectsMask );
SelectEffectImplicitTargets ( SpellEffIndex ( i ), m_spellInfo -> Effects [ i ]. TargetB , processedAreaEffectsMask );
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
2012-03-03 00:19:00 +01:00
if ( m_targets . HasDst ())
AddDestTarget ( * m_targets . GetDst (), i );
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
{
2012-03-03 00:19:00 +01:00
float dist = m_caster -> GetDistance ( * m_targets . GetDstPos ());
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
}
}
}
2012-02-21 20:03:27 +01:00
void Spell :: SelectEffectImplicitTargets ( SpellEffIndex effIndex , SpellImplicitTargetInfo const & targetType , uint32 & processedEffectMask )
2011-09-23 11:58:01 +02:00
{
2012-02-21 20:03:27 +01:00
if ( ! targetType . GetTarget ())
return ;
uint32 effectMask = 1 << effIndex ;
// set the same target list for all effects
// some spells appear to need this, however this requires more research
switch ( targetType . GetSelectionCategory ())
2011-09-23 11:58:01 +02:00
{
2012-02-21 20:03:27 +01:00
case TARGET_SELECT_CATEGORY_NEARBY :
case TARGET_SELECT_CATEGORY_CONE :
case TARGET_SELECT_CATEGORY_AREA :
// targets for effect already selected
if ( effectMask & processedEffectMask )
return ;
// choose which targets we can select at once
for ( uint32 j = effIndex + 1 ; j < MAX_SPELL_EFFECTS ; ++ j )
if ( GetSpellInfo () -> Effects [ effIndex ]. TargetA . GetTarget () == GetSpellInfo () -> Effects [ j ]. TargetA . GetTarget () &&
GetSpellInfo () -> Effects [ effIndex ]. TargetB . GetTarget () == GetSpellInfo () -> Effects [ j ]. TargetB . GetTarget () &&
GetSpellInfo () -> Effects [ effIndex ]. ImplicitTargetConditions == GetSpellInfo () -> Effects [ j ]. ImplicitTargetConditions &&
GetSpellInfo () -> Effects [ effIndex ]. CalcRadius ( m_caster ) == GetSpellInfo () -> Effects [ j ]. CalcRadius ( m_caster ))
effectMask |= 1 << j ;
processedEffectMask |= effectMask ;
2012-02-22 09:15:57 +01:00
break ;
default :
break ;
2012-02-21 20:03:27 +01:00
}
2012-06-30 16:07:09 +02:00
switch ( targetType . GetSelectionCategory ())
2012-02-21 20:03:27 +01:00
{
case TARGET_SELECT_CATEGORY_CHANNEL :
SelectImplicitChannelTargets ( effIndex , targetType );
break ;
case TARGET_SELECT_CATEGORY_NEARBY :
SelectImplicitNearbyTargets ( effIndex , targetType , effectMask );
break ;
case TARGET_SELECT_CATEGORY_CONE :
SelectImplicitConeTargets ( effIndex , targetType , effectMask );
break ;
case TARGET_SELECT_CATEGORY_AREA :
SelectImplicitAreaTargets ( effIndex , targetType , effectMask );
break ;
case TARGET_SELECT_CATEGORY_DEFAULT :
switch ( targetType . GetObjectType ())
2011-09-23 11:58:01 +02:00
{
2012-02-21 20:03:27 +01:00
case TARGET_OBJECT_TYPE_SRC :
2012-06-30 16:07:09 +02:00
switch ( targetType . GetReferenceType ())
2012-02-21 20:03:27 +01:00
{
case TARGET_REFERENCE_TYPE_CASTER :
m_targets . SetSrc ( * m_caster );
break ;
default :
2012-03-02 17:57:26 +01:00
ASSERT ( false && "Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_SRC" );
2012-02-21 20:03:27 +01:00
break ;
}
break ;
case TARGET_OBJECT_TYPE_DEST :
2012-06-30 16:07:09 +02:00
switch ( targetType . GetReferenceType ())
2012-02-21 20:03:27 +01:00
{
case TARGET_REFERENCE_TYPE_CASTER :
SelectImplicitCasterDestTargets ( effIndex , targetType );
break ;
case TARGET_REFERENCE_TYPE_TARGET :
2012-02-22 10:21:02 +01:00
SelectImplicitTargetDestTargets ( effIndex , targetType );
2012-02-21 20:03:27 +01:00
break ;
case TARGET_REFERENCE_TYPE_DEST :
SelectImplicitDestDestTargets ( effIndex , targetType );
break ;
default :
2012-03-02 17:57:26 +01:00
ASSERT ( false && "Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_DEST" );
2012-02-21 20:03:27 +01:00
break ;
}
break ;
default :
2012-06-30 16:07:09 +02:00
switch ( targetType . GetReferenceType ())
2012-02-21 20:03:27 +01:00
{
case TARGET_REFERENCE_TYPE_CASTER :
SelectImplicitCasterObjectTargets ( effIndex , targetType );
break ;
case TARGET_REFERENCE_TYPE_TARGET :
SelectImplicitTargetObjectTargets ( effIndex , targetType );
break ;
default :
2012-03-02 17:57:26 +01:00
ASSERT ( false && "Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT" );
2012-02-21 20:03:27 +01:00
break ;
}
break ;
2011-09-23 11:58:01 +02:00
}
2012-02-21 20:03:27 +01:00
break ;
case TARGET_SELECT_CATEGORY_NYI :
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "SPELL: target type %u, found in spellID %u, effect %u is not implemented yet!" , m_spellInfo -> Id , effIndex , targetType . GetTarget ());
break ;
2011-09-23 11:58:01 +02:00
default :
2012-02-21 20:03:27 +01:00
ASSERT ( false && "Spell::SelectEffectImplicitTargets: received not implemented select target category" );
2011-09-23 11:58:01 +02:00
break ;
}
2012-02-21 20:03:27 +01:00
}
2011-09-23 11:58:01 +02:00
2012-02-21 20:03:27 +01:00
void Spell :: SelectImplicitChannelTargets ( SpellEffIndex effIndex , SpellImplicitTargetInfo const & targetType )
{
if ( targetType . GetReferenceType () != TARGET_REFERENCE_TYPE_CASTER )
{
ASSERT ( false && "Spell::SelectImplicitChannelTargets: received not implemented target reference type" );
2011-09-23 11:58:01 +02:00
return ;
2012-02-21 20:03:27 +01:00
}
2011-09-23 11:58:01 +02:00
2012-02-21 20:03:27 +01:00
Spell * channeledSpell = m_originalCaster -> GetCurrentSpell ( CURRENT_CHANNELED_SPELL );
if ( ! channeledSpell )
{
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell::SelectImplicitChannelTargets: cannot find channel spell for spell ID %u, effect %u" , m_spellInfo -> Id , effIndex );
2011-09-23 11:58:01 +02:00
return ;
2012-02-21 20:03:27 +01:00
}
2012-02-22 10:34:08 +01:00
switch ( targetType . GetTarget ())
2011-09-23 11:58:01 +02:00
{
2012-02-21 20:03:27 +01:00
case TARGET_UNIT_CHANNEL_TARGET :
2012-07-03 12:35:06 +02:00
{
WorldObject * target = ObjectAccessor :: GetUnit ( * m_caster , channeledSpell -> m_targets . GetUnitTargetGUID ());
CallScriptObjectTargetSelectHandlers ( target , effIndex );
2012-02-21 20:03:27 +01:00
// unit target may be no longer avalible - teleported out of map for example
2012-07-03 12:35:06 +02:00
if ( target && target -> ToUnit ())
AddUnitTarget ( target -> ToUnit (), 1 << effIndex );
2012-02-21 20:03:27 +01:00
else
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "SPELL: cannot find channel spell target for spell ID %u, effect %u" , m_spellInfo -> Id , effIndex );
2011-09-23 11:58:01 +02:00
break ;
2012-07-03 12:35:06 +02:00
}
2012-02-21 20:03:27 +01:00
case TARGET_DEST_CHANNEL_TARGET :
if ( channeledSpell -> m_targets . HasDst ())
m_targets . SetDst ( channeledSpell -> m_targets );
else if ( WorldObject * target = ObjectAccessor :: GetWorldObject ( * m_caster , channeledSpell -> m_targets . GetObjectTargetGUID ()))
2012-07-03 12:35:06 +02:00
{
CallScriptObjectTargetSelectHandlers ( target , effIndex );
if ( target )
m_targets . SetDst ( * target );
}
2012-02-21 20:03:27 +01:00
else
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "SPELL: cannot find channel spell destination for spell ID %u, effect %u" , m_spellInfo -> Id , effIndex );
break ;
case TARGET_DEST_CHANNEL_CASTER :
m_targets . SetDst ( * channeledSpell -> GetCaster ());
2011-09-23 11:58:01 +02:00
break ;
2011-09-28 11:11:38 +02:00
default :
2012-02-21 20:03:27 +01:00
ASSERT ( false && "Spell::SelectImplicitChannelTargets: received not implemented target type" );
2011-09-28 11:11:38 +02:00
break ;
2011-09-23 11:58:01 +02:00
}
}
2012-02-21 20:03:27 +01:00
void Spell :: SelectImplicitNearbyTargets ( SpellEffIndex effIndex , SpellImplicitTargetInfo const & targetType , uint32 effMask )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( targetType . GetReferenceType () != TARGET_REFERENCE_TYPE_CASTER )
{
ASSERT ( false && "Spell::SelectImplicitNearbyTargets: received not implemented target reference type" );
return ;
}
2010-02-20 23:59:05 +01:00
2012-02-22 09:15:57 +01:00
float range = 0.0f ;
2012-02-21 20:03:27 +01:00
switch ( targetType . GetCheckType ())
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
case TARGET_CHECK_ENEMY :
range = m_spellInfo -> GetMaxRange ( false , m_caster , this );
2010-02-20 23:59:05 +01:00
break ;
2012-02-21 20:03:27 +01:00
case TARGET_CHECK_ALLY :
case TARGET_CHECK_PARTY :
case TARGET_CHECK_RAID :
case TARGET_CHECK_RAID_CLASS :
range = m_spellInfo -> GetMaxRange ( true , m_caster , this );
break ;
case TARGET_CHECK_ENTRY :
case TARGET_CHECK_DEFAULT :
range = m_spellInfo -> GetMaxRange ( m_spellInfo -> IsPositive (), m_caster , this );
2010-02-20 23:59:05 +01:00
break ;
default :
2012-02-21 20:03:27 +01:00
ASSERT ( false && "Spell::SelectImplicitNearbyTargets: received not implemented selection check type" );
break ;
2010-02-20 23:59:05 +01:00
}
2010-04-07 18:09:10 +02:00
2012-02-21 20:03:27 +01:00
ConditionList * condList = m_spellInfo -> Effects [ effIndex ]. ImplicitTargetConditions ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// handle emergency case - try to use other provided targets if no conditions provided
2012-02-22 09:15:57 +01:00
if ( targetType . GetCheckType () == TARGET_CHECK_ENTRY && ( ! condList || condList -> empty ()))
2012-02-21 20:03:27 +01:00
{
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell::SelectImplicitNearbyTargets: no conditions entry for target with TARGET_CHECK_ENTRY of spell ID %u, effect %u - selecting default targets" , m_spellInfo -> Id , effIndex );
switch ( targetType . GetObjectType ())
{
case TARGET_OBJECT_TYPE_GOBJ :
if ( m_spellInfo -> RequiresSpellFocus )
{
if ( focusObject )
AddGOTarget ( focusObject , effMask );
return ;
}
break ;
case TARGET_OBJECT_TYPE_DEST :
if ( m_spellInfo -> RequiresSpellFocus )
{
if ( focusObject )
m_targets . SetDst ( * focusObject );
return ;
}
break ;
default :
break ;
}
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
WorldObject * target = SearchNearbyTarget ( range , targetType . GetObjectType (), targetType . GetCheckType (), condList );
if ( ! target )
2010-07-21 01:15:27 +02:00
{
2012-02-21 20:03:27 +01:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell::SelectImplicitNearbyTargets: cannot find nearby target for spell ID %u, effect %u" , m_spellInfo -> Id , effIndex );
return ;
2010-07-21 01:15:27 +02:00
}
2012-07-03 12:35:06 +02:00
CallScriptObjectTargetSelectHandlers ( target , effIndex );
2012-02-21 20:03:27 +01:00
switch ( targetType . GetObjectType ())
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
case TARGET_OBJECT_TYPE_UNIT :
if ( Unit * unitTarget = target -> ToUnit ())
2012-04-04 17:06:50 -05:00
AddUnitTarget ( unitTarget , effMask , true , false );
2012-02-21 20:03:27 +01:00
break ;
case TARGET_OBJECT_TYPE_GOBJ :
if ( GameObject * gobjTarget = target -> ToGameObject ())
AddGOTarget ( gobjTarget , effMask );
break ;
case TARGET_OBJECT_TYPE_DEST :
m_targets . SetDst ( * target );
break ;
default :
ASSERT ( false && "Spell::SelectImplicitNearbyTargets: received not implemented target object type" );
break ;
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
SelectImplicitChainTargets ( effIndex , targetType , target , effMask );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
void Spell :: SelectImplicitConeTargets ( SpellEffIndex effIndex , SpellImplicitTargetInfo const & targetType , uint32 effMask )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( targetType . GetReferenceType () != TARGET_REFERENCE_TYPE_CASTER )
{
ASSERT ( false && "Spell::SelectImplicitConeTargets: received not implemented target reference type" );
2010-02-20 23:59:05 +01:00
return ;
2012-02-21 20:03:27 +01:00
}
std :: list < WorldObject *> targets ;
SpellTargetObjectTypes objectType = targetType . GetObjectType ();
SpellTargetCheckTypes selectionType = targetType . GetCheckType ();
ConditionList * condList = m_spellInfo -> Effects [ effIndex ]. ImplicitTargetConditions ;
float coneAngle = M_PI / 2 ;
float radius = m_spellInfo -> Effects [ effIndex ]. CalcRadius ( m_caster ) * m_spellValue -> RadiusMod ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
if ( uint32 containerTypeMask = GetSearcherTypeMask ( objectType , condList ))
{
Trinity :: WorldObjectSpellConeTargetCheck check ( coneAngle , radius , m_caster , m_spellInfo , selectionType , condList );
Trinity :: WorldObjectListSearcher < Trinity :: WorldObjectSpellConeTargetCheck > searcher ( m_caster , targets , check , containerTypeMask );
2012-06-29 21:53:35 +02:00
SearchTargets < Trinity :: WorldObjectListSearcher < Trinity :: WorldObjectSpellConeTargetCheck > > ( searcher , containerTypeMask , m_caster , m_caster , radius );
CallScriptObjectAreaTargetSelectHandlers ( targets , effIndex );
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
if ( ! targets . empty ())
{
// Other special target selection goes here
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 ();
2010-02-20 23:59:05 +01:00
2012-04-08 17:40:05 +02:00
Trinity :: Containers :: RandomResizeList ( targets , maxTargets );
2012-02-21 20:03:27 +01:00
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// for compability with older code - add only unit and go targets
// TODO: remove this
std :: list < Unit *> unitTargets ;
std :: list < GameObject *> gObjTargets ;
for ( std :: list < WorldObject *>:: iterator itr = targets . begin (); itr != targets . end (); ++ itr )
{
if ( Unit * unitTarget = ( * itr ) -> ToUnit ())
unitTargets . push_back ( unitTarget );
else if ( GameObject * gObjTarget = ( * itr ) -> ToGameObject ())
gObjTargets . push_back ( gObjTarget );
}
for ( std :: list < Unit *>:: iterator itr = unitTargets . begin (); itr != unitTargets . end (); ++ itr )
AddUnitTarget ( * itr , effMask , false );
for ( std :: list < GameObject *>:: iterator itr = gObjTargets . begin (); itr != gObjTargets . end (); ++ itr )
AddGOTarget ( * itr , effMask );
}
}
}
void Spell :: SelectImplicitAreaTargets ( SpellEffIndex effIndex , SpellImplicitTargetInfo const & targetType , uint32 effMask )
{
Unit * referer = NULL ;
switch ( targetType . GetReferenceType ())
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
case TARGET_REFERENCE_TYPE_SRC :
case TARGET_REFERENCE_TYPE_DEST :
case TARGET_REFERENCE_TYPE_CASTER :
referer = m_caster ;
break ;
case TARGET_REFERENCE_TYPE_TARGET :
referer = m_targets . GetUnitTarget ();
break ;
case TARGET_REFERENCE_TYPE_LAST :
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
// find last added target for this effect
for ( std :: list < TargetInfo >:: reverse_iterator ihit = m_UniqueTargetInfo . rbegin (); ihit != m_UniqueTargetInfo . rend (); ++ ihit )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( ihit -> effectMask & ( 1 << effIndex ))
{
referer = ObjectAccessor :: GetUnit ( * m_caster , ihit -> targetGUID );
break ;
}
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
break ;
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
default :
ASSERT ( false && "Spell::SelectImplicitAreaTargets: received not implemented target reference type" );
return ;
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
if ( ! referer )
return ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
Position const * center = NULL ;
switch ( targetType . GetReferenceType ())
{
case TARGET_REFERENCE_TYPE_SRC :
2012-03-03 00:19:00 +01:00
center = m_targets . GetSrcPos ();
2012-02-21 20:03:27 +01:00
break ;
case TARGET_REFERENCE_TYPE_DEST :
2012-03-03 00:19:00 +01:00
center = m_targets . GetDstPos ();
2012-02-21 20:03:27 +01:00
break ;
case TARGET_REFERENCE_TYPE_CASTER :
case TARGET_REFERENCE_TYPE_TARGET :
case TARGET_REFERENCE_TYPE_LAST :
center = referer ;
break ;
default :
ASSERT ( false && "Spell::SelectImplicitAreaTargets: received not implemented target reference type" );
return ;
}
std :: list < WorldObject *> targets ;
float radius = m_spellInfo -> Effects [ effIndex ]. CalcRadius ( m_caster ) * m_spellValue -> RadiusMod ;
SearchAreaTargets ( targets , radius , center , referer , targetType . GetObjectType (), targetType . GetCheckType (), m_spellInfo -> Effects [ effIndex ]. ImplicitTargetConditions );
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Custom entries
// TODO: remove those
switch ( m_spellInfo -> Id )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
case 46584 : // Raise Dead
{
if ( Player * playerCaster = m_caster -> ToPlayer ())
{
for ( std :: list < WorldObject *>:: iterator itr = targets . begin (); itr != targets . end (); ++ itr )
{
switch (( * itr ) -> GetTypeId ())
{
case TYPEID_UNIT :
case TYPEID_PLAYER :
{
Unit * unitTarget = ( * itr ) -> ToUnit ();
2012-02-23 13:01:16 +01:00
if ( unitTarget -> isAlive () || ! playerCaster -> isHonorOrXPTarget ( unitTarget )
2012-02-21 20:03:27 +01:00
|| (( unitTarget -> GetCreatureTypeMask () & ( 1 << ( CREATURE_TYPE_HUMANOID - 1 ))) == 0 )
|| ( unitTarget -> GetDisplayId () != unitTarget -> GetNativeDisplayId ()))
break ;
AddUnitTarget ( unitTarget , effMask , false );
// no break;
}
case TYPEID_CORPSE : // wont work until corpses are allowed in target lists, but at least will send dest in packet
m_targets . SetDst ( * ( * itr ));
return ; // nothing more to do here
default :
break ;
}
}
}
return ; // don't add targets to target map
}
// Corpse Explosion
case 49158 :
case 51325 :
case 51326 :
case 51327 :
case 51328 :
// check if our target is not valid (spell can target ghoul or dead unit)
if ( ! ( m_targets . GetUnitTarget () && m_targets . GetUnitTarget () -> GetDisplayId () == m_targets . GetUnitTarget () -> GetNativeDisplayId () &&
2012-02-23 13:01:16 +01:00
(( m_targets . GetUnitTarget () -> GetEntry () == 26125 && m_targets . GetUnitTarget () -> GetOwnerGUID () == m_caster -> GetGUID ())
2012-02-21 20:03:27 +01:00
|| m_targets . GetUnitTarget () -> isDead ())))
{
// remove existing targets
CleanupTargetList ();
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
for ( std :: list < WorldObject *>:: iterator itr = targets . begin (); itr != targets . end (); ++ itr )
{
switch (( * itr ) -> GetTypeId ())
{
case TYPEID_UNIT :
case TYPEID_PLAYER :
if ( ! ( * itr ) -> ToUnit () -> isDead ())
break ;
AddUnitTarget (( * itr ) -> ToUnit (), 1 << effIndex , false );
return ;
default :
break ;
}
}
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
m_caster -> ToPlayer () -> RemoveSpellCooldown ( m_spellInfo -> Id , true );
SendCastResult ( SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW );
finish ( false );
}
return ;
default :
break ;
}
2012-07-01 21:05:53 +02:00
CallScriptObjectAreaTargetSelectHandlers ( targets , effIndex );
2012-02-21 20:03:27 +01:00
std :: list < Unit *> unitTargets ;
std :: list < GameObject *> gObjTargets ;
// for compability with older code - add only unit and go targets
// TODO: remove this
for ( std :: list < WorldObject *>:: iterator itr = targets . begin (); itr != targets . end (); ++ itr )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( Unit * unitTarget = ( * itr ) -> ToUnit ())
unitTargets . push_back ( unitTarget );
else if ( GameObject * gObjTarget = ( * itr ) -> ToGameObject ())
gObjTargets . push_back ( gObjTarget );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
if ( ! unitTargets . empty ())
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01: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
// In arenas Replenishment may only affect the caster
if ( m_caster -> GetTypeId () == TYPEID_PLAYER && m_caster -> ToPlayer () -> InArena ())
{
unitTargets . clear ();
unitTargets . push_back ( m_caster );
break ;
}
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 ;
}
else
break ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Remove targets outside caster's raid
2012-03-28 19:11:50 +08:00
for ( std :: list < Unit *>:: iterator itr = unitTargets . begin (); itr != unitTargets . end ();)
2012-02-21 20:03:27 +01:00
{
if ( ! ( * itr ) -> IsInRaidWith ( m_caster ))
itr = unitTargets . 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 ;
}
else
break ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Remove targets outside caster's raid
2012-03-28 19:11:50 +08:00
for ( std :: list < Unit *>:: iterator itr = unitTargets . begin (); itr != unitTargets . end ();)
2012-02-21 20:03:27 +01:00
if ( ! ( * itr ) -> IsInRaidWith ( m_caster ))
itr = unitTargets . erase ( itr );
else
++ itr ;
break ;
default :
break ;
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
if ( maxSize && power != - 1 )
{
if ( Powers ( power ) == POWER_HEALTH )
{
if ( unitTargets . size () > maxSize )
{
unitTargets . sort ( Trinity :: HealthPctOrderPred ());
unitTargets . resize ( maxSize );
}
}
else
{
2012-03-28 19:11:50 +08:00
for ( std :: list < Unit *>:: iterator itr = unitTargets . begin (); itr != unitTargets . end ();)
2012-02-21 20:03:27 +01:00
if (( * itr ) -> getPowerType () != ( Powers ) power )
itr = unitTargets . erase ( itr );
else
++ itr ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
if ( unitTargets . size () > maxSize )
{
unitTargets . sort ( Trinity :: PowerPctOrderPred (( Powers ) power ));
unitTargets . resize ( maxSize );
}
}
}
2010-02-20 23:59:05 +01:00
2012-05-28 04:07:51 +02:00
// todo: move to scripts, but we must call it before resize list by MaxAffectedTargets
// Intimidating Shout
if ( m_spellInfo -> Id == 5246 && effIndex != EFFECT_0 )
unitTargets . remove ( m_targets . GetUnitTarget ());
2012-02-21 20:03:27 +01:00
// Other special target selection goes here
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 ();
2012-04-08 17:40:05 +02:00
Trinity :: Containers :: RandomResizeList ( unitTargets , maxTargets );
2012-02-21 20:03:27 +01:00
}
for ( std :: list < Unit *>:: iterator itr = unitTargets . begin (); itr != unitTargets . end (); ++ itr )
AddUnitTarget ( * itr , effMask , false );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
if ( ! gObjTargets . 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 ();
2012-04-08 17:40:05 +02:00
Trinity :: Containers :: RandomResizeList ( gObjTargets , maxTargets );
2012-02-21 20:03:27 +01:00
}
2012-06-29 21:53:35 +02:00
2012-02-21 20:03:27 +01:00
for ( std :: list < GameObject *>:: iterator itr = gObjTargets . begin (); itr != gObjTargets . end (); ++ itr )
AddGOTarget ( * itr , effMask );
}
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
void Spell :: SelectImplicitCasterDestTargets ( SpellEffIndex effIndex , SpellImplicitTargetInfo const & targetType )
2010-02-20 23:59:05 +01:00
{
2012-06-30 16:07:09 +02:00
switch ( targetType . GetTarget ())
2011-07-22 21:22:05 +02:00
{
2012-02-21 20:03:27 +01:00
case TARGET_DEST_CASTER :
m_targets . SetDst ( * m_caster );
return ;
case TARGET_DEST_HOME :
if ( Player * playerCaster = m_caster -> ToPlayer ())
m_targets . SetDst ( playerCaster -> m_homebindX , playerCaster -> m_homebindY , playerCaster -> m_homebindZ , playerCaster -> GetOrientation (), playerCaster -> m_homebindMapId );
return ;
case TARGET_DEST_DB :
if ( SpellTargetPosition const * st = sSpellMgr -> GetSpellTargetPosition ( m_spellInfo -> Id ))
2011-09-16 11:40:53 +02:00
{
2012-02-21 20:03:27 +01:00
// TODO: fix this check
if ( m_spellInfo -> HasEffect ( SPELL_EFFECT_TELEPORT_UNITS ))
m_targets . SetDst ( st -> target_X , st -> target_Y , st -> target_Z , st -> target_Orientation , ( int32 ) st -> target_mapId );
else if ( st -> target_mapId == m_caster -> GetMapId ())
m_targets . SetDst ( st -> target_X , st -> target_Y , st -> target_Z , st -> target_Orientation );
}
else
{
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "SPELL: unknown target coordinates for spell ID %u" , m_spellInfo -> Id );
WorldObject * target = m_targets . GetObjectTarget ();
m_targets . SetDst ( target ? * target : * m_caster );
2011-09-16 11:40:53 +02:00
}
2012-02-21 20:03:27 +01:00
return ;
case TARGET_DEST_CASTER_FISHING :
{
float min_dis = m_spellInfo -> GetMinRange ( true );
float max_dis = m_spellInfo -> GetMaxRange ( true );
float dis = ( float ) rand_norm () * ( max_dis - min_dis ) + min_dis ;
float x , y , z , angle ;
angle = ( float ) rand_norm () * static_cast < float > ( M_PI * 35.0f / 180.0f ) - static_cast < float > ( M_PI * 17.5f / 180.0f );
m_caster -> GetClosePoint ( x , y , z , DEFAULT_WORLD_OBJECT_SIZE , dis , angle );
m_targets . SetDst ( x , y , z , m_caster -> GetOrientation ());
return ;
2011-09-16 11:40:53 +02:00
}
2012-02-22 09:15:57 +01:00
default :
break ;
2011-07-22 21:22:05 +02:00
}
2012-02-21 20:03:27 +01:00
float dist ;
float angle = targetType . CalcDirectionAngle ();
float objSize = m_caster -> GetObjectSize ();
2012-02-22 10:34:08 +01:00
if ( targetType . GetTarget () == TARGET_DEST_CASTER_SUMMON )
2012-02-21 20:03:27 +01:00
dist = PET_FOLLOW_DIST ;
else
dist = m_spellInfo -> Effects [ effIndex ]. CalcRadius ( m_caster );
2011-09-16 11:40:53 +02:00
2012-02-21 20:03:27 +01:00
if ( dist < objSize )
dist = objSize ;
2012-02-22 10:34:08 +01:00
else if ( targetType . GetTarget () == TARGET_DEST_CASTER_RANDOM )
2012-02-21 20:03:27 +01:00
dist = objSize + ( dist - objSize ) * ( float ) rand_norm ();
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
Position pos ;
2012-02-22 10:34:08 +01:00
if ( targetType . GetTarget () == TARGET_DEST_CASTER_FRONT_LEAP )
2012-02-21 20:03:27 +01:00
m_caster -> GetFirstCollisionPosition ( pos , dist , angle );
else
m_caster -> GetNearPosition ( pos , dist , angle );
m_targets . SetDst ( * m_caster );
m_targets . ModDst ( pos );
}
void Spell :: SelectImplicitTargetDestTargets ( SpellEffIndex effIndex , SpellImplicitTargetInfo const & targetType )
{
WorldObject * target = m_targets . GetObjectTarget ();
2012-06-30 16:07:09 +02:00
switch ( targetType . GetTarget ())
2011-07-22 21:22:05 +02:00
{
2012-02-21 20:03:27 +01:00
case TARGET_DEST_TARGET_ENEMY :
case TARGET_DEST_TARGET_ANY :
m_targets . SetDst ( * target );
2010-02-20 23:59:05 +01:00
return ;
2012-02-22 09:15:57 +01:00
default :
break ;
2011-07-22 21:22:05 +02:00
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
float angle = targetType . CalcDirectionAngle ();
float objSize = target -> GetObjectSize ();
float dist = m_spellInfo -> Effects [ effIndex ]. CalcRadius ( m_caster );
if ( dist < objSize )
dist = objSize ;
2012-02-22 10:34:08 +01:00
else if ( targetType . GetTarget () == TARGET_DEST_TARGET_RANDOM )
2012-02-21 20:03:27 +01:00
dist = objSize + ( dist - objSize ) * ( float ) rand_norm ();
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
Position pos ;
target -> GetNearPosition ( pos , dist , angle );
m_targets . SetDst ( * target );
m_targets . ModDst ( pos );
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
void Spell :: SelectImplicitDestDestTargets ( SpellEffIndex effIndex , SpellImplicitTargetInfo const & targetType )
{
2012-02-22 21:06:29 +01:00
// set destination to caster if no dest provided
// can only happen if previous destination target could not be set for some reason
// (not found nearby target, or channel target for example
// maybe we should abort the spell in such case?
if ( ! m_targets . HasDst ())
m_targets . SetDst ( * m_caster );
2012-06-30 16:07:09 +02:00
switch ( targetType . GetTarget ())
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
case TARGET_DEST_DYNOBJ_ENEMY :
case TARGET_DEST_DYNOBJ_ALLY :
case TARGET_DEST_DYNOBJ_NONE :
case TARGET_DEST_DEST :
return ;
case TARGET_DEST_TRAJ :
SelectImplicitTrajTargets ();
return ;
2012-02-22 09:15:57 +01:00
default :
break ;
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
float angle = targetType . CalcDirectionAngle ();
float dist = m_spellInfo -> Effects [ effIndex ]. CalcRadius ( m_caster );
if ( targetType . GetTarget () == TARGET_DEST_DEST_RANDOM )
dist *= ( float ) rand_norm ();
2012-03-03 00:19:00 +01:00
Position pos = * m_targets . GetDstPos ();
2012-02-21 20:03:27 +01:00
m_caster -> MovePosition ( pos , dist , angle );
m_targets . ModDst ( pos );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
void Spell :: SelectImplicitCasterObjectTargets ( SpellEffIndex effIndex , SpellImplicitTargetInfo const & targetType )
2010-02-20 23:59:05 +01:00
{
2012-07-03 12:35:06 +02:00
WorldObject * target = NULL ;
bool checkIfValid = true ;
2012-06-30 16:07:09 +02:00
switch ( targetType . GetTarget ())
2012-02-21 20:03:27 +01:00
{
case TARGET_UNIT_CASTER :
2012-07-03 12:35:06 +02:00
target = m_caster ;
checkIfValid = false ;
2012-02-21 20:03:27 +01:00
break ;
case TARGET_UNIT_MASTER :
2012-07-03 12:35:06 +02:00
target = m_caster -> GetCharmerOrOwner ();
2012-02-21 20:03:27 +01:00
break ;
case TARGET_UNIT_PET :
2012-07-03 12:35:06 +02:00
target = m_caster -> GetGuardianPet ();
2012-02-21 20:03:27 +01:00
break ;
case TARGET_UNIT_SUMMONER :
if ( m_caster -> isSummon ())
2012-07-03 12:35:06 +02:00
target = m_caster -> ToTempSummon () -> GetSummoner ();
2012-02-21 20:03:27 +01:00
break ;
case TARGET_UNIT_VEHICLE :
2012-07-03 12:35:06 +02:00
target = m_caster -> GetVehicleBase ();
2012-02-21 20:03:27 +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 :
if ( m_caster -> GetTypeId () == TYPEID_UNIT && m_caster -> ToCreature () -> IsVehicle ())
2012-07-03 12:35:06 +02:00
target = m_caster -> GetVehicleKit () -> GetPassenger ( targetType . GetTarget () - TARGET_UNIT_PASSENGER_0 );
2012-02-21 20:03:27 +01:00
break ;
2012-02-22 09:15:57 +01:00
default :
break ;
2012-02-21 20:03:27 +01:00
}
2012-07-03 12:35:06 +02:00
CallScriptObjectTargetSelectHandlers ( target , effIndex );
if ( target && target -> ToUnit ())
AddUnitTarget ( target -> ToUnit (), 1 << effIndex , checkIfValid );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
void Spell :: SelectImplicitTargetObjectTargets ( SpellEffIndex effIndex , SpellImplicitTargetInfo const & targetType )
2010-02-20 23:59:05 +01:00
{
2012-02-22 19:15:52 +01:00
ASSERT (( m_targets . GetObjectTarget () || m_targets . GetItemTarget ()) && "Spell::SelectImplicitTargetObjectTargets - no explicit object or item target available!" );
2011-09-16 11:40:53 +02:00
2012-07-03 12:35:06 +02:00
WorldObject * target = m_targets . GetObjectTarget ();
CallScriptObjectTargetSelectHandlers ( target , effIndex );
if ( target )
{
if ( Unit * unit = target -> ToUnit ())
AddUnitTarget ( unit , 1 << effIndex , true , false );
else if ( GameObject * gobj = target -> ToGameObject ())
AddGOTarget ( gobj , 1 << effIndex );
2012-02-21 20:03:27 +01:00
SelectImplicitChainTargets ( effIndex , targetType , target , 1 << effIndex );
2012-07-03 12:35:06 +02:00
}
// Script hook can remove object target and we would wrongly land here
else if ( Item * item = m_targets . GetItemTarget ())
AddItemTarget ( item , 1 << effIndex );
2012-02-21 20:03:27 +01:00
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
void Spell :: SelectImplicitChainTargets ( SpellEffIndex effIndex , SpellImplicitTargetInfo const & targetType , WorldObject * target , uint32 effMask )
{
uint32 maxTargets = m_spellInfo -> Effects [ effIndex ]. ChainTarget ;
if ( Player * modOwner = m_caster -> GetSpellModOwner ())
modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_JUMP_TARGETS , maxTargets , this );
if ( maxTargets > 1 )
2011-09-16 11:40:53 +02:00
{
2012-02-21 20:03:27 +01:00
// mark damage multipliers as used
for ( uint32 k = effIndex ; k < MAX_SPELL_EFFECTS ; ++ k )
if ( effMask & ( 1 << k ))
m_damageMultipliers [ k ] = 1.0f ;
m_applyMultiplierMask |= effMask ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
std :: list < WorldObject *> targets ;
SearchChainTargets ( targets , maxTargets - 1 , target , targetType . GetObjectType (), targetType . GetCheckType ()
2012-02-22 10:34:08 +01:00
, m_spellInfo -> Effects [ effIndex ]. ImplicitTargetConditions , targetType . GetTarget () == TARGET_UNIT_TARGET_CHAINHEAL_ALLY );
2010-02-20 23:59:05 +01:00
2012-07-01 21:05:53 +02:00
// Chain primary target is added earlier
CallScriptObjectAreaTargetSelectHandlers ( targets , effIndex );
2012-02-21 20:03:27 +01:00
// for backward compability
std :: list < Unit *> unitTargets ;
for ( std :: list < WorldObject *>:: iterator itr = targets . begin (); itr != targets . end (); ++ itr )
if ( Unit * unitTarget = ( * itr ) -> ToUnit ())
unitTargets . push_back ( unitTarget );
2011-09-16 11:40:53 +02:00
2012-02-21 20:03:27 +01:00
for ( std :: list < Unit *>:: iterator itr = unitTargets . begin (); itr != unitTargets . end (); ++ itr )
AddUnitTarget ( * itr , effMask , false );
}
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
float tangent ( float x )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
x = tan ( x );
//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 ;
return 0.0f ;
}
2011-05-22 16:01:53 -07:00
2012-02-21 20:03:27 +01:00
#define DEBUG_TRAJ(a) //a
2011-05-22 16:01:53 -07:00
2012-02-21 20:03:27 +01:00
void Spell :: SelectImplicitTrajTargets ()
{
if ( ! m_targets . HasTraj ())
2010-02-20 23:59:05 +01:00
return ;
2012-02-21 20:03:27 +01:00
float dist2d = m_targets . GetDist2d ();
if ( ! dist2d )
2010-02-20 23:59:05 +01:00
return ;
2012-03-03 00:19:00 +01:00
float srcToDestDelta = m_targets . GetDstPos () -> m_positionZ - m_targets . GetSrcPos () -> m_positionZ ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
std :: list < WorldObject *> targets ;
2012-03-03 00:19:00 +01:00
Trinity :: WorldObjectSpellTrajTargetCheck check ( dist2d , m_targets . GetSrcPos (), m_caster , m_spellInfo );
2012-02-21 20:03:27 +01:00
Trinity :: WorldObjectListSearcher < Trinity :: WorldObjectSpellTrajTargetCheck > searcher ( m_caster , targets , check , GRID_MAP_TYPE_MASK_ALL );
2012-03-03 00:19:00 +01:00
SearchTargets < Trinity :: WorldObjectListSearcher < Trinity :: WorldObjectSpellTrajTargetCheck > > ( searcher , GRID_MAP_TYPE_MASK_ALL , m_caster , m_targets . GetSrcPos (), dist2d );
2012-02-21 20:03:27 +01:00
if ( targets . empty ())
2010-02-20 23:59:05 +01:00
return ;
2012-02-21 20:03:27 +01:00
targets . sort ( Trinity :: ObjectDistanceOrderPred ( m_caster ));
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
float b = tangent ( m_targets . GetElevation ());
float a = ( srcToDestDelta - dist2d * b ) / ( dist2d * dist2d );
if ( a > - 0.0001f )
a = 0 ;
2012-08-03 14:20:18 +02:00
DEBUG_TRAJ ( sLog -> outError ( LOG_FILTER_SPELLS_AURAS , "Spell::SelectTrajTargets: a %f b %f" , a , b );)
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
float bestDist = m_spellInfo -> GetMaxRange ( false );
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
std :: list < WorldObject *>:: const_iterator itr = targets . begin ();
for (; itr != targets . end (); ++ itr )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( Unit * unitTarget = ( * itr ) -> ToUnit ())
if ( m_caster == * itr || m_caster -> IsOnVehicle ( unitTarget ) || ( unitTarget ) -> GetVehicle ()) //(*itr)->IsOnVehicle(m_caster))
continue ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
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
2012-03-03 00:19:00 +01:00
const float objDist2d = m_targets . GetSrcPos () -> GetExactDist2d ( * itr ) * cos ( m_targets . GetSrcPos () -> GetRelativeAngle ( * itr ));
const float dz = ( * itr ) -> GetPositionZ () - m_targets . GetSrcPos () -> m_positionZ ;
2010-02-20 23:59:05 +01:00
2012-08-03 14:20:18 +02:00
DEBUG_TRAJ ( sLog -> outError ( LOG_FILTER_SPELLS_AURAS , "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
2012-02-21 20:03:27 +01:00
float dist = objDist2d - size ;
float height = dist * ( a * dist + b );
2012-08-03 14:20:18 +02:00
DEBUG_TRAJ ( sLog -> outError ( LOG_FILTER_SPELLS_AURAS , "Spell::SelectTrajTargets: dist %f, height %f." , dist , height );)
2012-02-21 20:03:27 +01:00
if ( dist < bestDist && height < dz + size && height > dz - size )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
bestDist = dist > 0 ? dist : 0 ;
2010-02-20 23:59:05 +01:00
break ;
}
2010-08-21 20:18:54 +02:00
2012-02-21 20:03:27 +01:00
#define CHECK_DIST {\
2012-08-03 14:20:18 +02:00
DEBUG_TRAJ(sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::SelectTrajTargets: dist %f, height %f.", dist, height);)\
2012-02-21 20:03:27 +01:00
if (dist > bestDist)\
continue;\
if (dist < objDist2d + size && dist > objDist2d - size)\
{\
bestDist = dist;\
break;\
}\
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
if ( ! a )
{
height = dz - size ;
dist = height / b ;
CHECK_DIST ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
height = dz + size ;
dist = height / b ;
CHECK_DIST ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
continue ;
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
height = dz - size ;
float sqrt1 = b * b + 4 * a * height ;
if ( sqrt1 > 0 )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
sqrt1 = sqrt ( sqrt1 );
dist = ( sqrt1 - b ) / ( 2 * a );
CHECK_DIST ;
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
height = dz + size ;
float sqrt2 = b * b + 4 * a * height ;
if ( sqrt2 > 0 )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
sqrt2 = sqrt ( sqrt2 );
dist = ( sqrt2 - b ) / ( 2 * a );
CHECK_DIST ;
dist = ( - sqrt2 - b ) / ( 2 * a );
CHECK_DIST ;
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
if ( sqrt1 > 0 )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
dist = ( - sqrt1 - b ) / ( 2 * a );
CHECK_DIST ;
2010-02-20 23:59:05 +01:00
}
}
2012-03-03 00:19:00 +01:00
if ( m_targets . GetSrcPos () -> GetExactDist2d ( m_targets . GetDstPos ()) > bestDist )
2010-02-20 23:59:05 +01:00
{
2012-03-03 00:19:00 +01:00
float x = m_targets . GetSrcPos () -> m_positionX + cos ( m_caster -> GetOrientation ()) * bestDist ;
float y = m_targets . GetSrcPos () -> m_positionY + sin ( m_caster -> GetOrientation ()) * bestDist ;
float z = m_targets . GetSrcPos () -> m_positionZ + bestDist * ( a * bestDist + b );
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
if ( itr != targets . end ())
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
float distSq = ( * itr ) -> GetExactDistSq ( x , y , z );
float sizeSq = ( * itr ) -> GetObjectSize ();
sizeSq *= sizeSq ;
2012-08-03 14:20:18 +02:00
DEBUG_TRAJ ( sLog -> outError ( LOG_FILTER_SPELLS_AURAS , "Initial %f %f %f %f %f" , x , y , z , distSq , sizeSq );)
2012-02-21 20:03:27 +01:00
if ( distSq > sizeSq )
{
float factor = 1 - sqrt ( sizeSq / distSq );
x += factor * (( * itr ) -> GetPositionX () - x );
y += factor * (( * itr ) -> GetPositionY () - y );
z += factor * (( * itr ) -> GetPositionZ () - z );
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
distSq = ( * itr ) -> GetExactDistSq ( x , y , z );
2012-08-03 14:20:18 +02:00
DEBUG_TRAJ ( sLog -> outError ( LOG_FILTER_SPELLS_AURAS , "Initial %f %f %f %f %f" , x , y , z , distSq , sizeSq );)
2012-02-21 20:03:27 +01:00
}
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
Position trajDst ;
trajDst . Relocate ( x , y , z , m_caster -> GetOrientation ());
m_targets . ModDst ( trajDst );
2010-02-20 23:59:05 +01:00
}
}
2012-02-21 20:03:27 +01:00
void Spell :: SelectEffectTypeImplicitTargets ( uint8 effIndex )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
// 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 ())
{
2012-07-03 12:35:06 +02:00
WorldObject * target = ObjectAccessor :: FindPlayer ( m_caster -> ToPlayer () -> GetSelection ());
CallScriptObjectTargetSelectHandlers ( target , SpellEffIndex ( effIndex ));
if ( target && target -> ToPlayer ())
AddUnitTarget ( target -> ToUnit (), 1 << effIndex , false );
2012-02-21 20:03:27 +01:00
}
return ;
default :
break ;
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// select spell implicit targets based on effect type
if ( ! m_spellInfo -> Effects [ effIndex ]. GetImplicitTargetType ())
return ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
uint32 targetMask = m_spellInfo -> Effects [ effIndex ]. GetMissingTargetMask ();
2010-08-19 14:31:31 +02:00
2012-02-21 20:03:27 +01:00
if ( ! targetMask )
return ;
2012-07-03 12:35:06 +02:00
WorldObject * target = NULL ;
2012-02-21 20:03:27 +01:00
switch ( m_spellInfo -> Effects [ effIndex ]. GetImplicitTargetType ())
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
// add explicit object target or self to the target map
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 ())
2012-07-03 12:35:06 +02:00
target = unitTarget ;
2012-02-21 20:03:27 +01:00
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 ()))
2012-07-03 12:35:06 +02:00
target = owner ;
2012-02-21 20:03:27 +01:00
}
}
else //if (targetMask & TARGET_FLAG_UNIT_MASK)
2012-07-03 12:35:06 +02:00
target = m_caster ;
2012-02-21 20:03:27 +01:00
}
if ( targetMask & TARGET_FLAG_ITEM_MASK )
{
if ( Item * itemTarget = m_targets . GetItemTarget ())
AddItemTarget ( itemTarget , 1 << effIndex );
2012-07-03 12:35:06 +02:00
return ;
2012-02-21 20:03:27 +01:00
}
if ( targetMask & TARGET_FLAG_GAMEOBJECT_MASK )
2012-07-03 12:35:06 +02:00
target = m_targets . GetGOTarget ();
2012-02-21 20:03:27 +01:00
break ;
// add self to the target map
case EFFECT_IMPLICIT_TARGET_CASTER :
if ( targetMask & TARGET_FLAG_UNIT_MASK )
2012-07-03 12:35:06 +02:00
target = m_caster ;
2012-02-21 20:03:27 +01:00
break ;
default :
break ;
2010-02-20 23:59:05 +01:00
}
2012-07-03 12:35:06 +02:00
CallScriptObjectTargetSelectHandlers ( target , SpellEffIndex ( effIndex ));
if ( target )
{
if ( target -> ToUnit ())
AddUnitTarget ( target -> ToUnit (), 1 << effIndex , false );
else if ( target -> ToGameObject ())
AddGOTarget ( target -> ToGameObject (), 1 << effIndex );
}
2012-02-21 20:03:27 +01:00
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
uint32 Spell :: GetSearcherTypeMask ( SpellTargetObjectTypes objType , ConditionList * condList )
{
// this function selects which containers need to be searched for spell target
uint32 retMask = GRID_MAP_TYPE_MASK_ALL ;
// filter searchers based on searched object type
switch ( objType )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
case TARGET_OBJECT_TYPE_UNIT :
case TARGET_OBJECT_TYPE_UNIT_AND_DEST :
case TARGET_OBJECT_TYPE_CORPSE :
case TARGET_OBJECT_TYPE_CORPSE_ENEMY :
case TARGET_OBJECT_TYPE_CORPSE_ALLY :
retMask &= GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_CREATURE ;
break ;
case TARGET_OBJECT_TYPE_GOBJ :
case TARGET_OBJECT_TYPE_GOBJ_ITEM :
retMask &= GRID_MAP_TYPE_MASK_GAMEOBJECT ;
break ;
2012-02-22 09:15:57 +01:00
default :
break ;
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
if ( ! ( m_spellInfo -> AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD ))
retMask &= ~ GRID_MAP_TYPE_MASK_CORPSE ;
if ( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS )
retMask &= GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_PLAYER ;
if ( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS )
retMask &= GRID_MAP_TYPE_MASK_PLAYER ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
if ( condList )
retMask &= sConditionMgr -> GetSearcherTypeMaskForConditionList ( * condList );
return retMask ;
}
template < class SEARCHER >
void Spell :: SearchTargets ( SEARCHER & searcher , uint32 containerMask , Unit * referer , Position const * pos , float radius )
{
if ( ! containerMask )
return ;
// search world and grid for possible targets
bool searchInGrid = containerMask & ( GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_GAMEOBJECT );
bool searchInWorld = containerMask & ( GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CORPSE );
if ( searchInGrid || searchInWorld )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
float x , y ;
x = pos -> GetPositionX ();
y = pos -> GetPositionY ();
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
CellCoord p ( Trinity :: ComputeCellCoord ( x , y ));
Cell cell ( p );
cell . SetNoCreate ();
Map & map = * ( referer -> GetMap ());
if ( searchInWorld )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
TypeContainerVisitor < SEARCHER , WorldTypeMapContainer > world_object_notifier ( searcher );
cell . Visit ( p , world_object_notifier , map , radius , x , y );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
if ( searchInGrid )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
TypeContainerVisitor < SEARCHER , GridTypeMapContainer > grid_object_notifier ( searcher );
cell . Visit ( p , grid_object_notifier , map , radius , x , y );
2010-02-20 23:59:05 +01:00
}
}
2012-02-21 20:03:27 +01:00
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
WorldObject * Spell :: SearchNearbyTarget ( float range , SpellTargetObjectTypes objectType , SpellTargetCheckTypes selectionType , ConditionList * condList )
{
WorldObject * target = NULL ;
uint32 containerTypeMask = GetSearcherTypeMask ( objectType , condList );
if ( ! containerTypeMask )
return NULL ;
Trinity :: WorldObjectSpellNearbyTargetCheck check ( range , m_caster , m_spellInfo , selectionType , condList );
Trinity :: WorldObjectLastSearcher < Trinity :: WorldObjectSpellNearbyTargetCheck > searcher ( m_caster , target , check , containerTypeMask );
SearchTargets < Trinity :: WorldObjectLastSearcher < Trinity :: WorldObjectSpellNearbyTargetCheck > > ( searcher , containerTypeMask , m_caster , m_caster , range );
return target ;
}
void Spell :: SearchAreaTargets ( std :: list < WorldObject *>& targets , float range , Position const * position , Unit * referer , SpellTargetObjectTypes objectType , SpellTargetCheckTypes selectionType , ConditionList * condList )
{
uint32 containerTypeMask = GetSearcherTypeMask ( objectType , condList );
if ( ! containerTypeMask )
return ;
Trinity :: WorldObjectSpellAreaTargetCheck check ( range , position , m_caster , referer , m_spellInfo , selectionType , condList );
Trinity :: WorldObjectListSearcher < Trinity :: WorldObjectSpellAreaTargetCheck > searcher ( m_caster , targets , check , containerTypeMask );
2012-03-15 13:15:25 +01:00
SearchTargets < Trinity :: WorldObjectListSearcher < Trinity :: WorldObjectSpellAreaTargetCheck > > ( searcher , containerTypeMask , m_caster , position , range );
2012-02-21 20:03:27 +01:00
}
void Spell :: SearchChainTargets ( std :: list < WorldObject *>& targets , uint32 chainTargets , WorldObject * target , SpellTargetObjectTypes objectType , SpellTargetCheckTypes selectType , ConditionList * condList , bool isChainHeal )
{
// max dist for jump target selection
float jumpRadius = 0.0f ;
switch ( m_spellInfo -> DmgClass )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
case SPELL_DAMAGE_CLASS_RANGED :
// 7.5y for multi shot
jumpRadius = 7.5f ;
break ;
case SPELL_DAMAGE_CLASS_MELEE :
// 5y for swipe, cleave and similar
jumpRadius = 5.0f ;
break ;
case SPELL_DAMAGE_CLASS_NONE :
case SPELL_DAMAGE_CLASS_MAGIC :
// 12.5y for chain heal spell since 3.2 patch
if ( isChainHeal )
jumpRadius = 12.5f ;
// 10y as default for magic chain spells
else
jumpRadius = 10.0f ;
break ;
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
// chain lightning/heal spells and similar - allow to jump at larger distance and go out of los
2012-02-23 13:01:16 +01:00
bool isBouncingFar = ( m_spellInfo -> AttributesEx4 & SPELL_ATTR4_AREA_TARGET_CHAIN
2012-02-21 20:03:27 +01:00
|| m_spellInfo -> DmgClass == SPELL_DAMAGE_CLASS_NONE
|| m_spellInfo -> DmgClass == SPELL_DAMAGE_CLASS_MAGIC );
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// max dist which spell can reach
float searchRadius = jumpRadius ;
if ( isBouncingFar )
searchRadius *= chainTargets ;
std :: list < WorldObject *> tempTargets ;
SearchAreaTargets ( tempTargets , searchRadius , target , m_caster , objectType , selectType , condList );
tempTargets . remove ( target );
// remove targets which are always invalid for chain spells
// for some spells allow only chain targets in front of caster (swipe for example)
if ( ! isBouncingFar )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
for ( std :: list < WorldObject *>:: iterator itr = tempTargets . begin (); itr != tempTargets . end ();)
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
std :: list < WorldObject *>:: iterator checkItr = itr ++ ;
if ( ! m_caster -> HasInArc ( static_cast < float > ( M_PI ), * checkItr ))
tempTargets . erase ( checkItr );
}
}
while ( chainTargets )
{
// try to get unit for next chain jump
std :: list < WorldObject *>:: iterator foundItr = tempTargets . end ();
// get unit with highest hp deficit in dist
if ( isChainHeal )
{
uint32 maxHPDeficit = 0 ;
for ( std :: list < WorldObject *>:: iterator itr = tempTargets . begin (); itr != tempTargets . end (); ++ itr )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( Unit * unitTarget = ( * itr ) -> ToUnit ())
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
uint32 deficit = unitTarget -> GetMaxHealth () - unitTarget -> GetHealth ();
if (( deficit > maxHPDeficit || foundItr == tempTargets . end ()) && target -> IsWithinDist ( unitTarget , jumpRadius ) && target -> IsWithinLOSInMap ( unitTarget ))
{
foundItr = itr ;
maxHPDeficit = deficit ;
}
2010-02-20 23:59:05 +01:00
}
}
}
2012-02-21 20:03:27 +01:00
// get closest object
else
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
for ( std :: list < WorldObject *>:: iterator itr = tempTargets . begin (); itr != tempTargets . end (); ++ itr )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( foundItr == tempTargets . end ())
2011-08-01 12:05:30 +02:00
{
2012-02-21 20:03:27 +01:00
if (( ! isBouncingFar || target -> IsWithinDist ( * itr , jumpRadius )) && target -> IsWithinLOSInMap ( * itr ))
foundItr = itr ;
2011-08-01 12:05:30 +02:00
}
2012-02-21 20:03:27 +01:00
else if ( target -> GetDistanceOrder ( * itr , * foundItr ) && target -> IsWithinLOSInMap ( * itr ))
foundItr = itr ;
}
}
// not found any valid target - chain ends
if ( foundItr == tempTargets . end ())
break ;
target = * foundItr ;
tempTargets . erase ( foundItr );
targets . push_back ( target );
-- chainTargets ;
}
}
2011-05-21 21:36:37 +02:00
2012-02-21 20:03:27 +01:00
void Spell :: prepareDataForTriggerSystem ( AuraEffect const * /*triggeredByAura*/ )
{
//==========================================================================================
// Now fill data for trigger system, need know:
// can spell trigger another or not (m_canTrigger)
// Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_procEx)
//==========================================================================================
2010-07-16 14:23:03 +02:00
2012-02-21 20:03:27 +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 :
m_procAttacker = PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS ;
if ( m_attackType == OFF_ATTACK )
m_procAttacker |= PROC_FLAG_DONE_OFFHAND_ATTACK ;
else
m_procAttacker |= PROC_FLAG_DONE_MAINHAND_ATTACK ;
m_procVictim = PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS ;
break ;
case SPELL_DAMAGE_CLASS_RANGED :
// Auto attack
if ( m_spellInfo -> AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG )
{
m_procAttacker = PROC_FLAG_DONE_RANGED_AUTO_ATTACK ;
m_procVictim = PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK ;
}
else // Ranged spell attack
{
m_procAttacker = PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS ;
m_procVictim = PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS ;
}
break ;
default :
if ( m_spellInfo -> EquippedItemClass == ITEM_CLASS_WEAPON &&
m_spellInfo -> EquippedItemSubClassMask & ( 1 << ITEM_SUBCLASS_WEAPON_WAND )
&& m_spellInfo -> AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG ) // Wands auto attack
{
m_procAttacker = PROC_FLAG_DONE_RANGED_AUTO_ATTACK ;
m_procVictim = PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK ;
}
// For other spells trigger procflags are set in Spell::DoAllEffectOnTarget
// Because spell positivity is dependant on target
}
m_procEx = PROC_EX_NONE ;
2010-07-16 14:23:03 +02:00
2012-02-21 20:03:27 +01:00
// Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection
if ( m_spellInfo -> SpellFamilyName == SPELLFAMILY_HUNTER &&
( 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-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
m_procAttacker |= PROC_FLAG_DONE_TRAP_ACTIVATION ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
/* Effects which are result of aura proc from triggered spell cannot proc
to prevent chain proc of these spells */
2010-08-01 01:22:13 +02:00
2012-02-21 20:03:27 +01:00
// Hellfire Effect - trigger as DOT
if ( m_spellInfo -> SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo -> SpellFamilyFlags [ 0 ] & 0x00000040 )
{
m_procAttacker = PROC_FLAG_DONE_PERIODIC ;
m_procVictim = PROC_FLAG_TAKEN_PERIODIC ;
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
// Ranged autorepeat attack is set as triggered spell - ignore it
if ( ! ( m_procAttacker & PROC_FLAG_DONE_RANGED_AUTO_ATTACK ))
{
if ( _triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS &&
( m_spellInfo -> AttributesEx2 & SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC ||
m_spellInfo -> AttributesEx3 & SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2 ))
m_procEx |= PROC_EX_INTERNAL_CANT_PROC ;
else if ( _triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS )
m_procEx |= PROC_EX_INTERNAL_TRIGGERED ;
}
// Totem casts require spellfamilymask defined in spell_proc_event to proc
if ( m_originalCaster && m_caster != m_originalCaster && m_caster -> GetTypeId () == TYPEID_UNIT && m_caster -> ToCreature () -> isTotem () && m_caster -> IsControlledByPlayer ())
m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY ;
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
void Spell :: CleanupTargetList ()
{
m_UniqueTargetInfo . clear ();
m_UniqueGOTargetInfo . clear ();
m_UniqueItemInfo . clear ();
m_delayMoment = 0 ;
2010-02-20 23:59:05 +01:00
}
2012-04-04 17:06:50 -05:00
void Spell :: AddUnitTarget ( Unit * target , uint32 effectMask , bool checkIfValid /*= true*/ , bool implicit /*= true*/ )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
for ( uint32 effIndex = 0 ; effIndex < MAX_SPELL_EFFECTS ; ++ effIndex )
if ( ! m_spellInfo -> Effects [ effIndex ]. IsEffect () || ! CheckEffectTarget ( target , effIndex ))
effectMask &= ~ ( 1 << effIndex );
2010-03-26 22:21:33 +01:00
2012-02-21 20:03:27 +01:00
// no effects left
if ( ! effectMask )
return ;
2010-03-26 22:21:33 +01:00
2012-02-21 20:03:27 +01:00
if ( checkIfValid )
2012-04-04 17:06:50 -05:00
if ( m_spellInfo -> CheckTarget ( m_caster , target , implicit ) != SPELL_CAST_OK )
2012-02-21 20:03:27 +01:00
return ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Check for effect immune skip if immuned
for ( uint32 effIndex = 0 ; effIndex < MAX_SPELL_EFFECTS ; ++ effIndex )
if ( target -> IsImmunedToSpellEffect ( m_spellInfo , effIndex ))
effectMask &= ~ ( 1 << effIndex );
uint64 targetGUID = target -> GetGUID ();
// Lookup target in already in list
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( targetGUID == ihit -> targetGUID ) // Found in list
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
ihit -> effectMask |= effectMask ; // Immune effects removed from mask
ihit -> scaleAura = false ;
if ( m_auraScaleMask && ihit -> effectMask == m_auraScaleMask && m_caster != target )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
SpellInfo const * auraSpell = sSpellMgr -> GetSpellInfo ( sSpellMgr -> GetFirstSpellInChain ( m_spellInfo -> Id ));
if ( uint32 ( target -> getLevel () + 10 ) >= auraSpell -> SpellLevel )
ihit -> scaleAura = true ;
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
return ;
2010-02-20 23:59:05 +01:00
}
}
2012-02-21 20:03:27 +01:00
// This is new target calculate data for him
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Get spell hit result on target
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 )
{
SpellInfo const * auraSpell = sSpellMgr -> GetSpellInfo ( sSpellMgr -> GetFirstSpellInChain ( m_spellInfo -> Id ));
if ( uint32 ( target -> getLevel () + 10 ) >= auraSpell -> SpellLevel )
targetInfo . scaleAura = true ;
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Calculate hit result
if ( m_originalCaster )
{
targetInfo . missCondition = m_originalCaster -> SpellHitResult ( target , m_spellInfo , m_canReflect );
if ( m_skipCheck && targetInfo . missCondition != SPELL_MISS_IMMUNE )
targetInfo . missCondition = SPELL_MISS_NONE ;
}
else
targetInfo . missCondition = SPELL_MISS_EVADE ; //SPELL_MISS_NONE;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Spell have speed - need calculate incoming time
// Incoming time is zero for self casts. At least I think so.
if ( m_spellInfo -> Speed > 0.0f && m_caster != target )
{
// calculate spell incoming interval
// TODO: this is a hack
float dist = m_caster -> GetDistance ( target -> GetPositionX (), target -> GetPositionY (), target -> GetPositionZ ());
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
if ( dist < 5.0f )
dist = 5.0f ;
targetInfo . timeDelay = ( uint64 ) floor ( dist / m_spellInfo -> Speed * 1000.0f );
2010-08-19 14:31:31 +02:00
2012-02-21 20:03:27 +01:00
// Calculate minimum incoming time
if ( m_delayMoment == 0 || m_delayMoment > targetInfo . timeDelay )
m_delayMoment = targetInfo . timeDelay ;
}
else
targetInfo . timeDelay = 0LL ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// If target reflect spell back to caster
if ( targetInfo . missCondition == SPELL_MISS_REFLECT )
{
// Calculate reflected spell result on caster
2012-03-29 13:42:04 +08:00
targetInfo . reflectResult = m_caster -> SpellHitResult ( m_caster , m_spellInfo , m_canReflect );
2010-08-21 20:18:54 +02:00
2012-02-21 20:03:27 +01: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
2012-02-21 20:03:27 +01:00
// Increase time interval for reflected spells by 1.5
targetInfo . timeDelay += targetInfo . timeDelay >> 1 ;
}
else
targetInfo . reflectResult = SPELL_MISS_NONE ;
2010-08-21 20:18:54 +02:00
2012-02-21 20:03:27 +01:00
// Add target to list
m_UniqueTargetInfo . push_back ( targetInfo );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
void Spell :: AddGOTarget ( GameObject * go , uint32 effectMask )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
for ( uint32 effIndex = 0 ; effIndex < MAX_SPELL_EFFECTS ; ++ effIndex )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( ! m_spellInfo -> Effects [ effIndex ]. IsEffect ())
effectMask &= ~ ( 1 << effIndex );
else
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
switch ( m_spellInfo -> Effects [ effIndex ]. Effect )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
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 ;
2010-02-20 23:59:05 +01:00
}
}
}
2012-02-21 20:03:27 +01:00
if ( ! effectMask )
return ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
uint64 targetGUID = go -> GetGUID ();
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Lookup target in already in list
for ( std :: list < GOTargetInfo >:: iterator ihit = m_UniqueGOTargetInfo . begin (); ihit != m_UniqueGOTargetInfo . end (); ++ ihit )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( targetGUID == ihit -> targetGUID ) // Found in list
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
ihit -> effectMask |= effectMask ; // Add only effect mask
return ;
2010-02-20 23:59:05 +01:00
}
}
2012-02-21 20:03:27 +01:00
// This is new target calculate data for him
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
GOTargetInfo target ;
target . targetGUID = targetGUID ;
target . effectMask = effectMask ;
target . processed = false ; // Effects not apply on target
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Spell have speed - need calculate incoming time
if ( m_spellInfo -> Speed > 0.0f )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
// calculate spell incoming interval
float dist = m_caster -> GetDistance ( go -> GetPositionX (), go -> GetPositionY (), go -> GetPositionZ ());
if ( dist < 5.0f )
dist = 5.0f ;
target . timeDelay = uint64 ( floor ( dist / m_spellInfo -> Speed * 1000.0f ));
if ( m_delayMoment == 0 || m_delayMoment > target . timeDelay )
m_delayMoment = target . timeDelay ;
2010-02-20 23:59:05 +01:00
}
else
2012-02-21 20:03:27 +01:00
target . timeDelay = 0LL ;
2011-01-15 19:40:06 +01:00
2012-02-21 20:03:27 +01:00
// Add target to list
m_UniqueGOTargetInfo . push_back ( target );
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
void Spell :: AddItemTarget ( Item * item , uint32 effectMask )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01: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-07-30 01:51:33 +02:00
return ;
2010-08-08 19:45:53 +02:00
2012-02-21 20:03:27 +01:00
// Lookup target in already in list
for ( std :: list < ItemTargetInfo >:: iterator ihit = m_UniqueItemInfo . begin (); ihit != m_UniqueItemInfo . end (); ++ ihit )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( item == ihit -> item ) // Found in list
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
ihit -> effectMask |= effectMask ; // Add only effect mask
return ;
2010-02-20 23:59:05 +01:00
}
}
2012-02-21 20:03:27 +01:00
// This is new target add data
ItemTargetInfo target ;
target . item = item ;
target . effectMask = effectMask ;
m_UniqueItemInfo . push_back ( target );
2010-02-20 23:59:05 +01:00
}
2012-03-03 00:19:00 +01:00
void Spell :: AddDestTarget ( SpellDestination const & dest , uint32 effIndex )
{
m_destTargets [ effIndex ] = dest ;
}
2012-02-21 20:03:27 +01:00
void Spell :: DoAllEffectOnTarget ( TargetInfo * target )
2010-07-30 01:51:33 +02:00
{
2012-02-21 20:03:27 +01:00
if ( ! target || target -> processed )
2010-07-30 01:51:33 +02:00
return ;
2012-02-21 20:03:27 +01:00
target -> processed = true ; // Target checked in apply effects procedure
2010-07-30 01:51:33 +02:00
2012-02-21 20:03:27 +01:00
// Get mask of effects for target
uint8 mask = target -> effectMask ;
2010-07-30 01:51:33 +02:00
2012-02-21 20:03:27 +01:00
Unit * unit = m_caster -> GetGUID () == target -> targetGUID ? m_caster : ObjectAccessor :: GetUnit ( * m_caster , target -> targetGUID );
if ( ! unit )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
uint8 farMask = 0 ;
// create far target mask
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
if ( m_spellInfo -> Effects [ i ]. IsFarUnitTargetEffect ())
if (( 1 << i ) & mask )
farMask |= ( 1 << i );
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
if ( ! farMask )
return ;
// find unit in world
unit = ObjectAccessor :: FindUnit ( target -> targetGUID );
if ( ! unit )
return ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// do far effects on the unit
// can't use default call because of threading, do stuff as fast as possible
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
if ( farMask & ( 1 << i ))
HandleEffects ( unit , NULL , NULL , i , SPELL_EFFECT_HANDLE_HIT_TARGET );
return ;
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
if ( unit -> isAlive () != target -> alive )
return ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
if ( getState () == SPELL_STATE_DELAYED && ! m_spellInfo -> IsPositive () && ( getMSTime () - target -> timeDelay ) <= unit -> m_lastSanctuaryTime )
return ; // No missinfo in that case
2011-09-16 11:40:53 +02:00
2012-02-21 20:03:27 +01:00
// Get original caster (if exist) and calculate damage/healing from him data
Unit * caster = m_originalCaster ? m_originalCaster : m_caster ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Skip if m_originalCaster not avaiable
if ( ! caster )
return ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
SpellMissInfo missInfo = target -> missCondition ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Need init unitTarget by default unit (can changed in code on reflect)
// Or on missInfo != SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem)
unitTarget = unit ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Reset damage/healing counter
m_damage = target -> damage ;
m_healing = - target -> damage ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Fill base trigger info
uint32 procAttacker = m_procAttacker ;
uint32 procVictim = m_procVictim ;
uint32 procEx = m_procEx ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
m_spellAura = NULL ; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
//Spells with this flag cannot trigger if effect is casted on self
bool canEffectTrigger = ! ( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_CANT_TRIGGER_PROC ) && unitTarget -> CanProc () && CanExecuteTriggersOnHit ( mask );
Unit * spellHitTarget = NULL ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
if ( missInfo == SPELL_MISS_NONE ) // In case spell hit target, do all effect on that target
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
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
spellHitTarget = m_caster ;
if ( m_caster -> GetTypeId () == TYPEID_UNIT )
m_caster -> ToCreature () -> LowerPlayerDamageReq ( target -> damage );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
if ( spellHitTarget )
{
SpellMissInfo missInfo2 = DoSpellHitOnUnit ( spellHitTarget , mask , target -> scaleAura );
if ( missInfo2 != SPELL_MISS_NONE )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( missInfo2 != SPELL_MISS_MISS )
m_caster -> SendSpellMiss ( unit , m_spellInfo -> Id , missInfo2 );
m_damage = 0 ;
spellHitTarget = NULL ;
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Do not take combo points on dodge and miss
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
2012-02-21 20:03:27 +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 )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
// If at least one effect negative spell is negative hit
if ( mask & ( 1 << i ) && ! m_spellInfo -> IsPositiveEffect ( i ))
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
positive = false ;
2010-02-20 23:59:05 +01:00
break ;
}
}
2012-02-21 20:03:27 +01:00
switch ( m_spellInfo -> DmgClass )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
case SPELL_DAMAGE_CLASS_MAGIC :
if ( positive )
{
procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS ;
procVictim |= PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS ;
}
else
{
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 ;
2012-02-21 20:03:27 +01:00
case SPELL_DAMAGE_CLASS_NONE :
if ( positive )
{
procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS ;
procVictim |= PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS ;
}
else
{
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 ;
}
}
2012-02-21 20:03:27 +01:00
CallScriptOnHitHandlers ();
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// All calculated do it!
// Do healing and triggers
if ( m_healing > 0 )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
bool crit = caster -> isSpellCrit ( unitTarget , m_spellInfo , m_spellSchoolMask );
uint32 addhealth = m_healing ;
if ( crit )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
procEx |= PROC_EX_CRITICAL_HIT ;
addhealth = caster -> SpellCriticalHealingBonus ( m_spellInfo , addhealth , NULL );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
else
procEx |= PROC_EX_NORMAL_HIT ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
int32 gain = caster -> HealBySpell ( unitTarget , m_spellInfo , addhealth , crit );
unitTarget -> getHostileRefManager (). threatAssist ( caster , float ( gain ) * 0.5f , m_spellInfo );
m_healing = gain ;
2012-04-11 17:41:36 -05: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 , addhealth , m_attackType , m_spellInfo , m_triggeredByAuraSpell );
2012-02-21 20:03:27 +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 );
2010-12-04 10:31:14 +01:00
2012-02-21 20:03:27 +01:00
// Add bonuses and fill damageInfo struct
caster -> CalculateSpellDamageTaken ( & damageInfo , m_damage , m_spellInfo , m_attackType , target -> crit );
caster -> DealDamageMods ( damageInfo . target , damageInfo . damage , & damageInfo . absorb );
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// Send log damage message to client
caster -> SendSpellNonMeleeDamageLog ( & damageInfo );
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
procEx |= createProcExtendMask ( & damageInfo , missInfo );
procVictim |= PROC_FLAG_TAKEN_DAMAGE ;
2011-01-21 23:42:51 +01:00
2012-02-21 20:03:27 +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 );
if ( caster -> GetTypeId () == TYPEID_PLAYER && ( m_spellInfo -> Attributes & SPELL_ATTR0_STOP_ATTACK_TARGET ) == 0 &&
( m_spellInfo -> DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo -> DmgClass == SPELL_DAMAGE_CLASS_RANGED ))
caster -> ToPlayer () -> CastItemCombatSpell ( unitTarget , m_attackType , procVictim , procEx );
}
2012-05-18 12:31:13 -04:00
2012-02-21 20:03:27 +01:00
m_damage = damageInfo . damage ;
2012-05-18 12:31:13 -04:00
caster -> DealSpellDamage ( & damageInfo , true );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
// Passive spell hits/misses or active spells only misses (only triggers)
else
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
// 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
if ( missInfo == SPELL_MISS_RESIST && m_spellInfo -> AttributesCu & SPELL_ATTR0_CU_PICKPOCKET && unitTarget -> GetTypeId () == TYPEID_UNIT )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
m_caster -> RemoveAurasWithInterruptFlags ( AURA_INTERRUPT_FLAG_TALK );
if ( unitTarget -> ToCreature () -> IsAIEnabled )
unitTarget -> ToCreature () -> AI () -> AttackStart ( m_caster );
}
}
2012-09-05 17:17:45 +02:00
if ( missInfo != SPELL_MISS_EVADE && ! m_caster -> IsFriendlyTo ( unit ) && ( ! m_spellInfo -> IsPositive () || m_spellInfo -> HasEffect ( SPELL_EFFECT_DISPEL )))
2012-02-21 20:03:27 +01:00
{
m_caster -> CombatStart ( unit , ! ( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO ));
if ( m_spellInfo -> AttributesCu & SPELL_ATTR0_CU_AURA_CC )
if ( ! unit -> IsStandState ())
unit -> SetStandState ( UNIT_STAND_STATE_STAND );
}
if ( spellHitTarget )
{
//AI functions
if ( spellHitTarget -> GetTypeId () == TYPEID_UNIT )
{
if ( spellHitTarget -> ToCreature () -> IsAIEnabled )
spellHitTarget -> ToCreature () -> AI () -> SpellHit ( m_caster , m_spellInfo );
// cast at creature (or GO) quest objectives update at successful cast finished (+channel finished)
// ignore pets or autorepeat/melee casts for speed (not exist quest for spells (hm...)
if ( m_originalCaster && m_originalCaster -> IsControlledByPlayer () && ! spellHitTarget -> ToCreature () -> isPet () && ! IsAutoRepeat () && ! IsNextMeleeSwingSpell () && ! IsChannelActive ())
if ( Player * p = m_originalCaster -> GetCharmerOrOwnerPlayerOrPlayerItself ())
p -> CastedCreatureOrGO ( spellHitTarget -> GetEntry (), spellHitTarget -> GetGUID (), m_spellInfo -> Id );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
if ( m_caster -> GetTypeId () == TYPEID_UNIT && m_caster -> ToCreature () -> IsAIEnabled )
m_caster -> ToCreature () -> AI () -> SpellHitTarget ( spellHitTarget , m_spellInfo );
// Needs to be called after dealing damage/healing to not remove breaking on damage auras
DoTriggersOnSpellHit ( spellHitTarget , mask );
// if target is fallged for pvp also flag caster if a player
if ( unit -> IsPvP () && m_caster -> GetTypeId () == TYPEID_PLAYER )
m_caster -> ToPlayer () -> UpdatePvP ( true );
CallScriptAfterHitHandlers ();
}
}
SpellMissInfo Spell :: DoSpellHitOnUnit ( Unit * unit , uint32 effectMask , bool scaleAura )
{
if ( ! unit || ! effectMask )
return SPELL_MISS_EVADE ;
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
2012-06-13 12:34:59 -04:00
if ( m_spellInfo -> Speed && ( unit -> IsImmunedToDamage ( m_spellInfo ) || unit -> IsImmunedToSpell ( m_spellInfo )))
return SPELL_MISS_IMMUNE ;
2012-02-21 20:03:27 +01:00
// disable effects to which unit is immune
2012-06-13 12:34:59 -04:00
SpellMissInfo returnVal = SPELL_MISS_IMMUNE ;
2012-02-21 20:03:27 +01:00
for ( uint32 effectNumber = 0 ; effectNumber < MAX_SPELL_EFFECTS ; ++ effectNumber )
2012-06-13 12:34:59 -04:00
{
if ( effectMask & ( 1 << effectNumber ))
2012-07-30 10:07:26 +02:00
{
2012-06-13 12:34:59 -04:00
if ( unit -> IsImmunedToSpellEffect ( m_spellInfo , effectNumber ))
effectMask &= ~ ( 1 << effectNumber );
else if ( m_spellInfo -> Effects [ effectNumber ]. IsAura () && ! m_spellInfo -> IsPositiveEffect ( effectNumber ))
{
int32 debuff_resist_chance = unit -> GetMaxPositiveAuraModifierByMiscValue ( SPELL_AURA_MOD_DEBUFF_RESISTANCE , int32 ( m_spellInfo -> Dispel ));
debuff_resist_chance += unit -> GetMaxNegativeAuraModifierByMiscValue ( SPELL_AURA_MOD_DEBUFF_RESISTANCE , int32 ( m_spellInfo -> Dispel ));
if ( debuff_resist_chance > 0 )
if ( irand ( 0 , 10000 ) <= ( debuff_resist_chance * 100 ))
{
effectMask &= ~ ( 1 << effectNumber );
returnVal = SPELL_MISS_RESIST ;
}
}
2012-07-30 10:07:26 +02:00
}
2012-06-13 12:34:59 -04:00
}
2012-07-30 10:07:26 +02:00
2012-06-13 12:34:59 -04:00
if ( ! effectMask )
return returnVal ;
2012-02-21 20:03:27 +01:00
PrepareScriptHitHandlers ();
CallScriptBeforeHitHandlers ();
if ( unit -> GetTypeId () == TYPEID_PLAYER )
{
unit -> ToPlayer () -> GetAchievementMgr (). StartTimedAchievement ( ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET , m_spellInfo -> Id );
unit -> ToPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET , m_spellInfo -> Id , 0 , m_caster );
unit -> ToPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 , m_spellInfo -> Id );
}
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
{
m_caster -> ToPlayer () -> GetAchievementMgr (). StartTimedAchievement ( ACHIEVEMENT_TIMED_TYPE_SPELL_CASTER , m_spellInfo -> Id );
m_caster -> ToPlayer () -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 , m_spellInfo -> Id , 0 , unit );
}
if ( m_caster != unit )
{
// Recheck UNIT_FLAG_NON_ATTACKABLE for delayed spells
if ( m_spellInfo -> Speed > 0.0f && unit -> HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_NON_ATTACKABLE ) && unit -> GetCharmerOrOwnerGUID () != m_caster -> GetGUID ())
return SPELL_MISS_EVADE ;
if ( m_caster -> _IsValidAttackTarget ( unit , m_spellInfo ))
{
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
if (( m_spellInfo -> AttributesCu & SPELL_ATTR0_CU_AURA_CC ) && unit -> IsControlledByPlayer ())
unit -> RemoveAurasByType ( SPELL_AURA_MOD_STEALTH );
}
else if ( m_caster -> IsFriendlyTo ( unit ))
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
// for delayed spells ignore negative spells (after duel end) for friendly targets
// TODO: this cause soul transfer bugged
if ( m_spellInfo -> Speed > 0.0f && unit -> GetTypeId () == TYPEID_PLAYER && ! m_spellInfo -> IsPositive ())
return SPELL_MISS_EVADE ;
// assisting case, healing and resurrection
if ( unit -> HasUnitState ( UNIT_STATE_ATTACK_PLAYER ))
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
m_caster -> SetContestedPvP ();
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
m_caster -> ToPlayer () -> UpdatePvP ( true );
}
if ( unit -> isInCombat () && ! ( m_spellInfo -> AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO ))
{
m_caster -> SetInCombatState ( unit -> GetCombatTimer () > 0 , unit );
unit -> getHostileRefManager (). threatAssist ( m_caster , 0.0f );
}
}
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +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
m_diminishGroup = GetDiminishingReturnsGroupForSpell ( m_spellInfo , m_triggeredByAuraSpell );
if ( m_diminishGroup )
{
m_diminishLevel = unit -> GetDiminishing ( m_diminishGroup );
DiminishingReturnsType type = GetDiminishingReturnsGroupType ( m_diminishGroup );
// Increase Diminishing on unit, current informations for actually casts will use values above
if (( type == DRTYPE_PLAYER && unit -> GetCharmerOrOwnerPlayerOrPlayerItself ()) || type == DRTYPE_ALL )
unit -> IncrDiminishing ( m_diminishGroup );
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
uint8 aura_effmask = 0 ;
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
if ( effectMask & ( 1 << i ) && m_spellInfo -> Effects [ i ]. IsUnitOwnedAuraEffect ())
aura_effmask |= 1 << i ;
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
SpellInfo const * aurSpellInfo = m_spellInfo ;
int32 basePoints [ 3 ];
if ( scaleAura )
{
aurSpellInfo = m_spellInfo -> GetAuraRankForLevel ( unitTarget -> getLevel ());
ASSERT ( aurSpellInfo );
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
{
basePoints [ i ] = aurSpellInfo -> Effects [ i ]. BasePoints ;
if ( m_spellInfo -> Effects [ i ]. Effect != aurSpellInfo -> Effects [ i ]. Effect )
{
aurSpellInfo = m_spellInfo ;
break ;
2010-02-20 23:59:05 +01:00
}
}
2012-02-21 20:03:27 +01:00
}
if ( m_originalCaster )
{
bool refresh = false ;
m_spellAura = Aura :: TryRefreshStackOrCreate ( aurSpellInfo , effectMask , unit ,
m_originalCaster , ( aurSpellInfo == m_spellInfo ) ? & m_spellValue -> EffectBasePoints [ 0 ] : & basePoints [ 0 ], m_CastItem , 0 , & refresh );
if ( m_spellAura )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
// Set aura stack amount to desired value
if ( m_spellValue -> AuraStackAmount > 1 )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( ! refresh )
m_spellAura -> SetStackAmount ( m_spellValue -> AuraStackAmount );
else
m_spellAura -> ModStackAmount ( m_spellValue -> AuraStackAmount );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
// Now Reduce spell duration using data received at spell hit
int32 duration = m_spellAura -> GetMaxDuration ();
int32 limitduration = GetDiminishingReturnsLimitDuration ( m_diminishGroup , aurSpellInfo );
float diminishMod = unit -> ApplyDiminishingToDuration ( m_diminishGroup , duration , m_originalCaster , m_diminishLevel , limitduration );
// unit is immune to aura if it was diminished to 0 duration
if ( diminishMod == 0.0f )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
m_spellAura -> Remove ();
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-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
else
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
(( UnitAura * ) m_spellAura ) -> SetDiminishGroup ( m_diminishGroup );
bool positive = m_spellAura -> GetSpellInfo () -> IsPositive ();
if ( AuraApplication * aurApp = m_spellAura -> GetApplicationOfTarget ( m_originalCaster -> GetGUID ()))
positive = aurApp -> IsPositive ();
duration = m_originalCaster -> ModSpellDuration ( aurSpellInfo , unit , duration , positive , effectMask );
// Haste modifies duration of channeled spells
if ( m_spellInfo -> IsChanneled ())
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
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-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
if ( duration != m_spellAura -> GetMaxDuration ())
{
m_spellAura -> SetMaxDuration ( duration );
m_spellAura -> SetDuration ( duration );
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
m_spellAura -> _RegisterForTargets ();
2010-02-20 23:59:05 +01:00
}
}
2012-02-21 20:03:27 +01:00
}
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
for ( uint32 effectNumber = 0 ; effectNumber < MAX_SPELL_EFFECTS ; ++ effectNumber )
if ( effectMask & ( 1 << effectNumber ))
HandleEffects ( unit , NULL , NULL , effectNumber , SPELL_EFFECT_HANDLE_HIT_TARGET );
return SPELL_MISS_NONE ;
}
void Spell :: DoTriggersOnSpellHit ( Unit * unit , uint8 effMask )
{
// Apply additional spell effects to target
// TODO: move this code to scripts
if ( m_preCastSpell )
{
// Paladin immunity shields
if ( m_preCastSpell == 61988 )
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
// Cast Forbearance
m_caster -> CastSpell ( unit , 25771 , true );
// Cast Avenging Wrath Marker
unit -> CastSpell ( unit , 61987 , true );
}
2010-06-18 04:17:21 +02:00
2012-02-21 20:03:27 +01:00
// Avenging Wrath
if ( m_preCastSpell == 61987 )
// Cast the serverside immunity shield marker
m_caster -> CastSpell ( unit , 61988 , true );
2010-06-18 04:17:21 +02:00
2012-02-21 20:03:27 +01:00
if ( sSpellMgr -> GetSpellInfo ( m_preCastSpell ))
// Blizz seems to just apply aura without bothering to cast
m_caster -> AddAura ( m_preCastSpell , unit );
}
2010-06-18 04:17:21 +02:00
2012-02-21 20:03:27 +01: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
if ( ! m_hitTriggerSpells . empty ())
{
int _duration = 0 ;
2012-04-05 20:09:20 +02:00
for ( HitTriggerSpellList :: const_iterator i = m_hitTriggerSpells . begin (); i != m_hitTriggerSpells . end (); ++ i )
2012-02-21 20:03:27 +01:00
{
2012-04-05 20:09:20 +02:00
if ( CanExecuteTriggersOnHit ( effMask , i -> triggeredByAura ) && roll_chance_i ( i -> chance ))
2010-06-18 04:17:21 +02:00
{
2012-04-05 20:09:20 +02:00
m_caster -> CastSpell ( unit , i -> triggeredSpell , true );
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura" , m_spellInfo -> Id , i -> triggeredSpell -> Id );
2011-05-22 16:01:53 -07:00
2012-02-21 20:03:27 +01:00
// SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration
// set duration of current aura to the triggered spell
2012-04-05 20:09:20 +02:00
if ( i -> triggeredSpell -> GetDuration () == - 1 )
2012-02-21 20:03:27 +01:00
{
2012-04-05 20:09:20 +02:00
if ( Aura * triggeredAur = unit -> GetAura ( i -> triggeredSpell -> Id , m_caster -> GetGUID ()))
2010-06-18 04:17:21 +02:00
{
2012-02-21 20:03:27 +01:00
// get duration from aura-only once
if ( ! _duration )
{
Aura * aur = unit -> GetAura ( m_spellInfo -> Id , m_caster -> GetGUID ());
_duration = aur ? aur -> GetDuration () : - 1 ;
}
triggeredAur -> SetDuration ( _duration );
2010-06-18 04:17:21 +02:00
}
}
}
2012-02-21 20:03:27 +01:00
}
}
2010-08-08 19:45:53 +02:00
2012-02-21 20:03:27 +01:00
// trigger linked auras remove/apply
// TODO: remove/cleanup this, as this table is not documented and people are doing stupid things with it
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 ());
}
void Spell :: DoAllEffectOnTarget ( GOTargetInfo * target )
{
if ( target -> processed ) // Check target
return ;
target -> processed = true ; // Target checked in apply effects procedure
uint32 effectMask = target -> effectMask ;
if ( ! effectMask )
return ;
GameObject * go = m_caster -> GetMap () -> GetGameObject ( target -> targetGUID );
if ( ! go )
return ;
PrepareScriptHitHandlers ();
CallScriptBeforeHitHandlers ();
for ( uint32 effectNumber = 0 ; effectNumber < MAX_SPELL_EFFECTS ; ++ effectNumber )
if ( effectMask & ( 1 << effectNumber ))
HandleEffects ( NULL , NULL , go , effectNumber , SPELL_EFFECT_HANDLE_HIT_TARGET );
CallScriptOnHitHandlers ();
// cast at creature (or GO) quest objectives update at successful cast finished (+channel finished)
// 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 ())
p -> CastedCreatureOrGO ( go -> GetEntry (), go -> GetGUID (), m_spellInfo -> Id );
CallScriptAfterHitHandlers ();
}
void Spell :: DoAllEffectOnTarget ( ItemTargetInfo * target )
{
uint32 effectMask = target -> effectMask ;
if ( ! target -> item || ! effectMask )
return ;
PrepareScriptHitHandlers ();
CallScriptBeforeHitHandlers ();
for ( uint32 effectNumber = 0 ; effectNumber < MAX_SPELL_EFFECTS ; ++ effectNumber )
if ( effectMask & ( 1 << effectNumber ))
HandleEffects ( NULL , target -> item , NULL , effectNumber , SPELL_EFFECT_HANDLE_HIT_TARGET );
CallScriptOnHitHandlers ();
CallScriptAfterHitHandlers ();
}
bool Spell :: UpdateChanneledTargetList ()
{
// Not need check return true
if ( m_channelTargetEffectMask == 0 )
return true ;
uint8 channelTargetEffectMask = m_channelTargetEffectMask ;
uint8 channelAuraMask = 0 ;
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
if ( m_spellInfo -> Effects [ i ]. Effect == SPELL_EFFECT_APPLY_AURA )
channelAuraMask |= 1 << i ;
channelAuraMask &= channelTargetEffectMask ;
float range = 0 ;
if ( channelAuraMask )
{
range = m_spellInfo -> GetMaxRange ( m_spellInfo -> IsPositive ());
if ( Player * modOwner = m_caster -> GetSpellModOwner ())
modOwner -> ApplySpellMod ( m_spellInfo -> Id , SPELLMOD_RANGE , range , this );
}
for ( std :: list < TargetInfo >:: iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end (); ++ ihit )
{
if ( ihit -> missCondition == SPELL_MISS_NONE && ( channelTargetEffectMask & ihit -> effectMask ))
{
Unit * unit = m_caster -> GetGUID () == ihit -> targetGUID ? m_caster : ObjectAccessor :: GetUnit ( * m_caster , ihit -> targetGUID );
if ( ! unit )
continue ;
if ( IsValidDeadOrAliveTarget ( unit ))
2010-02-20 23:59:05 +01:00
{
2012-02-21 20:03:27 +01:00
if ( channelAuraMask & ihit -> effectMask )
{
if ( AuraApplication * aurApp = unit -> GetAuraApplication ( m_spellInfo -> Id , m_originalCasterGUID ))
{
if ( m_caster != unit && ! m_caster -> IsWithinDistInMap ( unit , range ))
{
ihit -> effectMask &= ~ aurApp -> GetEffectMask ();
unit -> RemoveAura ( aurApp );
continue ;
}
}
else // aura is dispelled
continue ;
}
2010-02-20 23:59:05 +01:00
2012-02-21 20:03:27 +01:00
channelTargetEffectMask &= ~ ihit -> effectMask ; // remove from need alive mask effect that have alive target
2010-02-20 23:59:05 +01:00
}
2012-02-21 20:03:27 +01:00
}
}
2011-01-21 23:42:51 +01:00
2012-02-21 20:03:27 +01:00
// is all effects from m_needAliveTargetMask have alive targets
return channelTargetEffectMask == 0 ;
}
2011-01-21 23:42:51 +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
// 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 )
2012-08-31 01:26:21 +01:00
{
2011-05-17 13:33:24 +02:00
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , false );
2012-09-04 16:14:15 +01:00
2012-08-31 01:26:21 +01:00
// Set casttime to 0 if .cheat casttime is enabled.
if ( m_caster -> ToPlayer () -> GetCommandStatus ( CHEAT_CASTTIME ))
m_casttime = 0 ;
}
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 );
2012-03-26 03:12:56 +02:00
if ( m_spellInfo -> IsChanneled ()) // if not channeled then the object for the current cast wasn't summoned yet
2012-03-26 03:02:05 +03: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
}
2011-06-12 01:47:45 +02:00
if ( Player * playerCaster = m_caster -> ToPlayer ())
2012-04-05 20:32:02 -04:00
{
// now that we've done the basic check, now run the scripts
// should be done before the spell is actually executed
2010-12-22 21:25:23 +01:00
sScriptMgr -> OnPlayerSpellCast ( playerCaster , this , skipCheck );
2010-09-03 19:58:16 -07:00
2012-04-20 20:22:40 -04:00
// As of 3.0.2 pets begin attacking their owner's target immediately
// Let any pets know we've attacked something. Check DmgClass for harmful spells only
// This prevents spells such as Hunter's Mark from triggering pet attack
if ( this -> GetSpellInfo () -> DmgClass != SPELL_DAMAGE_CLASS_NONE )
if ( Pet * playerPet = playerCaster -> GetPet ())
if ( playerPet -> isAlive () && playerPet -> isControlled () && ( m_targets . GetTargetMask () & TARGET_FLAG_UNIT ))
playerPet -> AI () -> OwnerAttacked ( m_targets . GetObjectTarget () -> ToUnit ());
2012-04-05 20:32:02 -04: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-12-31 13:10:13 +01:00
CallScriptBeforeCastHandlers ();
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
2011-12-31 13:10:13 +01:00
CallScriptOnCastHandlers ();
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 );
2012-02-03 19:02:17 +02:00
if ( m_caster -> HasUnitState ( UNIT_STATE_CASTING ) && ! m_caster -> IsNonMeleeSpellCasted ( false , false , true ))
m_caster -> ClearUnitState ( UNIT_STATE_CASTING );
2010-02-20 23:59:05 +01:00
}
else
{
// Immediate spell, no big deal
handle_immediate ();
}
2011-12-31 13:10:13 +01:00
CallScriptAfterCastHandlers ();
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 )
2012-08-31 01:26:21 +01:00
{
2010-03-07 15:20:19 +01:00
m_caster -> ToPlayer () -> SetSpellModTakingSpell ( this , false );
2012-09-04 16:14:15 +01:00
2012-08-31 01:26:21 +01:00
//Clear spell cooldowns after every spell is cast if .cheat cooldown is enabled.
if ( m_caster -> ToPlayer () -> GetCommandStatus ( CHEAT_COOLDOWN ))
m_caster -> ToPlayer () -> RemoveSpellCooldown ( m_spellInfo -> Id , true );
}
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 );
}
2011-12-22 00:38:01 +01:00
else if ( duration == - 1 )
{
m_spellState = SPELL_STATE_CASTING ;
m_caster -> AddInterruptMask ( m_spellInfo -> ChannelInterruptFlags );
SendChannelStart ( duration );
}
2010-02-20 23:59:05 +01:00
}
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 ));
2012-05-18 11:44:38 -04:00
2012-05-13 19:39:06 -05:00
if ( ! m_originalCaster )
return ;
// Handle procs on cast
// TODO: finish new proc system:P
if ( m_UniqueTargetInfo . empty () && m_targets . HasDst ())
{
uint32 procAttacker = m_procAttacker ;
if ( ! procAttacker )
procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS ;
2012-05-18 11:44:38 -04:00
2012-05-13 19:39:06 -05:00
// Proc the spells that have DEST target
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 ) &&
2012-03-17 20:34:03 +01:00
( m_spellInfo -> Effects [ 0 ]. Effect != SPELL_EFFECT_STUCK || ! m_caster -> HasUnitMovementFlag ( MOVEMENTFLAG_FALLING_FAR )))
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 :
{
2011-12-22 18:48:06 +01:00
if ( m_timer > 0 )
2010-02-20 23:59:05 +01:00
{
2011-12-22 13:22:18 +01:00
if ( difftime >= ( uint32 ) 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 );
2011-12-22 13:22:18 +01:00
break ;
}
2010-02-20 23:59:05 +01:00
case SPELL_STATE_CASTING :
{
2011-12-22 18:48:06 +01:00
if ( m_timer )
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 ();
}
2011-12-22 18:48:06 +01:00
if ( m_timer > 0 )
{
if ( difftime >= ( uint32 ) m_timer )
m_timer = 0 ;
else
m_timer -= difftime ;
}
2010-02-20 23:59:05 +01:00
}
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 ();
}
2011-12-22 13:22:18 +01:00
break ;
}
2010-02-20 23:59:05 +01:00
default :
2011-12-22 13:22:18 +01:00
break ;
2010-02-20 23:59:05 +01:00
}
}
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 ();
2012-02-03 19:02:17 +02:00
if ( m_caster -> HasUnitState ( UNIT_STATE_CASTING ) && ! m_caster -> IsNonMeleeSpellCasted ( false , false , true ))
m_caster -> ClearUnitState ( UNIT_STATE_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 :
2011-12-22 00:38:01 +01:00
data << uint32 ( spellInfo -> RequiresSpellFocus ); // SpellFocusObject.dbc id
2010-02-20 23:59:05 +01:00
break ;
2011-12-22 00:38:01 +01:00
case SPELL_FAILED_REQUIRES_AREA : // AreaTable.dbc id
2010-02-20 23:59:05 +01:00
// 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 :
2011-12-22 00:38:01 +01:00
case SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND :
case SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND :
2010-02-20 23:59:05 +01:00
data << uint32 ( spellInfo -> EquippedItemClass );
data << uint32 ( spellInfo -> EquippedItemSubClassMask );
break ;
case SPELL_FAILED_TOO_MANY_OF_ITEM :
{
2010-04-19 09:26:37 +02:00
uint32 item = 0 ;
2012-03-16 08:59:18 +01:00
for ( int8 eff = 0 ; eff < MAX_SPELL_EFFECTS ; eff ++ )
if ( spellInfo -> Effects [ eff ]. ItemType )
item = spellInfo -> Effects [ eff ]. ItemType ;
ItemTemplate const * proto = sObjectMgr -> GetItemTemplate ( item );
if ( proto && proto -> ItemLimitCategory )
data << uint32 ( proto -> ItemLimitCategory );
2010-02-20 23:59:05 +01:00
break ;
}
2011-03-04 21:18:38 +01:00
case SPELL_FAILED_CUSTOM_ERROR :
data << uint32 ( customError );
break ;
2012-02-15 00:46:08 +01:00
case SPELL_FAILED_REAGENTS :
{
uint32 missingItem = 0 ;
for ( uint32 i = 0 ; i < MAX_SPELL_REAGENTS ; i ++ )
{
if ( spellInfo -> Reagent [ i ] <= 0 )
continue ;
uint32 itemid = spellInfo -> Reagent [ i ];
uint32 itemcount = spellInfo -> ReagentCount [ i ];
if ( ! caster -> HasItemCount ( itemid , itemcount ))
{
missingItem = itemid ;
break ;
}
}
data << uint32 ( missingItem ); // first missing item
break ;
}
2012-03-16 08:59:18 +01:00
case SPELL_FAILED_PREVENTED_BY_MECHANIC :
data << uint32 ( spellInfo -> Mechanic );
break ;
case SPELL_FAILED_NEED_EXOTIC_AMMO :
data << uint32 ( spellInfo -> EquippedItemSubClassMask );
break ;
case SPELL_FAILED_NEED_MORE_ITEMS :
data << uint32 ( 0 ); // Item entry
data << uint32 ( 0 ); // Count
break ;
case SPELL_FAILED_MIN_SKILL :
data << uint32 ( 0 ); // SkillLine.dbc Id
data << uint32 ( 0 ); // Amount
break ;
case SPELL_FAILED_FISHING_TOO_LOW :
data << uint32 ( 0 ); // Skill level
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
2011-12-22 00:38:01 +01:00
data << int32 ( m_timer ); // delay?
2010-02-20 23:59:05 +01:00
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
2012-03-16 08:59:18 +01:00
2010-02-20 23:59:05 +01:00
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
}
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
}
2012-01-08 18:50:25 +03:00
if ( m_targets . HasTraj ())
castFlags |= CAST_FLAG_ADJUST_MISSILE ;
2010-02-20 23:59:05 +01:00
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-10-31 09:56:04 -04:00
//TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature
//The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster
if ( 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
for ( uint8 i = 0 ; i < MAX_RUNES ; ++ i )
2011-04-07 23:13:35 +02:00
{
2011-10-31 09:56:04 -04: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
}
2011-04-07 23:13:35 +02:00
}
2010-02-20 23:59:05 +01:00
}
}
2012-01-08 18:50:25 +03:00
if ( castFlags & CAST_FLAG_ADJUST_MISSILE )
2010-02-20 23:59:05 +01:00
{
2012-01-08 18:50:25 +03:00
data << m_targets . GetElevation ();
2012-01-13 19:18:13 +03:00
data << uint32 ( m_delayMoment );
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 );
2012-03-16 08:59:18 +01:00
if ( castFlags & CAST_FLAG_VISUAL_CHAIN )
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 )
{
2012-03-14 18:51:51 +01:00
Item * pItem = m_caster -> ToPlayer () -> GetWeaponForAttack ( RANGED_ATTACK );
if ( pItem )
2010-02-20 23:59:05 +01:00
{
2012-03-14 18:51:51 +01:00
ammoInventoryType = pItem -> GetTemplate () -> InventoryType ;
2010-04-07 22:59:46 +02:00
if ( ammoInventoryType == INVTYPE_THROWN )
2012-03-14 18:51:51 +01: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 );
}
2012-09-03 02:45:27 +01:00
/// Writes miss and hit targets for a SMSG_SPELL_GO packet
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
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 ;
}
2012-09-03 02:45:27 +01:00
// Hit and miss target counts are both uint8, that limits us to 255 targets for each
// sending more than 255 targets crashes the client (since count sent would be wrong)
// Spells like 40647 (with a huge radius) can easily reach this limit (spell might need
// target conditions but we still need to limit the number of targets sent and keeping
// correct count for both hit and miss).
uint32 hit = 0 ;
size_t hitPos = data -> wpos ();
* data << ( uint8 ) 0 ; // placeholder
for ( std :: list < TargetInfo >:: const_iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end () && hit <= 255 ; ++ ihit )
2010-02-20 23:59:05 +01:00
{
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 ;
2012-09-03 02:45:27 +01:00
++ hit ;
2010-02-20 23:59:05 +01:00
}
}
2012-09-03 02:45:27 +01:00
for ( std :: list < GOTargetInfo >:: const_iterator ighit = m_UniqueGOTargetInfo . begin (); ighit != m_UniqueGOTargetInfo . end () && hit <= 255 ; ++ ighit )
{
2010-02-20 23:59:05 +01:00
* data << uint64 ( ighit -> targetGUID ); // Always hits
2012-09-03 02:45:27 +01:00
++ hit ;
}
2010-02-20 23:59:05 +01:00
2012-09-03 02:45:27 +01:00
uint32 miss = 0 ;
size_t missPos = data -> wpos ();
* data << ( uint8 ) 0 ; // placeholder
for ( std :: list < TargetInfo >:: const_iterator ihit = m_UniqueTargetInfo . begin (); ihit != m_UniqueTargetInfo . end () && miss <= 255 ; ++ ihit )
2010-02-20 23:59:05 +01:00
{
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 );
2012-09-03 02:45:27 +01:00
++ miss ;
2010-02-20 23:59:05 +01:00
}
}
// 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 ;
2012-09-03 02:45:27 +01:00
data -> put < uint8 > ( hitPos , ( uint8 ) hit );
data -> put < uint8 > ( missPos , ( uint8 ) miss );
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 );
}
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
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SPELLS_AURAS , "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 ;
2012-08-31 01:26:21 +01:00
//Don't take power if the spell is cast while .cheat power is enabled.
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
{
if ( m_caster -> ToPlayer () -> GetCommandStatus ( CHEAT_POWER ))
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
{
if ( ihit -> missCondition != SPELL_MISS_NONE )
{
2012-04-07 16:20:01 -05:00
hit = false ;
2010-02-20 23:59:05 +01:00
//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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SPELLS_AURAS , "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
{
2012-03-14 18:51:51 +01:00
Item * pItem = m_caster -> ToPlayer () -> GetWeaponForAttack ( RANGED_ATTACK );
2010-02-20 23:59:05 +01:00
// wands don't have ammo
2012-03-14 18:51:51 +01:00
if ( ! pItem || pItem -> IsBroken () || pItem -> GetTemplate () -> SubClass == ITEM_SUBCLASS_WEAPON_WAND )
2010-02-20 23:59:05 +01:00
return ;
2012-03-14 18:51:51 +01:00
if ( pItem -> GetTemplate () -> InventoryType == INVTYPE_THROWN )
2010-02-20 23:59:05 +01:00
{
2012-03-14 18:51:51 +01: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 ;
2012-03-14 18:51:51 +01: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-11-07 11:06:39 -06:00
Player * player = ( Player * ) m_caster ;
2010-02-20 23:59:05 +01:00
2011-11-07 11:06:39 -06:00
if ( player -> 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 )
{
2011-11-07 11:06:39 -06:00
RuneType rune = player -> GetCurrentRune ( i );
if (( player -> 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 ;
2012-02-23 13:01:16 +01:00
ItemTemplate const * castItemTemplate = m_CastItem ? m_CastItem -> GetTemplate () : NULL ;
2011-09-05 14:01:50 +02:00
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 ;
2012-03-03 00:19:00 +01:00
destTarget = & m_destTargets [ i ]. _position ;
2010-02-20 23:59:05 +01:00
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 )
2012-02-16 13:56:08 +01:00
if ( uint32 (( * blockItr ) -> GetMiscValue ()) == m_spellInfo -> SpellFamilyName )
2011-10-02 16:23:52 +02:00
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
2012-03-17 20:34:03 +01:00
if (( ! m_caster -> HasUnitMovementFlag ( MOVEMENTFLAG_FALLING_FAR ) || 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 ;
}
2012-02-10 23:40:38 +01:00
// check spell cast conditions from database
2012-02-09 18:35:52 +01:00
{
2012-02-10 23:40:38 +01:00
ConditionSourceInfo condInfo = ConditionSourceInfo ( m_caster );
condInfo . mConditionTargets [ 1 ] = m_targets . GetObjectTarget ();
2012-02-09 18:35:52 +01:00
ConditionList conditions = sConditionMgr -> GetConditionsForNotGroupedEntry ( CONDITION_SOURCE_TYPE_SPELL , m_spellInfo -> Id );
2012-02-10 23:40:38 +01:00
if ( ! conditions . empty () && ! sConditionMgr -> IsObjectMeetToConditions ( condInfo , conditions ))
{
// send error msg to player if condition failed and text message available
// TODO: using WorldSession::SendNotification is not blizzlike
if ( Player * playerCaster = m_caster -> ToPlayer ())
{
2012-03-09 17:15:22 -05:00
// mLastFailedCondition can be NULL if there was an error processing the condition in Condition::Meets (i.e. wrong data for ConditionTarget or others)
if ( playerCaster -> GetSession () && condInfo . mLastFailedCondition
2012-02-14 12:46:26 -05:00
&& condInfo . mLastFailedCondition -> ErrorTextId )
2012-02-25 11:52:28 +01:00
{
2012-02-14 12:46:26 -05:00
playerCaster -> GetSession () -> SendNotification ( condInfo . mLastFailedCondition -> ErrorTextId );
2012-02-25 11:52:28 +01:00
return SPELL_FAILED_DONT_REPORT ;
}
2012-02-10 23:40:38 +01:00
}
2012-03-09 17:15:22 -05:00
if ( ! condInfo . mLastFailedCondition || ! condInfo . mLastFailedCondition -> ConditionTarget )
2012-02-25 11:52:28 +01:00
return SPELL_FAILED_CASTER_AURASTATE ;
return SPELL_FAILED_BAD_TARGETS ;
2012-02-10 23:40:38 +01:00
}
2012-02-09 18:35:52 +01:00
}
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
2012-05-28 22:16:47 +01:00
if ( m_caster -> GetEntry () != WORLD_TRIGGER ) // Ignore LOS for gameobjects casts (wrongly casted by a trigger)
if ( ! ( m_spellInfo -> AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS ) && VMAP :: VMapFactory :: checkSpellForLoS ( m_spellInfo -> Id ) && ! m_caster -> IsWithinLOSInMap ( target ))
return SPELL_FAILED_LINE_OF_SIGHT ;
2010-02-20 23:59:05 +01:00
}
2011-09-16 22:17:20 +02:00
}
2010-02-20 23:59:05 +01:00
2012-05-28 04:07:51 +02:00
// Check for line of sight for spells with dest
2012-02-02 19:06:28 +01:00
if ( m_targets . HasDst ())
{
float x , y , z ;
2012-03-03 00:19:00 +01:00
m_targets . GetDstPos () -> GetPosition ( x , y , z );
2012-02-02 19:06:28 +01:00
if ( ! ( m_spellInfo -> AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS ) && VMAP :: VMapFactory :: checkSpellForLoS ( m_spellInfo -> Id ) && ! m_caster -> IsWithinLOS ( x , y , z ))
return SPELL_FAILED_LINE_OF_SIGHT ;
}
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 ;
2012-03-13 13:03:41 -04:00
bool hasDispellableAura = false ;
2012-03-16 17:59:10 -04:00
bool hasNonDispelEffect = false ;
2012-05-28 04:07:51 +02:00
uint32 dispelMask = 0 ;
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2012-03-13 13:03:41 -04:00
if ( m_spellInfo -> Effects [ i ]. Effect == SPELL_EFFECT_DISPEL )
2012-03-15 14:12:40 -04:00
{
2012-03-16 09:08:46 -04:00
if ( m_spellInfo -> Effects [ i ]. IsTargetingArea () || m_spellInfo -> AttributesEx & SPELL_ATTR1_MELEE_COMBAT_START )
2012-03-15 14:12:40 -04:00
{
hasDispellableAura = true ;
break ;
}
2012-05-28 04:07:51 +02:00
dispelMask |= SpellInfo :: GetDispelMask ( DispelType ( m_spellInfo -> Effects [ i ]. MiscValue ));
2012-03-15 14:12:40 -04:00
}
2012-03-16 17:59:10 -04:00
else if ( m_spellInfo -> Effects [ i ]. IsEffect ())
{
hasNonDispelEffect = true ;
break ;
}
2012-03-13 13:03:41 -04:00
2012-05-28 04:07:51 +02:00
if ( ! hasNonDispelEffect && ! hasDispellableAura && dispelMask && ! IsTriggered ())
{
if ( Unit * target = m_targets . GetUnitTarget ())
{
DispelChargesList dispelList ;
target -> GetDispellableAuraList ( m_caster , dispelMask , dispelList );
if ( dispelList . empty ())
return SPELL_FAILED_NOTHING_TO_DISPEL ;
}
}
2012-03-13 13:03:41 -04:00
2012-05-28 04:07:51 +02:00
for ( uint8 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_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 ();
}
2012-02-03 19:02:17 +02:00
if ( m_caster -> HasUnitState ( UNIT_STATE_ROOT ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_ROOTED ;
2012-09-06 11:05:45 -04:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
if ( Unit * target = m_targets . GetUnitTarget ())
if ( ! target -> isAlive ())
return SPELL_FAILED_BAD_TARGETS ;
2010-02-20 23:59:05 +01:00
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 ;
2012-02-27 14:58:47 +01:00
uint32 skill = creature -> GetCreatureTemplate () -> GetRequiredLootSkill ();
2010-02-20 23:59:05 +01:00
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-02-20 23:59:05 +01:00
2012-04-08 16:22:19 -05:00
if ( pet && 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 :
{
2012-04-28 02:56:29 +02:00
if ( m_caster -> HasUnitState ( UNIT_STATE_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
}
}
2012-06-08 22:25:33 +02:00
for ( uint8 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_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 ())
{
2012-03-02 22:00:26 -03:00
Battlefield * Bf = sBattlefieldMgr -> GetBattlefieldToZoneId ( m_originalCaster -> GetZoneId ());
2012-08-21 23:01:24 +02:00
if ( AreaTableEntry const * area = GetAreaEntryByAreaID ( m_originalCaster -> GetAreaId ()))
if ( area -> flags & AREA_FLAG_NO_FLY_ZONE || ( Bf && ! Bf -> CanFlyIn ()))
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 :
{
2012-02-03 22:24:03 +01:00
if ( m_spellInfo -> Effects [ i ]. IsTargetingArea ())
2012-01-31 20:27:22 -05:00
break ;
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 )
{
2012-02-03 19:02:17 +02:00
if ( m_caster -> HasUnitState ( UNIT_STATE_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
2012-02-25 14:05:47 +01:00
if ( m_spellInfo -> NeedsExplicitUnitTarget ())
2011-08-20 09:49:18 +02:00
{
2012-02-25 14:05:47 +01:00
if ( ! target )
return SPELL_FAILED_BAD_IMPLICIT_TARGETS ;
m_targets . SetUnitTarget ( target );
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
{
2012-08-05 04:18:22 +02:00
for ( uint8 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 ;
2012-08-05 04:18:22 +02:00
if ( auraInfo -> GetSchoolMask () & school_immune && ! ( auraInfo -> AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_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 )
{
2011-12-24 08:40:30 +01:00
// check needed by 68766 51693 - both spells are cast on enemies and have 0 max range
// these are triggered by other spells - possibly we should omit range check in that case?
2011-10-19 00:24:43 +02:00
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
{
2012-03-03 00:19:00 +01:00
if ( ! m_caster -> IsWithinDist3d ( m_targets . GetDstPos (), max_range ))
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_OUT_OF_RANGE ;
2012-03-03 00:19:00 +01:00
if ( min_range && m_caster -> IsWithinDist3d ( m_targets . GetDstPos (), 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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SPELLS_AURAS , "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 ))
2012-02-15 00:46:08 +01:00
return SPELL_FAILED_REAGENTS ;
2010-02-20 23:59:05 +01:00
}
}
// check totem-item requirements (items presence in inventory)
uint32 totems = 2 ;
2012-03-28 19:11:50 +08:00
for ( int i = 0 ; i < 2 ; ++ i )
2010-02-20 23:59:05 +01:00
{
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 :
{
2012-03-28 20:00:29 +08: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 ;
2012-03-28 20:00:29 +08:00
2012-03-14 18:51:51 +01:00
Item * pItem = m_caster -> ToPlayer () -> GetWeaponForAttack ( m_attackType );
if ( ! pItem || pItem -> IsBroken ())
2010-02-20 23:59:05 +01:00
return SPELL_FAILED_EQUIPPED_ITEM ;
2012-03-14 18:51:51 +01:00
switch ( pItem -> GetTemplate () -> SubClass )
2010-02-20 23:59:05 +01:00
{
case ITEM_SUBCLASS_WEAPON_THROWN :
{
2012-03-14 18:51:51 +01:00
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 ;
2012-03-28 20:00:29 +08:00
};
break ;
2010-02-20 23:59:05 +01:00
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
2012-03-14 18:51:51 +01: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 ;
2012-03-14 18:51:51 +01:00
if ( Item * pitem = p_caster -> GetItemByEntry ( item_id ))
2010-02-20 23:59:05 +01:00
{
2010-04-07 19:12:44 +02:00
for ( int x = 0 ; x < MAX_ITEM_PROTO_SPELLS ; ++ x )
2012-03-14 18:51:51 +01:00
if ( pProto -> Spells [ x ]. SpellCharges != 0 && pitem -> GetSpellCharges ( x ) == pProto -> Spells [ x ]. SpellCharges )
2010-02-20 23:59:05 +01:00
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
2011-12-22 00:38:01 +01:00
if ( 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 ;
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_SPELLS_AURAS , "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
2011-12-22 00:38:01 +01:00
if ( 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 );
2012-03-03 00:19:00 +01:00
// further actions done only for dest targets
if ( ! m_targets . HasDst ())
return ;
// cache last transport
WorldObject * transport = NULL ;
// update effect destinations (in case of moved transport dest target)
for ( uint8 effIndex = 0 ; effIndex < MAX_SPELL_EFFECTS ; ++ effIndex )
{
SpellDestination & dest = m_destTargets [ effIndex ];
if ( ! dest . _transportGUID )
continue ;
2012-03-07 00:05:34 +01:00
2012-03-03 00:19:00 +01:00
if ( ! transport || transport -> GetGUID () != dest . _transportGUID )
transport = ObjectAccessor :: GetWorldObject ( * m_caster , dest . _transportGUID );
if ( transport )
{
dest . _position . Relocate ( transport );
dest . _position . RelocateOffset ( dest . _transportOffset );
}
}
2010-02-20 23:59:05 +01:00
}
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-11-03 16:53:29 +07:00
// TODO: changed SPELL_INTERRUPT_FLAG_AUTOATTACK -> SPELL_INTERRUPT_FLAG_INTERRUPT to fix compile - is this check correct at all?
return ! IsTriggered () && ( m_spellInfo -> InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT );
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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SPELLS_AURAS , "~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
/*
2012-03-26 03:12:56 +02:00
if (m_Spell->m_spellInfo->IsChanneled())
2010-02-20 23:59:05 +01:00
{
// 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
2012-02-03 22:24:03 +01:00
if ( IsTriggered () && m_spellInfo -> SpellFamilyName == SPELLFAMILY_HUNTER && m_spellInfo -> IsTargetingArea ())
2011-08-25 00:32:46 +02:00
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
{
2012-02-03 22:24:03 +01:00
if ( m_spellInfo -> Effects [ i ]. IsTargetingArea ())
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)
2012-08-27 18:17:34 +02:00
// add the effect base points 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 )
2012-08-27 18:17:34 +02:00
skillValue += m_spellInfo -> Effects [ effIndex ]. CalcValue ();
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
}
}
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 :: 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 ()
{
2010-12-22 21:25:23 +01:00
sScriptMgr -> CreateSpellScripts ( m_spellInfo -> Id , m_loadedScripts );
2012-03-28 19:11:50 +08: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 ;
2012-09-04 17:03:04 +02:00
delete ( * bitr );
2010-07-24 22:41:42 +02:00
m_loadedScripts . erase ( bitr );
continue ;
}
2011-12-31 13:10:13 +01:00
sLog -> outDebug ( LOG_FILTER_SPELLS_AURAS , "Spell::LoadScripts: Script `%s` for spell `%u` is loaded now" , ( * itr ) -> _GetScriptName () -> c_str (), m_spellInfo -> Id );
2010-07-24 22:41:42 +02:00
( * itr ) -> Register ();
++ itr ;
}
}
2010-08-19 14:31:31 +02:00
2011-12-31 13:10:13 +01:00
void Spell :: CallScriptBeforeCastHandlers ()
2010-08-19 14:31:31 +02:00
{
2012-03-28 19:11:50 +08:00
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end (); ++ scritr )
2011-12-31 13:10:13 +01:00
{
( * scritr ) -> _PrepareScriptCall ( SPELL_SCRIPT_HOOK_BEFORE_CAST );
std :: list < SpellScript :: CastHandler >:: iterator hookItrEnd = ( * scritr ) -> BeforeCast . end (), hookItr = ( * scritr ) -> BeforeCast . begin ();
2012-03-28 19:11:50 +08:00
for (; hookItr != hookItrEnd ; ++ hookItr )
2011-12-31 13:10:13 +01:00
( * hookItr ). Call ( * scritr );
( * scritr ) -> _FinishScriptCall ();
}
}
void Spell :: CallScriptOnCastHandlers ()
{
2012-03-28 19:11:50 +08:00
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end (); ++ scritr )
2011-12-31 13:10:13 +01:00
{
( * scritr ) -> _PrepareScriptCall ( SPELL_SCRIPT_HOOK_ON_CAST );
std :: list < SpellScript :: CastHandler >:: iterator hookItrEnd = ( * scritr ) -> OnCast . end (), hookItr = ( * scritr ) -> OnCast . begin ();
2012-03-28 19:11:50 +08:00
for (; hookItr != hookItrEnd ; ++ hookItr )
2011-12-31 13:10:13 +01:00
( * hookItr ). Call ( * scritr );
( * scritr ) -> _FinishScriptCall ();
}
}
void Spell :: CallScriptAfterCastHandlers ()
{
2012-03-28 19:11:50 +08:00
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end (); ++ scritr )
2011-12-31 13:10:13 +01:00
{
( * scritr ) -> _PrepareScriptCall ( SPELL_SCRIPT_HOOK_AFTER_CAST );
std :: list < SpellScript :: CastHandler >:: iterator hookItrEnd = ( * scritr ) -> AfterCast . end (), hookItr = ( * scritr ) -> AfterCast . begin ();
2012-03-28 19:11:50 +08:00
for (; hookItr != hookItrEnd ; ++ hookItr )
2011-12-31 13:10:13 +01:00
( * hookItr ). Call ( * scritr );
( * scritr ) -> _FinishScriptCall ();
}
2010-08-19 14:31:31 +02:00
}
2010-08-21 20:18:54 +02:00
2011-03-04 21:18:38 +01:00
SpellCastResult Spell :: CallScriptCheckCastHandlers ()
{
SpellCastResult retVal = SPELL_CAST_OK ;
2012-03-28 19:11:50 +08: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-12-31 13:10:13 +01:00
void Spell :: PrepareScriptHitHandlers ()
{
2012-03-28 19:11:50 +08:00
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end (); ++ scritr )
2011-12-31 13:10:13 +01:00
( * scritr ) -> _InitHit ();
}
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 ;
2012-03-28 19:11:50 +08: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 );
2011-11-23 12:42:11 -05:00
return false ;
2011-09-25 13:29:17 +02:00
}
( * scritr ) -> _PrepareScriptCall ( hookType );
2012-03-28 19:11:50 +08: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 ()
{
2012-03-28 19:11:50 +08: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 ();
2012-03-28 19:11:50 +08: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 ()
{
2012-03-28 19:11:50 +08: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 ();
2012-03-28 19:11:50 +08: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 ()
{
2012-03-28 19:11:50 +08: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 ();
2012-03-28 19:11:50 +08: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
2012-06-29 21:53:35 +02:00
void Spell :: CallScriptObjectAreaTargetSelectHandlers ( std :: list < WorldObject *>& targets , SpellEffIndex effIndex )
2011-01-21 23:42:51 +01:00
{
2012-03-28 19:11:50 +08:00
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end (); ++ scritr )
2011-01-21 23:42:51 +01:00
{
2012-06-30 00:06:17 +02:00
( * scritr ) -> _PrepareScriptCall ( SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT );
2012-06-29 21:53:35 +02:00
std :: list < SpellScript :: ObjectAreaTargetSelectHandler >:: iterator hookItrEnd = ( * scritr ) -> OnObjectAreaTargetSelect . end (), hookItr = ( * scritr ) -> OnObjectAreaTargetSelect . begin ();
2012-03-28 19:11:50 +08:00
for (; hookItr != hookItrEnd ; ++ hookItr )
2011-01-21 23:42:51 +01:00
if (( * hookItr ). IsEffectAffected ( m_spellInfo , effIndex ))
2012-06-29 21:53:35 +02:00
( * hookItr ). Call ( * scritr , targets );
2011-01-21 23:42:51 +01:00
( * scritr ) -> _FinishScriptCall ();
}
}
2011-02-22 17:02:47 +06:00
2012-07-03 12:35:06 +02:00
void Spell :: CallScriptObjectTargetSelectHandlers ( WorldObject *& target , SpellEffIndex effIndex )
{
for ( std :: list < SpellScript *>:: iterator scritr = m_loadedScripts . begin (); scritr != m_loadedScripts . end (); ++ scritr )
{
( * scritr ) -> _PrepareScriptCall ( SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT );
std :: list < SpellScript :: ObjectTargetSelectHandler >:: iterator hookItrEnd = ( * scritr ) -> OnObjectTargetSelect . end (), hookItr = ( * scritr ) -> OnObjectTargetSelect . begin ();
for (; hookItr != hookItrEnd ; ++ hookItr )
if (( * hookItr ). IsEffectAffected ( m_spellInfo , effIndex ))
( * hookItr ). Call ( * scritr , target );
( * scritr ) -> _FinishScriptCall ();
}
}
2012-04-05 20:09:20 +02:00
bool Spell :: CanExecuteTriggersOnHit ( uint8 effMask , SpellInfo const * triggeredByAura ) const
2011-06-26 00:29:12 +02:00
{
2012-04-05 20:09:20 +02:00
bool only_on_caster = ( triggeredByAura && ( triggeredByAura -> AttributesEx4 & SPELL_ATTR4_PROC_ONLY_ON_CASTER ));
// If triggeredByAura has SPELL_ATTR4_PROC_ONLY_ON_CASTER then it can only proc on a casted spell with TARGET_UNIT_CASTER
2011-10-19 22:08:54 +02:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2011-06-26 00:29:12 +02:00
{
2012-04-05 20:09:20 +02:00
if (( effMask & ( 1 << i )) && ( ! only_on_caster || ( m_spellInfo -> Effects [ i ]. TargetA . GetTarget () == TARGET_UNIT_CASTER )))
2011-10-19 22:08:54 +02:00
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_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 ();
// proc chance is stored in effect amount
2012-04-05 20:09:20 +02:00
int32 chance = m_caster -> CalculateSpellDamage ( NULL , auraSpellInfo , auraSpellIdx , & auraBaseAmount );
// build trigger and add to the list
HitTriggerSpell spellTriggerInfo ;
spellTriggerInfo . triggeredSpell = spellInfo ;
spellTriggerInfo . triggeredByAura = auraSpellInfo ;
spellTriggerInfo . chance = chance * ( * i ) -> GetBase () -> GetStackAmount ();
m_hitTriggerSpells . push_back ( spellTriggerInfo );
2011-06-26 00:29:12 +02:00
}
}
}
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 ;
2012-08-31 01:26:21 +01:00
if ( m_caster -> GetTypeId () == TYPEID_PLAYER )
if ( m_caster -> ToPlayer () -> GetCommandStatus ( CHEAT_COOLDOWN ))
return ;
2011-02-22 17:02:47 +06:00
// 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 );
}
2012-02-21 20:03:27 +01:00
namespace Trinity
{
WorldObjectSpellTargetCheck :: WorldObjectSpellTargetCheck ( Unit * caster , Unit * referer , SpellInfo const * spellInfo ,
2012-02-23 13:01:16 +01:00
SpellTargetCheckTypes selectionType , ConditionList * condList ) : _caster ( caster ), _referer ( referer ), _spellInfo ( spellInfo ),
2012-02-22 09:15:57 +01:00
_targetSelectionType ( selectionType ), _condList ( condList )
2012-02-21 20:03:27 +01:00
{
if ( condList )
_condSrcInfo = new ConditionSourceInfo ( NULL , caster );
else
_condSrcInfo = NULL ;
}
WorldObjectSpellTargetCheck ::~ WorldObjectSpellTargetCheck ()
{
if ( _condSrcInfo )
delete _condSrcInfo ;
}
bool WorldObjectSpellTargetCheck :: operator ()( WorldObject * target )
{
if ( _spellInfo -> CheckTarget ( _caster , target , true ) != SPELL_CAST_OK )
return false ;
Unit * unitTarget = target -> ToUnit ();
if ( Corpse * corpseTarget = target -> ToCorpse ())
{
// use ofter for party/assistance checks
if ( Player * owner = ObjectAccessor :: FindPlayer ( corpseTarget -> GetOwnerGUID ()))
unitTarget = owner ;
else
return false ;
}
if ( unitTarget )
{
switch ( _targetSelectionType )
{
case TARGET_CHECK_ENEMY :
if ( unitTarget -> isTotem ())
return false ;
if ( ! _caster -> _IsValidAttackTarget ( unitTarget , _spellInfo ))
return false ;
break ;
case TARGET_CHECK_ALLY :
if ( unitTarget -> isTotem ())
return false ;
if ( ! _caster -> _IsValidAssistTarget ( unitTarget , _spellInfo ))
return false ;
break ;
case TARGET_CHECK_PARTY :
if ( unitTarget -> isTotem ())
return false ;
if ( ! _caster -> _IsValidAssistTarget ( unitTarget , _spellInfo ))
return false ;
if ( ! _referer -> IsInPartyWith ( unitTarget ))
return false ;
break ;
case TARGET_CHECK_RAID_CLASS :
if ( _referer -> getClass () != unitTarget -> getClass ())
return false ;
// nobreak;
case TARGET_CHECK_RAID :
if ( unitTarget -> isTotem ())
return false ;
if ( ! _caster -> _IsValidAssistTarget ( unitTarget , _spellInfo ))
return false ;
if ( ! _referer -> IsInRaidWith ( unitTarget ))
return false ;
break ;
default :
break ;
}
}
if ( ! _condSrcInfo )
return true ;
_condSrcInfo -> mConditionTargets [ 0 ] = target ;
return sConditionMgr -> IsObjectMeetToConditions ( * _condSrcInfo , * _condList );
}
2012-02-23 13:01:16 +01:00
WorldObjectSpellNearbyTargetCheck :: WorldObjectSpellNearbyTargetCheck ( float range , Unit * caster , SpellInfo const * spellInfo ,
2012-02-21 20:03:27 +01:00
SpellTargetCheckTypes selectionType , ConditionList * condList )
: WorldObjectSpellTargetCheck ( caster , caster , spellInfo , selectionType , condList ), _range ( range ), _position ( caster )
{
}
bool WorldObjectSpellNearbyTargetCheck :: operator ()( WorldObject * target )
{
float dist = target -> GetDistance ( * _position );
if ( dist < _range && WorldObjectSpellTargetCheck :: operator ()( target ))
{
_range = dist ;
return true ;
}
return false ;
}
WorldObjectSpellAreaTargetCheck :: WorldObjectSpellAreaTargetCheck ( float range , Position const * position , Unit * caster ,
Unit * referer , SpellInfo const * spellInfo , SpellTargetCheckTypes selectionType , ConditionList * condList )
: WorldObjectSpellTargetCheck ( caster , referer , spellInfo , selectionType , condList ), _range ( range ), _position ( position )
{
}
bool WorldObjectSpellAreaTargetCheck :: operator ()( WorldObject * target )
{
if ( ! target -> IsWithinDist3d ( _position , _range ))
return false ;
return WorldObjectSpellTargetCheck :: operator ()( target );
}
WorldObjectSpellConeTargetCheck :: WorldObjectSpellConeTargetCheck ( float coneAngle , float range , Unit * caster ,
SpellInfo const * spellInfo , SpellTargetCheckTypes selectionType , ConditionList * condList )
: WorldObjectSpellAreaTargetCheck ( range , caster , caster , caster , spellInfo , selectionType , condList ), _coneAngle ( coneAngle )
{
}
bool WorldObjectSpellConeTargetCheck :: operator ()( WorldObject * target )
{
if ( _spellInfo -> AttributesCu & SPELL_ATTR0_CU_CONE_BACK )
{
if ( ! _caster -> isInBack ( target , _coneAngle ))
return false ;
}
else if ( _spellInfo -> AttributesCu & SPELL_ATTR0_CU_CONE_LINE )
{
if ( ! _caster -> HasInLine ( target , _caster -> GetObjectSize ()))
return false ;
}
else
{
if ( ! _caster -> isInFront ( target , _coneAngle ))
return false ;
}
return WorldObjectSpellAreaTargetCheck :: operator ()( target );
}
WorldObjectSpellTrajTargetCheck :: WorldObjectSpellTrajTargetCheck ( float range , Position const * position , Unit * caster , SpellInfo const * spellInfo )
: WorldObjectSpellAreaTargetCheck ( range , position , caster , caster , spellInfo , TARGET_CHECK_DEFAULT , NULL )
{
}
bool WorldObjectSpellTrajTargetCheck :: operator ()( WorldObject * target )
{
// return all targets on missile trajectory (0 - size of a missile)
if ( ! _caster -> HasInLine ( target , 0 ))
return false ;
return WorldObjectSpellAreaTargetCheck :: operator ()( target );
}
} //namespace Trinity