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/>.
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"
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 )
{
recvPacket . rfinish ();
// movement packet for caster of the spell
/*recvPacket.read_skip<uint32>(); // MSG_MOVE_STOP - hardcoded in client
uint64 guid;
recvPacket.readPackGUID(guid);
MovementInfo movementInfo;
movementInfo.guid = guid;
ReadMovementInfo(recvPacket, &movementInfo);*/
}
}
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 )
{
// TODO: add targets.read() check
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 ;
uint8 castCount ; // next cast if exists (single or not)
uint64 itemGUID ;
2008-12-24 09:58:26 -06:00
uint32 glyphIndex ; // something to do with glyphs?
2010-08-08 20:32:14 +02:00
uint32 spellId ; // casted 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
2012-06-03 05:41:30 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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
2010-03-23 14:38:31 -05:00
if ( proto -> InventoryType != 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)
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
{
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
if ( proto -> Flags & ITEM_PROTO_FLAG_NOT_USEABLE_IN_ARENA && pUser -> InArena ())
{
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
2008-10-02 16:23:55 -05:00
if ( pUser -> isInCombat ())
{
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
{
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)
2011-04-28 22:42:33 +02: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
{
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 )
{
2012-06-03 05:41:30 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_NETWORKIO , "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 );
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "Possible hacking attempt: Player %s [guid: %u] tried to open item [guid: %u, entry: %u] which is not openable!" ,
2011-12-25 18:12:58 +01:00
pUser -> GetName (), 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 );
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "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-05-30 08:01:02 +02: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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "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-05-30 08:01:02 +02: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-08-05 19:40:30 -05:00
void WorldSession :: HandleGameObjectUseOpcode ( WorldPacket & recvData )
2008-10-02 16:23:55 -05:00
{
uint64 guid ;
2009-10-17 15:51:44 -07:00
2012-08-05 19:40:30 -05:00
recvData >> guid ;
2009-10-17 15:51:44 -07:00
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: Recvd CMSG_GAMEOBJ_USE Message [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
2011-09-15 14:08:17 +02:00
if ( GameObject * obj = GetPlayer () -> GetMap () -> GetGameObject ( guid ))
2011-08-30 13:46:36 +02:00
obj -> Use ( _player );
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
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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
2010-11-20 13:54:45 +01:00
go -> AI () -> GossipHello ( _player );
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
2008-10-02 16:23:55 -05:00
void WorldSession :: HandleCastSpellOpcode ( WorldPacket & recvPacket )
{
2011-11-24 06:14:57 +01:00
uint32 spellId , glyphIndex ;
2010-08-08 20:32:14 +02:00
uint8 castCount , castFlags ;
2011-11-24 06:14:57 +01:00
recvPacket >> castCount ;
recvPacket >> spellId ;
recvPacket >> glyphIndex ;
recvPacket >> castFlags ;
2010-08-08 20:32:14 +02:00
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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
2012-08-09 18:07:12 +02:00
if ( Player * plrMover = mover -> ToPlayer ())
spellId = plrMover -> GetSpellForCast ( spellId );
2009-10-17 15:51:44 -07:00
2012-08-09 18:07:12 +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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "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
2010-03-23 14:38:31 -05:00
if ( mover -> GetTypeId () == TYPEID_PLAYER )
2008-10-02 16:23:55 -05:00
{
2009-04-03 16:42:19 -06:00
// not have spell in spellbook or spell passive and not casted by client
2012-08-09 18:07:12 +02:00
if ( ! mover -> ToPlayer () -> HasActiveSpell ( spellId ) || spellInfo -> IsPassive ())
2009-04-03 16:42:19 -06:00
{
//cheater? kick? ban?
2010-08-08 20:32:14 +02:00
recvPacket . rfinish (); // prevent spam at ignore packet
2009-04-03 16:42:19 -06:00
return ;
}
}
else
{
// not have spell in spellbook or spell passive and not casted by client
2011-07-26 23:09:28 +02:00
if (( mover -> GetTypeId () == TYPEID_UNIT && ! mover -> ToCreature () -> HasSpell ( spellId )) || spellInfo -> IsPassive ())
2009-04-03 16:42:19 -06:00
{
//cheater? kick? ban?
2010-08-08 20:32:14 +02:00
recvPacket . rfinish (); // prevent spam at ignore packet
2009-04-03 16:42:19 -06:00
return ;
}
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2009-06-09 19:33:38 +02:00
// Client is resending autoshot cast opcode when other spell is casted during shoot rotation
// Skip it to prevent "interrupt" message
2011-07-26 23:09:28 +02:00
if ( spellInfo -> IsAutoRepeatRangedSpell () && _player -> GetCurrentSpell ( CURRENT_AUTOREPEAT_SPELL )
2009-08-19 16:52:51 -05:00
&& _player -> 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 ;
2011-06-23 13:28:52 +02:00
targets . Read ( recvPacket , mover );
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
2008-10-02 16:23:55 -05:00
// if rank not found then function return NULL but in explicit cast case original spell can be casted 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
2011-07-31 19:03:06 +02:00
Spell * spell = new Spell ( mover , spellInfo , TRIGGERED_NONE , 0 , false );
2010-08-08 20:32:14 +02:00
spell -> m_cast_count = castCount ; // set count of casts
2012-01-29 17:40:14 +01:00
spell -> m_glyphIndex = glyphIndex ;
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
2010-03-23 14:38:31 -05:00
if ( _player -> IsNonMeleeSpellCasted ( 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 ;
2008-11-21 21:00:45 -05:00
// channeled spell case (it currently casted 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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "HandlePetCancelAura: Attempt to cancel an aura for non-existant pet %u by player '%s'" , uint32 ( GUID_LOPART ( guid )), GetPlayer () -> GetName ());
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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "HandlePetCancelAura: Pet %u is not a pet of player '%s'" , uint32 ( GUID_LOPART ( guid )), GetPlayer () -> GetName ());
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 -> 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
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleCancelGrowthAuraOpcode ( WorldPacket & /*recvPacket*/ )
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 :: 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-08-05 19:40:30 -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 ;
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 ]);
2008-11-14 20:40:35 -06:00
// Don't unsummon sentry totem
2010-03-23 14:38:31 -05:00
if ( totem && totem -> isTotem () && totem -> GetEntry () != SENTRY_TOTEM_ENTRY )
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
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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 )
2011-04-29 20:47:02 +02:00
_player -> CastSpell ( _player , spellInfo , false , 0 );
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
{
uint64 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
2009-08-27 11:08:55 -05: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
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: CMSG_GET_MIRRORIMAGE_DATA" );
2009-07-22 17:10:30 +02:00
uint64 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
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 ();
2012-01-18 18:13:57 +01:00
Guild * guild = NULL ;
2012-01-18 18:26:15 +01:00
if ( uint32 guildId = player -> GetGuildId ())
2012-01-18 18:13:57 +01:00
guild = sGuildMgr -> GetGuildById ( guildId );
2011-07-31 16:43:54 +02:00
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
2012-07-09 11:08:33 +02:00
data << uint64 ( guild ? guild -> GetGUID () : 0 );
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 ))
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 )
{
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: CMSG_UPDATE_PROJECTILE_POSITION" );
uint64 casterGuid ;
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 );
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
}