2010-10-07 15:35:36 +02:00
/*
2014-01-01 00:07:53 +01:00
* Copyright (C) 2008-2014 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"
#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"
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 ;
if ( hasMovementData )
{
2012-11-25 11:12:53 +01:00
recvPacket . SetOpcode ( recvPacket . read < uint32 > ());
HandleMovementOpcodes ( recvPacket );
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)
2010-08-08 20:32:14 +02:00
uint64 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 ;
}
2012-03-14 18:51:51 +01:00
Item * pItem = pUser -> GetUseableItemByPos ( bagIndex , slot );
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
2012-03-14 18:51:51 +01: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
2012-03-14 18:51:51 +01:00
ItemTemplate const * proto = pItem -> GetTemplate ();
2010-03-23 14:38:31 -05:00
if ( ! proto )
2008-10-02 16:23:55 -05:00
{
2012-03-14 18:51:51 +01: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
2012-03-14 18:51:51 +01:00
if ( proto -> InventoryType != INVTYPE_NON_EQUIP && ! pItem -> IsEquipped ())
2008-10-02 16:23:55 -05:00
{
2012-03-14 18:51:51 +01: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
2012-03-14 18:51:51 +01: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
{
2012-03-14 18:51:51 +01: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)
2010-08-04 10:34:30 +02:00
if ( proto -> Class == ITEM_CLASS_CONSUMABLE && ! ( proto -> Flags & ITEM_PROTO_FLAG_USEABLE_IN_ARENA ) && pUser -> InArena ())
2008-10-02 16:23:55 -05:00
{
2012-03-14 18:51:51 +01:00
pUser -> SendEquipError ( EQUIP_ERR_NOT_DURING_ARENA_MATCH , pItem , NULL );
2010-08-04 10:34:30 +02:00
return ;
}
// don't allow items banned in arena
if ( proto -> Flags & ITEM_PROTO_FLAG_NOT_USEABLE_IN_ARENA && pUser -> InArena ())
{
2012-03-14 18:51:51 +01: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
{
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < MAX_ITEM_PROTO_SPELLS ; ++ i )
2008-10-02 16:23:55 -05:00
{
2011-09-15 14:08:17 +02:00
if ( SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( proto -> Spells [ 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
{
2012-03-14 18:51:51 +01: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)
2012-03-14 18:51:51 +01:00
if ( pItem -> GetTemplate () -> Bonding == BIND_WHEN_USE || pItem -> GetTemplate () -> Bonding == BIND_WHEN_PICKED_UP || pItem -> GetTemplate () -> Bonding == BIND_QUEST_ITEM )
2008-10-02 16:23:55 -05:00
{
2012-03-14 18:51:51 +01:00
if ( ! pItem -> IsSoulBound ())
2008-10-02 16:23:55 -05:00
{
2012-03-14 18:51:51 +01:00
pItem -> SetState ( ITEM_CHANGED , pUser );
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.
2012-03-14 18:51:51 +01:00
if ( ! sScriptMgr -> OnItemUse ( pUser , pItem , targets ))
2008-10-02 16:23:55 -05:00
{
// no script or script not process request by self
2012-03-14 18:51:51 +01: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"
2011-12-25 18:12:58 +01:00
if ( ! ( proto -> Flags & ITEM_PROTO_FLAG_OPENABLE ) && ! item -> HasFlag ( ITEM_FIELD_FLAGS , ITEM_FLAG_WRAPPED ))
2010-11-07 20:08:52 +01:00
{
2011-12-25 18:12:58 +01:00
pUser -> SendEquipError ( EQUIP_ERR_CANT_DO_RIGHT_NOW , item , NULL );
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network" , "Possible hacking attempt: Player %s [guid: %u] tried to open item [guid: %u, entry: %u] which is not openable!" ,
2012-10-24 13:29:34 +02:00
pUser -> GetName (). c_str (), pUser -> GetGUIDLow (), item -> GetGUIDLow (), proto -> ItemId );
2010-11-07 20:08:52 +01:00
return ;
}
2008-10-02 16:23:55 -05:00
// locked item
uint32 lockId = proto -> LockID ;
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 );
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network" , "WORLD::OpenItem: item [guid = %u] has an unknown lockId: %u!" , item -> GetGUIDLow (), 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-03-24 01:25:08 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_GIFT_BY_ITEM );
stmt -> setUInt32 ( 0 , item -> GetGUIDLow ());
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
2011-12-25 18:12:58 +01:00
item -> SetUInt64Value ( ITEM_FIELD_GIFTCREATOR , 0 );
item -> SetEntry ( entry );
item -> SetUInt32Value ( ITEM_FIELD_FLAGS , flags );
item -> SetState ( ITEM_CHANGED , pUser );
2008-10-02 16:23:55 -05:00
}
else
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network" , "Wrapped item %u don't have record in character_gifts table and will deleted" , item -> GetGUIDLow ());
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-03-24 01:25:08 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_GIFT );
2011-12-25 18:12:58 +01:00
stmt -> setUInt32 ( 0 , item -> GetGUIDLow ());
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
2012-11-27 13:02:04 +01:00
void WorldSession :: HandleGameObjectUseOpcode ( WorldPacket & recvData )
2008-10-02 16:23:55 -05:00
{
uint64 guid ;
2012-11-02 22:23:14 +01:00
recvData >> guid ;
2009-10-17 15:51:44 -07:00
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: Recvd CMSG_GAMEOBJ_USE Message [guid=%u]" , GUID_LOPART ( guid ));
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
if ( GameObject * obj = GetPlayer () -> GetMap () -> GetGameObject ( 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
2008-12-27 11:39:40 -06:00
void WorldSession :: HandleGameobjectReportUse ( WorldPacket & recvPacket )
{
uint64 guid ;
recvPacket >> guid ;
2009-10-17 15:51:44 -07:00
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: Recvd CMSG_GAMEOBJ_REPORT_USE Message [in game guid: %u]" , GUID_LOPART ( guid ));
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 ( _player -> m_mover != _player )
2009-04-03 16:42:19 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-04-20 20:28:19 -05:00
GameObject * go = GetPlayer () -> GetMap () -> GetGameObject ( 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-09-18 14:29:53 +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
2008-10-02 16:23:55 -05:00
void WorldSession :: HandleCastSpellOpcode ( WorldPacket & recvPacket )
{
uint32 spellId ;
2010-08-08 20:32:14 +02:00
uint8 castCount , castFlags ;
recvPacket >> castCount >> spellId >> castFlags ;
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: got cast spell packet, castCount: %u, spellId: %u, castFlags: %u, data length = %u" , castCount , spellId , castFlags , ( uint32 ) recvPacket . size ());
2009-10-17 15:51:44 -07: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-08-24 19:33:34 -05:00
{
2010-08-08 20:32:14 +02:00
recvPacket . rfinish (); // prevent spam at ignore packet
2009-04-03 16:42:19 -06:00
return ;
2009-08-24 19:33:34 -05:00
}
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 spell id %u" , spellId );
2010-08-08 20:32:14 +02:00
recvPacket . rfinish (); // prevent spam at ignore packet
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 ())
2008-10-02 16:23:55 -05:00
{
2013-02-27 13:17:20 +01:00
recvPacket . rfinish (); // prevent spam at ignore packet
return ;
2009-04-03 16:42:19 -06:00
}
2013-02-27 13:17:20 +01:00
Unit * caster = mover ;
if ( caster -> GetTypeId () == TYPEID_UNIT && ! caster -> ToCreature () -> HasSpell ( spellId ))
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
{
2010-08-08 20:32:14 +02:00
recvPacket . rfinish (); // prevent spam at ignore packet
2009-04-03 16:42:19 -06:00
return ;
}
2013-02-27 13:17:20 +01:00
caster = _player ;
}
if ( caster -> GetTypeId () == TYPEID_PLAYER && ! caster -> ToPlayer () -> HasActiveSpell ( spellId ))
{
// not have spell in spellbook
recvPacket . rfinish (); // prevent spam at ignore packet
return ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07: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 )
2010-12-22 21:32:48 +01:00
{
recvPacket . rfinish ();
2009-06-09 19:33:38 +02:00
return ;
2010-12-22 21:32:48 +01:00
}
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 ())
2010-08-08 20:32:14 +02:00
{
recvPacket . rfinish (); // prevent spam at ignore packet
2008-11-05 20:51:05 -06:00
return ;
2010-08-08 20:32:14 +02:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// client provided targets
SpellCastTargets targets ;
2013-02-27 13:17:20 +01:00
targets . Read ( recvPacket , caster );
2010-08-08 20:32:14 +02:00
HandleClientCastFlags ( recvPacket , castFlags , targets );
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
2013-02-27 13:17:20 +01:00
Spell * spell = new Spell ( caster , spellInfo , TRIGGERED_NONE , 0 , false );
2010-08-08 20:32:14 +02:00
spell -> m_cast_count = castCount ; // set count of casts
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
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleCancelAuraOpcode ( WorldPacket & recvPacket )
2008-10-02 16:23:55 -05:00
{
uint32 spellId ;
recvPacket >> spellId ;
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( 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
if ( spellInfo -> Attributes & 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 ))
2010-04-07 23:25:02 +02:00
if ( curSpell -> m_spellInfo -> Id == 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 ;
2009-05-18 23:07:36 -05:00
// maybe should only remove one buff when there are multiple?
2010-01-10 01:23:15 +01:00
_player -> RemoveOwnedAura ( spellId , 0 , 0 , AURA_REMOVE_BY_CANCEL );
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
{
uint64 guid ;
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
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network" , "HandlePetCancelAura: Attempt to cancel an aura for non-existant pet %u by player '%s'" , uint32 ( GUID_LOPART ( guid )), 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
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network" , "HandlePetCancelAura: Pet %u is not a pet of player '%s'" , uint32 ( GUID_LOPART ( guid )), 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
2010-01-10 01:23:15 +01:00
pet -> RemoveOwnedAura ( spellId , 0 , 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-11-27 13:02:04 +01:00
void WorldSession :: HandleCancelChanneling ( WorldPacket & recvData )
2008-10-02 16:23:55 -05:00
{
2012-11-02 22:23:14 +01: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 ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
recvPacket >> slotId ;
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 ]);
2012-08-23 17:46:14 +02:00
2013-06-11 19:54:27 -02:30
if ( totem && totem -> IsTotem ())
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-11-02 22:23:14 +01: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-11-02 22:23:14 +01:00
void WorldSession :: HandleSpellClick ( WorldPacket & recvData )
2009-05-05 16:56:15 -05:00
{
uint64 guid ;
2012-11-02 22:23:14 +01: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-11-27 13:02:04 +01:00
void WorldSession :: HandleMirrorImageDataRequest ( WorldPacket & recvData )
2009-07-22 17:10:30 +02:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: CMSG_GET_MIRRORIMAGE_DATA" );
2009-07-22 17:10:30 +02:00
uint64 guid ;
2012-11-02 22:23:14 +01:00
recvData >> guid ;
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
2009-07-22 17:10:30 +02:00
WorldPacket data ( SMSG_MIRRORIMAGE_DATA , 68 );
2010-03-23 14:38:31 -05:00
data << uint64 ( guid );
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 ();
data << uint8 ( player -> GetByteValue ( PLAYER_BYTES , 0 )); // skin
data << uint8 ( player -> GetByteValue ( PLAYER_BYTES , 1 )); // face
data << uint8 ( player -> GetByteValue ( PLAYER_BYTES , 2 )); // hair
data << uint8 ( player -> GetByteValue ( PLAYER_BYTES , 3 )); // haircolor
data << uint8 ( player -> GetByteValue ( PLAYER_BYTES_2 , 0 )); // facialhair
data << uint32 ( player -> GetGuildId ()); // unk
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 ))
2011-04-28 22:42:33 +02:00
data << uint32 ( item -> GetTemplate () -> DisplayInfoID );
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
uint64 casterGuid ;
uint32 spellId ;
uint8 castCount ;
float x , y , z ; // Position of missile hit
2012-05-25 16:44:34 +02:00
recvPacket >> casterGuid ;
2011-04-11 21:24:02 +02:00
recvPacket >> spellId ;
recvPacket >> castCount ;
recvPacket >> x ;
recvPacket >> y ;
recvPacket >> z ;
2012-05-25 16:44:34 +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-25 16:44:34 +02:00
2011-04-11 21:24:02 +02:00
WorldPacket data ( SMSG_SET_PROJECTILE_POSITION , 21 );
data << uint64 ( casterGuid );
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
}