2010-10-07 15:35:36 +02:00
/*
2015-01-01 00:27:46 +01:00
* Copyright (C) 2008-2015 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/>.
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#include "Common.h"
2009-03-27 09:58:20 -06:00
#include "DBCStores.h"
2008-10-02 16:23:55 -05:00
#include "WorldPacket.h"
#include "WorldSession.h"
#include "ObjectMgr.h"
2012-01-18 18:13:57 +01:00
#include "GuildMgr.h"
2008-10-02 16:23:55 -05:00
#include "SpellMgr.h"
#include "Log.h"
#include "Opcodes.h"
#include "Spell.h"
#include "Totem.h"
2008-11-17 18:57:16 -05:00
#include "TemporarySummon.h"
2009-03-08 13:05:56 -06:00
#include "SpellAuras.h"
2009-08-23 01:08:09 -05:00
#include "CreatureAI.h"
2010-01-19 11:36:05 +01:00
#include "ScriptMgr.h"
2010-10-27 21:01:47 +02:00
#include "GameObjectAI.h"
2011-07-31 16:43:54 +02:00
#include "SpellAuraEffects.h"
2012-11-17 05:18:37 +01:00
#include "Player.h"
2014-03-02 18:09:02 -05:00
#include "Config.h"
2014-11-14 02:00:34 +01:00
#include "SpellPackets.h"
2014-12-28 16:01:53 +00:00
#include "GameObjectPackets.h"
2009-10-17 15:51:44 -07:00
2011-06-23 13:28:52 +02:00
void WorldSession :: HandleClientCastFlags ( WorldPacket & recvPacket , uint8 castFlags , SpellCastTargets & targets )
2010-08-08 20:32:14 +02:00
{
// some spell cast packet including more data (for projectiles?)
if ( castFlags & 0x02 )
{
// not sure about these two
2011-06-23 13:28:52 +02:00
float elevation , speed ;
recvPacket >> elevation ;
recvPacket >> speed ;
targets . SetElevation ( elevation );
targets . SetSpeed ( speed );
2010-08-08 20:32:14 +02:00
uint8 hasMovementData ;
recvPacket >> hasMovementData ;
2014-11-14 22:54:12 +00:00
//if (hasMovementData)
// HandleMovementOpcodes(recvPacket);
2010-08-08 20:32:14 +02:00
}
2012-07-17 21:36:40 +02:00
else if ( castFlags & 0x8 ) // Archaeology
{
uint32 count , entry , usedCount ;
uint8 type ;
recvPacket >> count ;
for ( uint32 i = 0 ; i < count ; ++ i )
{
recvPacket >> type ;
switch ( type )
{
case 2 : // Keystones
recvPacket >> entry ; // Item id
recvPacket >> usedCount ; // Item count
break ;
case 1 : // Fragments
recvPacket >> entry ; // Currency id
recvPacket >> usedCount ; // Currency count
break ;
}
}
}
2010-08-08 20:32:14 +02:00
}
2008-10-02 16:23:55 -05:00
void WorldSession :: HandleUseItemOpcode ( WorldPacket & recvPacket )
{
2013-03-08 21:41:30 +01:00
/// @todo add targets.read() check
2008-10-02 16:23:55 -05:00
Player * pUser = _player ;
2009-10-17 15:51:44 -07:00
2009-04-03 16:42:19 -06:00
// ignore for remote control state
2010-03-23 14:38:31 -05:00
if ( pUser -> m_mover != pUser )
2009-04-03 16:42:19 -06:00
return ;
2009-10-17 15:51:44 -07:00
2010-08-08 20:32:14 +02:00
uint8 bagIndex , slot , castFlags ;
2013-12-25 14:16:55 -03:30
uint8 castCount ; // next cast if exists (single or not)
2014-09-14 16:14:12 +02:00
ObjectGuid itemGUID ;
2008-12-24 09:58:26 -06:00
uint32 glyphIndex ; // something to do with glyphs?
2013-12-25 14:16:55 -03:30
uint32 spellId ; // cast spell id
2009-10-17 15:51:44 -07:00
2010-08-08 20:32:14 +02:00
recvPacket >> bagIndex >> slot >> castCount >> spellId >> itemGUID >> glyphIndex >> castFlags ;
2009-10-17 15:51:44 -07:00
2010-03-23 14:38:31 -05:00
if ( glyphIndex >= MAX_GLYPH_SLOT_INDEX )
{
pUser -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , NULL , NULL );
return ;
}
2011-09-15 14:08:17 +02:00
Item * pItem = pUser -> GetUseableItemByPos ( bagIndex , slot );
2010-03-23 14:38:31 -05:00
if ( ! pItem )
2008-10-02 16:23:55 -05:00
{
2010-03-23 14:38:31 -05:00
pUser -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , NULL , NULL );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-08-08 20:32:14 +02:00
if ( pItem -> GetGUID () != itemGUID )
2008-11-20 16:16:57 -06:00
{
2010-03-23 14:38:31 -05:00
pUser -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , NULL , NULL );
2008-11-20 16:16:57 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, castCount: %u, spellId: %u, Item: %u, glyphIndex: %u, data length = %i" , bagIndex , slot , castCount , spellId , pItem -> GetEntry (), glyphIndex , ( uint32 ) recvPacket . size ());
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
ItemTemplate const * proto = pItem -> GetTemplate ();
2010-03-23 14:38:31 -05:00
if ( ! proto )
2008-10-02 16:23:55 -05:00
{
2010-03-23 14:38:31 -05:00
pUser -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , pItem , NULL );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// some item classes can be used only in equipped state
2014-12-21 13:35:43 +01:00
if ( proto -> GetInventoryType () != INVTYPE_NON_EQUIP && ! pItem -> IsEquipped ())
2008-10-02 16:23:55 -05:00
{
2010-03-23 14:38:31 -05:00
pUser -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , pItem , NULL );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-04-29 16:48:15 +06:00
InventoryResult msg = pUser -> CanUseItem ( pItem );
2010-03-23 14:38:31 -05:00
if ( msg != EQUIP_ERR_OK )
2008-10-02 16:23:55 -05:00
{
2010-03-23 14:38:31 -05:00
pUser -> SendEquipError ( msg , pItem , NULL );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB)
2014-12-21 13:35:43 +01:00
if ( proto -> GetClass () == ITEM_CLASS_CONSUMABLE && ! ( proto -> GetFlags () & ITEM_PROTO_FLAG_USEABLE_IN_ARENA ) && pUser -> InArena ())
2008-10-02 16:23:55 -05:00
{
2010-08-04 10:34:30 +02:00
pUser -> SendEquipError ( EQUIP_ERR_NOT_DURING_ARENA_MATCH , pItem , NULL );
return ;
}
// don't allow items banned in arena
2014-12-21 13:35:43 +01:00
if ( proto -> GetFlags () & ITEM_PROTO_FLAG_NOT_USEABLE_IN_ARENA && pUser -> InArena ())
2010-08-04 10:34:30 +02:00
{
pUser -> SendEquipError ( EQUIP_ERR_NOT_DURING_ARENA_MATCH , pItem , NULL );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2013-06-11 19:54:27 -02:30
if ( pUser -> IsInCombat ())
2008-10-02 16:23:55 -05:00
{
2014-12-01 17:20:41 +01:00
for ( uint32 i = 0 ; i < proto -> Effects . size (); ++ i )
2008-10-02 16:23:55 -05:00
{
2014-11-14 14:47:20 +02:00
if ( SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( proto -> Effects [ i ]. SpellID ))
2008-10-02 16:23:55 -05:00
{
2011-07-28 13:21:31 +02:00
if ( ! spellInfo -> CanBeUsedInCombat ())
2008-10-02 16:23:55 -05:00
{
2011-04-29 20:47:02 +02:00
pUser -> SendEquipError ( EQUIP_ERR_NOT_IN_COMBAT , pItem , NULL );
2008-10-02 16:23:55 -05:00
return ;
}
}
}
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory)
2014-12-21 13:35:43 +01:00
if ( pItem -> GetTemplate () -> GetBonding () == BIND_WHEN_USE || pItem -> GetTemplate () -> GetBonding () == BIND_WHEN_PICKED_UP || pItem -> GetTemplate () -> GetBonding () == BIND_QUEST_ITEM )
2008-10-02 16:23:55 -05:00
{
if ( ! pItem -> IsSoulBound ())
{
pItem -> SetState ( ITEM_CHANGED , pUser );
2010-04-07 22:59:46 +02:00
pItem -> SetBinding ( true );
2008-10-02 16:23:55 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
SpellCastTargets targets ;
2011-06-23 13:28:52 +02:00
targets . Read ( recvPacket , pUser );
2010-08-08 20:32:14 +02:00
HandleClientCastFlags ( recvPacket , castFlags , targets );
2009-10-17 15:51:44 -07:00
2010-08-08 20:32:14 +02:00
// Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state.
2011-04-29 20:47:02 +02:00
if ( ! sScriptMgr -> OnItemUse ( pUser , pItem , targets ))
2008-10-02 16:23:55 -05:00
{
// no script or script not process request by self
2011-04-29 20:47:02 +02:00
pUser -> CastItemUseSpell ( pItem , targets , castCount , glyphIndex );
2008-10-02 16:23:55 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
void WorldSession :: HandleOpenItemOpcode ( WorldPacket & recvPacket )
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: CMSG_OPEN_ITEM packet, data length = %i" , ( uint32 ) recvPacket . size ());
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Player * pUser = _player ;
2009-10-17 15:51:44 -07:00
2009-04-03 16:42:19 -06:00
// ignore for remote control state
2010-03-23 14:38:31 -05:00
if ( pUser -> m_mover != pUser )
2009-04-03 16:42:19 -06:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint8 bagIndex , slot ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
recvPacket >> bagIndex >> slot ;
2009-10-17 15:51:44 -07:00
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "network" , "bagIndex: %u, slot: %u" , bagIndex , slot );
2009-10-17 15:51:44 -07:00
2011-12-25 18:12:58 +01:00
Item * item = pUser -> GetItemByPos ( bagIndex , slot );
if ( ! item )
2008-10-02 16:23:55 -05:00
{
2010-04-07 22:59:46 +02:00
pUser -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , NULL , NULL );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-12-25 18:12:58 +01:00
ItemTemplate const * proto = item -> GetTemplate ();
2010-04-07 19:14:10 +02:00
if ( ! proto )
2008-10-02 16:23:55 -05:00
{
2011-12-25 18:12:58 +01:00
pUser -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , item , NULL );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-11-14 16:26:09 +01:00
// Verify that the bag is an actual bag or wrapped item that can be used "normally"
2014-12-21 13:35:43 +01:00
if ( ! ( proto -> GetFlags () & ITEM_PROTO_FLAG_OPENABLE ) && ! item -> HasFlag ( ITEM_FIELD_FLAGS , ITEM_FLAG_WRAPPED ))
2010-11-07 20:08:52 +01:00
{
2012-08-20 15:54:55 +02:00
pUser -> SendEquipError ( EQUIP_ERR_CLIENT_LOCKED_OUT , item , NULL );
2014-10-22 21:22:04 +02:00
TC_LOG_ERROR ( "network" , "Possible hacking attempt: Player %s [%s] tried to open item [%s, entry: %u] which is not openable!" ,
2014-12-21 13:35:43 +01:00
pUser -> GetName (). c_str (), pUser -> GetGUID (). ToString (). c_str (), item -> GetGUID (). ToString (). c_str (), proto -> GetId ());
2010-11-07 20:08:52 +01:00
return ;
}
2008-10-02 16:23:55 -05:00
// locked item
2014-12-21 13:35:43 +01:00
uint32 lockId = proto -> GetLockID ();
2010-03-23 14:38:31 -05:00
if ( lockId )
2008-10-02 16:23:55 -05:00
{
2011-09-15 14:08:17 +02:00
LockEntry const * lockInfo = sLockStore . LookupEntry ( lockId );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( ! lockInfo )
{
2011-12-25 18:12:58 +01:00
pUser -> SendEquipError ( EQUIP_ERR_ITEM_LOCKED , item , NULL );
2014-10-22 21:22:04 +02:00
TC_LOG_ERROR ( "network" , "WORLD::OpenItem: item [%s] has an unknown lockId: %u!" , item -> GetGUID (). ToString (). c_str (), lockId );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-08-04 10:34:30 +02:00
// was not unlocked yet
2011-12-25 18:12:58 +01:00
if ( item -> IsLocked ())
2008-10-02 16:23:55 -05:00
{
2011-12-25 18:12:58 +01:00
pUser -> SendEquipError ( EQUIP_ERR_ITEM_LOCKED , item , NULL );
2008-10-02 16:23:55 -05:00
return ;
}
}
2009-10-17 15:51:44 -07:00
2011-12-25 18:12:58 +01:00
if ( item -> HasFlag ( ITEM_FIELD_FLAGS , ITEM_FLAG_WRAPPED )) // wrapped?
2008-10-02 16:23:55 -05:00
{
2012-05-30 08:01:02 +02:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_GIFT_BY_ITEM );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , item -> GetGUID (). GetCounter ());
2012-05-30 08:01:02 +02:00
PreparedQueryResult result = CharacterDatabase . Query ( stmt );
2008-10-02 16:23:55 -05:00
if ( result )
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2008-10-02 16:23:55 -05:00
uint32 entry = fields [ 0 ]. GetUInt32 ();
uint32 flags = fields [ 1 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2014-09-14 16:14:12 +02:00
item -> SetGuidValue ( ITEM_FIELD_GIFTCREATOR , ObjectGuid :: Empty );
2011-12-25 18:12:58 +01:00
item -> SetEntry ( entry );
item -> SetUInt32Value ( ITEM_FIELD_FLAGS , flags );
item -> SetState ( ITEM_CHANGED , pUser );
2008-10-02 16:23:55 -05:00
}
else
{
2014-10-22 21:22:04 +02:00
TC_LOG_ERROR ( "network" , "Wrapped item %s don't have record in character_gifts table and will deleted" , item -> GetGUID (). ToString (). c_str ());
2011-12-25 18:12:58 +01:00
pUser -> DestroyItem ( item -> GetBagSlot (), item -> GetSlot (), true );
2008-10-02 16:23:55 -05:00
return ;
}
2011-12-25 18:12:58 +01:00
2012-05-30 08:01:02 +02:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_GIFT );
2011-12-25 18:12:58 +01:00
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , item -> GetGUID (). GetCounter ());
2011-12-25 18:12:58 +01:00
CharacterDatabase . Execute ( stmt );
2008-10-02 16:23:55 -05:00
}
else
2011-12-25 18:12:58 +01:00
pUser -> SendLoot ( item -> GetGUID (), LOOT_CORPSE );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2014-12-28 16:01:53 +00:00
void WorldSession :: HandleGameObjectUseOpcode ( WorldPackets :: GameObject :: GameObjectUse & packet )
2008-10-02 16:23:55 -05:00
{
2014-12-28 16:01:53 +00:00
if ( GameObject * obj = GetPlayer () -> GetMap () -> GetGameObject ( packet . Guid ))
2013-03-09 05:20:42 +02:00
{
2014-01-25 16:59:01 +01:00
if ( ! obj -> IsWithinDistInMap ( GetPlayer (), obj -> GetInteractionDistance ()))
return ;
2013-03-09 05:20:42 +02:00
// ignore for remote control state
2014-01-25 16:59:01 +01:00
if ( GetPlayer () -> m_mover != GetPlayer ())
if ( ! ( GetPlayer () -> IsOnVehicle ( GetPlayer () -> m_mover ) || GetPlayer () -> IsMounted ()) && ! obj -> GetGOInfo () -> IsUsableMounted ())
2013-03-09 05:20:42 +02:00
return ;
2014-01-25 16:59:01 +01:00
obj -> Use ( GetPlayer ());
2013-03-09 05:20:42 +02:00
}
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2014-12-28 16:01:53 +00:00
void WorldSession :: HandleGameobjectReportUse ( WorldPackets :: GameObject :: GameObjectReportUse & packet )
2008-12-27 11:39:40 -06:00
{
2009-04-03 16:42:19 -06:00
// ignore for remote control state
2010-03-23 14:38:31 -05:00
if ( _player -> m_mover != _player )
2009-04-03 16:42:19 -06:00
return ;
2009-10-17 15:51:44 -07:00
2014-12-28 16:01:53 +00:00
GameObject * go = GetPlayer () -> GetMap () -> GetGameObject ( packet . Guid );
2010-03-23 14:38:31 -05:00
if ( ! go )
2009-04-03 16:37:06 -06:00
return ;
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
if ( ! go -> IsWithinDistInMap ( _player , INTERACTION_DISTANCE ))
2009-04-03 16:37:06 -06:00
return ;
2009-10-17 15:51:44 -07:00
2012-09-22 21:28:37 +02:00
if ( go -> AI () -> GossipHello ( _player ))
return ;
2010-11-20 13:54:45 +01:00
2012-07-09 11:08:33 +02:00
_player -> UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT , go -> GetEntry ());
2008-12-27 11:39:40 -06:00
}
2009-10-17 15:51:44 -07:00
2015-01-30 23:58:16 +01:00
void WorldSession :: HandleCastSpellOpcode ( WorldPackets :: Spells :: CastSpell & cast )
2008-10-02 16:23:55 -05:00
{
2009-04-03 16:42:19 -06:00
// ignore for remote control state (for player case)
Unit * mover = _player -> m_mover ;
2010-03-23 14:38:31 -05:00
if ( mover != _player && mover -> GetTypeId () == TYPEID_PLAYER )
2009-04-03 16:42:19 -06:00
return ;
2009-10-17 15:51:44 -07:00
2015-01-30 23:58:16 +01:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( cast . Cast . SpellID );
2010-03-23 14:38:31 -05:00
if ( ! spellInfo )
2008-10-02 16:23:55 -05:00
{
2015-01-30 23:58:16 +01:00
TC_LOG_ERROR ( "network" , "WORLD: unknown spell id %u" , cast . Cast . SpellID );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2013-02-27 13:17:20 +01:00
if ( spellInfo -> IsPassive ())
return ;
Unit * caster = mover ;
2015-01-30 23:58:16 +01:00
if ( caster -> GetTypeId () == TYPEID_UNIT && ! caster -> ToCreature () -> HasSpell ( spellInfo -> Id ))
2009-04-03 16:42:19 -06:00
{
2013-02-27 13:17:20 +01:00
// If the vehicle creature does not have the spell but it allows the passenger to cast own spells
// change caster to player and let him cast
if ( ! _player -> IsOnVehicle ( caster ) || spellInfo -> CheckVehicle ( _player ) != SPELL_CAST_OK )
2009-04-03 16:42:19 -06:00
return ;
2013-02-27 13:17:20 +01:00
caster = _player ;
}
2015-01-30 23:58:16 +01:00
// check known spell
if ( caster -> GetTypeId () == TYPEID_PLAYER && ! caster -> ToPlayer () -> HasActiveSpell ( spellInfo -> Id ))
2013-02-27 13:17:20 +01:00
return ;
2012-08-13 14:56:56 +02:00
2015-01-30 23:58:16 +01:00
// Check possible spell cast overrides
spellInfo = caster -> GetCastSpellInfo ( spellInfo );
2012-08-13 14:56:56 +02:00
2013-12-25 14:16:55 -03:30
// Client is resending autoshot cast opcode when other spell is cast during shoot rotation
2009-06-09 19:33:38 +02:00
// Skip it to prevent "interrupt" message
2013-02-27 13:17:20 +01:00
if ( spellInfo -> IsAutoRepeatRangedSpell () && caster -> GetCurrentSpell ( CURRENT_AUTOREPEAT_SPELL )
&& caster -> GetCurrentSpell ( CURRENT_AUTOREPEAT_SPELL ) -> m_spellInfo == spellInfo )
2009-06-09 19:33:38 +02:00
return ;
2009-10-17 15:51:44 -07:00
2008-11-05 20:51:05 -06:00
// can't use our own spells when we're in possession of another unit,
2010-03-23 14:38:31 -05:00
if ( _player -> isPossessing ())
2008-11-05 20:51:05 -06:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// client provided targets
2015-01-30 23:58:16 +01:00
SpellCastTargets targets ( caster , cast . Cast . Target );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// auto-selection buff level base at target level (in spellInfo)
2011-06-23 13:28:52 +02:00
if ( targets . GetUnitTarget ())
2008-10-02 16:23:55 -05:00
{
2011-09-15 14:08:17 +02:00
SpellInfo const * actualSpellInfo = spellInfo -> GetAuraRankForLevel ( targets . GetUnitTarget () -> getLevel ());
2009-10-17 15:51:44 -07:00
2013-12-25 14:16:55 -03:30
// if rank not found then function return NULL but in explicit cast case original spell can be cast and later failed with appropriate error message
2010-03-23 14:38:31 -05:00
if ( actualSpellInfo )
2008-10-02 16:23:55 -05:00
spellInfo = actualSpellInfo ;
}
2009-10-17 15:51:44 -07:00
2014-09-14 16:14:12 +02:00
Spell * spell = new Spell ( caster , spellInfo , TRIGGERED_NONE , ObjectGuid :: Empty , false );
2015-01-30 23:58:16 +01:00
spell -> m_cast_count = cast . Cast . CastID ; // set count of casts
spell -> m_misc . Data = cast . Cast . Misc ; // 6.x Misc is just a guess
2008-10-02 16:23:55 -05:00
spell -> prepare ( & targets );
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
void WorldSession :: HandleCancelCastOpcode ( WorldPacket & recvPacket )
{
uint32 spellId ;
2009-10-17 15:51:44 -07:00
2009-08-19 16:54:52 -05:00
recvPacket . read_skip < uint8 > (); // counter, increments with every CANCEL packet, don't use for now
2008-10-02 16:23:55 -05:00
recvPacket >> spellId ;
2009-10-17 15:51:44 -07:00
2013-12-25 14:16:55 -03:30
if ( _player -> IsNonMeleeSpellCast ( false ))
2011-04-29 20:47:02 +02:00
_player -> InterruptNonMeleeSpells ( false , spellId , false );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2015-01-26 12:59:18 +01:00
void WorldSession :: HandleCancelAuraOpcode ( WorldPackets :: Spells :: CancelAura & cancelAura )
2008-10-02 16:23:55 -05:00
{
2015-01-26 12:59:18 +01:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( cancelAura . SpellID );
2008-10-02 16:23:55 -05:00
if ( ! spellInfo )
return ;
2009-10-17 15:51:44 -07:00
2011-09-03 17:06:20 +02:00
// not allow remove spells with attr SPELL_ATTR0_CANT_CANCEL
2015-01-05 23:49:43 +02:00
if ( spellInfo -> HasAttribute ( SPELL_ATTR0_CANT_CANCEL ))
2010-07-21 14:48:44 +02:00
return ;
2013-12-25 14:16:55 -03:30
// channeled spell case (it currently cast then)
2011-07-26 23:09:28 +02:00
if ( spellInfo -> IsChanneled ())
2008-11-05 20:51:05 -06:00
{
2009-08-19 16:52:51 -05:00
if ( Spell * curSpell = _player -> GetCurrentSpell ( CURRENT_CHANNELED_SPELL ))
2015-01-26 12:59:18 +01:00
if ( curSpell -> GetSpellInfo () -> Id == cancelAura . SpellID )
2009-08-19 16:52:51 -05:00
_player -> InterruptSpell ( CURRENT_CHANNELED_SPELL );
2008-10-02 16:23:55 -05:00
return ;
2008-11-21 21:00:45 -05:00
}
2009-10-17 15:51:44 -07:00
2011-09-03 17:06:20 +02:00
// non channeled case:
// don't allow remove non positive spells
// don't allow cancelling passive auras (some of them are visible)
if ( ! spellInfo -> IsPositive () || spellInfo -> IsPassive ())
return ;
2015-01-26 12:59:18 +01:00
_player -> RemoveOwnedAura ( cancelAura . SpellID , cancelAura . CasterGUID , 0 , AURA_REMOVE_BY_CANCEL );
2014-03-02 18:09:02 -05:00
// If spell being removed is a resource tracker, see if player was tracking both (herbs / minerals) and remove the other
2014-11-24 18:57:49 +01:00
if ( sWorld -> getBoolConfig ( CONFIG_ALLOW_TRACK_BOTH_RESOURCES ) && spellInfo -> HasAura ( DIFFICULTY_NONE , SPELL_AURA_TRACK_RESOURCES ))
2014-03-02 18:09:02 -05:00
{
Unit :: AuraEffectList const & auraEffects = _player -> GetAuraEffectsByType ( SPELL_AURA_TRACK_RESOURCES );
if ( ! auraEffects . empty ())
{
// Build list of spell IDs to cancel. Trying to cancel the aura while iterating
// over AuraEffectList caused "incompatible iterator" errors on second pass
std :: list < uint32 > spellIDs ;
2014-09-19 03:30:02 +01:00
for ( Unit :: AuraEffectList :: const_iterator auraEffect = auraEffects . begin (); auraEffect != auraEffects . end (); ++ auraEffect )
2014-03-02 18:09:02 -05:00
spellIDs . push_back (( * auraEffect ) -> GetId ());
// Remove all auras related to resource tracking (only Herbs and Minerals in 3.3.5a)
2014-09-19 03:30:02 +01:00
for ( std :: list < uint32 >:: iterator it = spellIDs . begin (); it != spellIDs . end (); ++ it )
2015-01-26 12:59:18 +01:00
_player -> RemoveOwnedAura ( * it , cancelAura . CasterGUID , 0 , AURA_REMOVE_BY_CANCEL );
2014-03-02 18:09:02 -05:00
}
}
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandlePetCancelAuraOpcode ( WorldPacket & recvPacket )
2008-10-02 16:23:55 -05:00
{
2014-09-14 16:14:12 +02:00
ObjectGuid guid ;
2008-10-02 16:23:55 -05:00
uint32 spellId ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
recvPacket >> guid ;
recvPacket >> spellId ;
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( spellId );
2010-03-23 14:38:31 -05:00
if ( ! spellInfo )
2008-10-02 16:23:55 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network" , "WORLD: unknown PET spell id %u" , spellId );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
Creature * pet = ObjectAccessor :: GetCreatureOrPetOrVehicle ( * _player , guid );
2009-10-17 15:51:44 -07:00
2010-03-23 14:38:31 -05:00
if ( ! pet )
2008-10-02 16:23:55 -05:00
{
2014-09-14 16:14:12 +02:00
TC_LOG_ERROR ( "network" , "HandlePetCancelAura: Attempt to cancel an aura for non-existant %s by player '%s'" , guid . ToString (). c_str (), GetPlayer () -> GetName (). c_str ());
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-03-23 14:38:31 -05:00
if ( pet != GetPlayer () -> GetGuardianPet () && pet != GetPlayer () -> GetCharm ())
2008-10-02 16:23:55 -05:00
{
2014-09-14 16:14:12 +02:00
TC_LOG_ERROR ( "network" , "HandlePetCancelAura: %s is not a pet of player '%s'" , guid . ToString (). c_str (), GetPlayer () -> GetName (). c_str ());
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2013-06-11 19:54:27 -02:30
if ( ! pet -> IsAlive ())
2008-10-02 16:23:55 -05:00
{
pet -> SendPetActionFeedback ( FEEDBACK_PET_DEAD );
return ;
}
2009-10-17 15:51:44 -07:00
2014-09-14 16:14:12 +02:00
pet -> RemoveOwnedAura ( spellId , ObjectGuid :: Empty , 0 , AURA_REMOVE_BY_CANCEL );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
pet -> AddCreatureSpellCooldown ( spellId );
}
2009-10-17 15:51:44 -07:00
2013-10-28 14:36:07 -04:00
void WorldSession :: HandleCancelGrowthAuraOpcode ( WorldPacket & /*recvPacket*/ ) { }
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleCancelAutoRepeatSpellOpcode ( WorldPacket & /*recvPacket*/ )
2008-10-02 16:23:55 -05:00
{
// may be better send SMSG_CANCEL_AUTO_REPEAT?
// cancel and prepare for deleting
2009-04-28 00:06:48 -05:00
_player -> InterruptSpell ( CURRENT_AUTOREPEAT_SPELL );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2012-09-09 14:57:37 -05:00
void WorldSession :: HandleCancelChanneling ( WorldPacket & recvData )
2008-10-02 16:23:55 -05:00
{
2012-08-05 19:40:30 -05:00
recvData . read_skip < uint32 > (); // spellid, not used
2009-10-17 15:51:44 -07:00
2009-08-19 16:55:35 -05:00
// ignore for remote control state (for player case)
Unit * mover = _player -> m_mover ;
2010-03-23 14:38:31 -05:00
if ( mover != _player && mover -> GetTypeId () == TYPEID_PLAYER )
2009-08-19 16:55:35 -05:00
return ;
2009-10-17 15:51:44 -07:00
2009-08-19 16:55:35 -05:00
mover -> InterruptSpell ( CURRENT_CHANNELED_SPELL );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleTotemDestroyed ( WorldPacket & recvPacket )
2008-10-02 16:23:55 -05:00
{
2009-04-03 16:42:19 -06:00
// ignore for remote control state
2010-03-23 14:38:31 -05:00
if ( _player -> m_mover != _player )
2009-04-03 16:42:19 -06:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint8 slotId ;
2014-10-21 19:23:32 +02:00
ObjectGuid guid ;
2008-10-02 16:23:55 -05:00
recvPacket >> slotId ;
2012-11-02 00:17:59 +01:00
recvPacket >> guid ;
2009-10-17 15:51:44 -07:00
2009-03-27 22:47:28 -06:00
++ slotId ;
if ( slotId >= MAX_TOTEM_SLOT )
2008-10-02 16:23:55 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-03-23 14:38:31 -05:00
if ( ! _player -> m_SummonSlot [ slotId ])
2008-10-02 16:23:55 -05:00
return ;
2009-10-17 15:51:44 -07:00
2009-04-20 20:28:19 -05:00
Creature * totem = GetPlayer () -> GetMap () -> GetCreature ( _player -> m_SummonSlot [ slotId ]);
2013-06-13 19:35:01 +02:00
if ( totem && totem -> IsTotem () && totem -> GetGUID () == guid )
2010-03-23 14:38:31 -05:00
totem -> ToTotem () -> UnSummon ();
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2012-08-09 18:46:59 -05:00
void WorldSession :: HandleSelfResOpcode ( WorldPacket & /*recvData*/ )
2008-10-02 16:23:55 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: CMSG_SELF_RES" ); // empty opcode
2009-10-17 15:51:44 -07:00
2011-09-06 14:23:53 +02:00
if ( _player -> HasAuraType ( SPELL_AURA_PREVENT_RESURRECTION ))
2011-08-21 14:38:21 +02:00
return ; // silent return, client should display error by itself and not send this opcode
2010-03-23 14:38:31 -05:00
if ( _player -> GetUInt32Value ( PLAYER_SELF_RES_SPELL ))
2008-10-02 16:23:55 -05:00
{
2011-09-15 14:08:17 +02:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( _player -> GetUInt32Value ( PLAYER_SELF_RES_SPELL ));
2010-03-23 14:38:31 -05:00
if ( spellInfo )
2014-08-09 21:32:26 +01:00
_player -> CastSpell ( _player , spellInfo , false , nullptr );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
_player -> SetUInt32Value ( PLAYER_SELF_RES_SPELL , 0 );
}
}
2009-10-17 15:51:44 -07:00
2012-08-05 19:40:30 -05:00
void WorldSession :: HandleSpellClick ( WorldPacket & recvData )
2009-05-05 16:56:15 -05:00
{
2014-09-14 16:14:12 +02:00
ObjectGuid guid ;
2012-08-05 19:40:30 -05:00
recvData >> guid ;
2009-10-17 15:51:44 -07:00
2009-08-26 23:40:28 -05:00
// this will get something not in world. crash
2011-06-12 01:47:45 +02:00
Creature * unit = ObjectAccessor :: GetCreatureOrPetOrVehicle ( * _player , guid );
2009-10-17 16:20:24 -07:00
2010-03-23 14:38:31 -05:00
if ( ! unit )
2009-05-05 16:56:15 -05:00
return ;
2009-10-17 15:51:44 -07:00
2013-03-08 21:41:30 +01:00
/// @todo Unit::SetCharmedBy: 28782 is not in world but 0 is trying to charm it! -> crash
2010-04-07 19:14:10 +02:00
if ( ! unit -> IsInWorld ())
2009-08-27 11:08:55 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-03-08 19:11:02 +01:00
unit -> HandleSpellClick ( _player );
2009-05-05 16:56:15 -05:00
}
2009-10-17 15:51:44 -07:00
2012-08-07 07:44:16 -05:00
void WorldSession :: HandleMirrorImageDataRequest ( WorldPacket & recvData )
2009-07-22 17:10:30 +02:00
{
2014-09-14 16:14:12 +02:00
ObjectGuid guid ;
2012-08-05 19:40:30 -05:00
recvData >> guid ;
2012-08-07 07:44:16 -05:00
recvData . read_skip < uint32 > (); // DisplayId ?
2009-10-17 15:51:44 -07:00
2009-07-22 17:10:30 +02:00
// Get unit for which data is needed by client
2011-07-31 16:43:54 +02:00
Unit * unit = ObjectAccessor :: GetObjectInWorld ( guid , ( Unit * ) NULL );
2010-03-23 14:38:31 -05:00
if ( ! unit )
2009-07-22 17:10:30 +02:00
return ;
2010-03-23 14:38:31 -05:00
2011-07-31 16:43:54 +02:00
if ( ! unit -> HasAuraType ( SPELL_AURA_CLONE_CASTER ))
return ;
// Get creator of the unit (SPELL_AURA_CLONE_CASTER does not stack)
Unit * creator = unit -> GetAuraEffectsByType ( SPELL_AURA_CLONE_CASTER ). front () -> GetCaster ();
2009-07-22 17:10:30 +02:00
if ( ! creator )
return ;
2010-03-23 14:38:31 -05:00
2015-02-01 20:52:05 +01:00
WorldPacket data ( SMSG_MIRROR_IMAGE_COMPONENTED_DATA , 68 );
2014-10-21 21:09:15 +02:00
data << guid ;
2010-03-23 14:38:31 -05:00
data << uint32 ( creator -> GetDisplayId ());
2011-07-31 16:43:54 +02:00
data << uint8 ( creator -> getRace ());
data << uint8 ( creator -> getGender ());
data << uint8 ( creator -> getClass ());
2009-10-18 18:38:46 -07:00
if ( creator -> GetTypeId () == TYPEID_PLAYER )
2009-07-22 17:10:30 +02:00
{
2011-07-31 16:43:54 +02:00
Player * player = creator -> ToPlayer ();
2012-01-18 18:13:57 +01:00
Guild * guild = NULL ;
2012-01-18 18:26:15 +01:00
2014-10-26 02:57:28 +02:00
if ( ObjectGuid :: LowType guildId = player -> GetGuildId ())
2012-01-18 18:13:57 +01:00
guild = sGuildMgr -> GetGuildById ( guildId );
2015-02-05 20:52:51 +01:00
data << uint8 ( player -> GetByteValue ( PLAYER_BYTES , PLAYER_BYTES_OFFSET_SKIN_ID ));
data << uint8 ( player -> GetByteValue ( PLAYER_BYTES , PLAYER_BYTES_OFFSET_FACE_ID ));
data << uint8 ( player -> GetByteValue ( PLAYER_BYTES , PLAYER_BYTES_OFFSET_HAIR_STYLE_ID ));
data << uint8 ( player -> GetByteValue ( PLAYER_BYTES , PLAYER_BYTES_OFFSET_HAIR_COLOR_ID ));
data << uint8 ( player -> GetByteValue ( PLAYER_BYTES_2 , PLAYER_BYTES_2_OFFSET_FACIAL_STYLE ));
2014-10-21 19:23:32 +02:00
data << ( guild ? guild -> GetGUID () : ObjectGuid :: Empty );
2011-07-31 16:43:54 +02:00
static EquipmentSlots const itemSlots [] =
2009-07-22 17:10:30 +02:00
{
EQUIPMENT_SLOT_HEAD ,
EQUIPMENT_SLOT_SHOULDERS ,
EQUIPMENT_SLOT_BODY ,
EQUIPMENT_SLOT_CHEST ,
EQUIPMENT_SLOT_WAIST ,
EQUIPMENT_SLOT_LEGS ,
EQUIPMENT_SLOT_FEET ,
EQUIPMENT_SLOT_WRISTS ,
EQUIPMENT_SLOT_HANDS ,
EQUIPMENT_SLOT_BACK ,
EQUIPMENT_SLOT_TABARD ,
EQUIPMENT_SLOT_END
};
2010-03-23 14:38:31 -05:00
2009-07-22 17:10:30 +02:00
// Display items in visible slots
2011-07-31 16:43:54 +02:00
for ( EquipmentSlots const * itr = & itemSlots [ 0 ]; * itr != EQUIPMENT_SLOT_END ; ++ itr )
2009-08-29 02:28:02 +02:00
{
2011-07-31 16:43:54 +02:00
if ( * itr == EQUIPMENT_SLOT_HEAD && player -> HasFlag ( PLAYER_FLAGS , PLAYER_FLAGS_HIDE_HELM ))
2010-03-23 14:38:31 -05:00
data << uint32 ( 0 );
2011-07-31 16:43:54 +02:00
else if ( * itr == EQUIPMENT_SLOT_BACK && player -> HasFlag ( PLAYER_FLAGS , PLAYER_FLAGS_HIDE_CLOAK ))
2010-03-23 14:38:31 -05:00
data << uint32 ( 0 );
2011-09-15 14:08:17 +02:00
else if ( Item const * item = player -> GetItemByPos ( INVENTORY_SLOT_BAG_0 , * itr ))
2014-12-21 13:35:43 +01:00
data << uint32 ( item -> GetDisplayId ());
2009-07-22 17:10:30 +02:00
else
2010-03-23 14:38:31 -05:00
data << uint32 ( 0 );
2009-08-29 02:28:02 +02:00
}
2009-07-22 17:10:30 +02:00
}
else
{
// Skip player data for creatures
2011-07-31 16:43:54 +02:00
data << uint8 ( 0 );
2010-03-23 14:38:31 -05:00
data << uint32 ( 0 );
data << uint32 ( 0 );
data << uint32 ( 0 );
data << uint32 ( 0 );
data << uint32 ( 0 );
data << uint32 ( 0 );
data << uint32 ( 0 );
data << uint32 ( 0 );
data << uint32 ( 0 );
data << uint32 ( 0 );
data << uint32 ( 0 );
data << uint32 ( 0 );
data << uint32 ( 0 );
}
SendPacket ( & data );
2009-07-22 17:10:30 +02:00
}
2011-04-11 21:24:02 +02:00
void WorldSession :: HandleUpdateProjectilePosition ( WorldPacket & recvPacket )
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: CMSG_UPDATE_PROJECTILE_POSITION" );
2011-04-11 21:24:02 +02:00
2014-09-14 16:14:12 +02:00
ObjectGuid casterGuid ;
2011-04-11 21:24:02 +02:00
uint32 spellId ;
uint8 castCount ;
float x , y , z ; // Position of missile hit
2012-05-30 08:01:02 +02:00
recvPacket >> casterGuid ;
2011-04-11 21:24:02 +02:00
recvPacket >> spellId ;
recvPacket >> castCount ;
recvPacket >> x ;
recvPacket >> y ;
recvPacket >> z ;
2012-05-30 08:01:02 +02:00
Unit * caster = ObjectAccessor :: GetUnit ( * _player , casterGuid );
2012-06-03 05:41:30 +02:00
if ( ! caster )
return ;
Spell * spell = caster -> FindCurrentSpellBySpellId ( spellId );
if ( ! spell || ! spell -> m_targets . HasDst ())
return ;
Position pos = * spell -> m_targets . GetDstPos ();
pos . Relocate ( x , y , z );
spell -> m_targets . ModDst ( pos );
2012-05-30 08:01:02 +02:00
2011-04-11 21:24:02 +02:00
WorldPacket data ( SMSG_SET_PROJECTILE_POSITION , 21 );
2014-10-21 21:09:15 +02:00
data << casterGuid ;
2011-04-11 21:24:02 +02:00
data << uint8 ( castCount );
data << float ( x );
data << float ( y );
data << float ( z );
2012-06-03 05:41:30 +02:00
caster -> SendMessageToSet ( & data , true );
2011-04-11 21:24:02 +02:00
}
2013-06-07 20:35:30 +02:00
void WorldSession :: HandleRequestCategoryCooldowns ( WorldPacket & /*recvPacket*/ )
{
2014-11-14 02:00:34 +01:00
SendSpellCategoryCooldowns ();
}
void WorldSession :: SendSpellCategoryCooldowns ()
{
2014-11-30 15:37:11 +01:00
WorldPackets :: Spells :: CategoryCooldown cooldowns ;
2014-11-14 02:00:34 +01:00
2013-06-07 20:35:30 +02:00
Unit :: AuraEffectList const & categoryCooldownAuras = _player -> GetAuraEffectsByType ( SPELL_AURA_MOD_SPELL_CATEGORY_COOLDOWN );
2014-11-14 02:00:34 +01:00
for ( AuraEffect * aurEff : categoryCooldownAuras )
2013-06-07 20:35:30 +02:00
{
2014-11-14 02:00:34 +01:00
uint32 categoryId = aurEff -> GetMiscValue ();
auto cItr = std :: find_if ( cooldowns . CategoryCooldowns . begin (), cooldowns . CategoryCooldowns . end (),
2014-11-30 15:37:11 +01:00
[ categoryId ]( WorldPackets :: Spells :: CategoryCooldown :: CategoryCooldownInfo const & cooldown )
2014-11-14 02:00:34 +01:00
{
return cooldown . Category == categoryId ;
});
2013-06-07 20:35:30 +02:00
2014-11-14 02:00:34 +01:00
if ( cItr == cooldowns . CategoryCooldowns . end ())
cooldowns . CategoryCooldowns . emplace_back ( aurEff -> GetMiscValue (), - aurEff -> GetAmount ());
else
cItr -> ModCooldown -= aurEff -> GetAmount ();
2013-06-07 20:35:30 +02:00
}
2014-11-14 02:00:34 +01:00
SendPacket ( cooldowns . Write ());
2013-06-07 20:35:30 +02:00
}