2010-10-07 15:35:36 +02:00
/*
2020-01-02 06:44:10 +01:00
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
2010-10-07 15:35:36 +02:00
*
* 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-11 14:16:25 -05:00
*/
2009-10-17 15:51:44 -07:00
2020-09-04 13:38:24 +02:00
#include "WorldSession.h"
2017-05-18 23:52:58 +02:00
#include "BattlePetMgr.h"
#include "Common.h"
2017-06-04 01:00:45 +02:00
#include "Creature.h"
2017-05-18 23:52:58 +02:00
#include "DatabaseEnv.h"
#include "DB2Stores.h"
#include "Item.h"
#include "ItemPackets.h"
2008-10-11 14:16:25 -05:00
#include "Log.h"
2017-05-18 23:52:58 +02:00
#include "NPCPackets.h"
2008-10-11 14:16:25 -05:00
#include "ObjectMgr.h"
2017-05-18 23:52:58 +02:00
#include "Opcodes.h"
2008-10-11 14:16:25 -05:00
#include "Player.h"
2020-04-08 13:36:59 +02:00
#include "SpellMgr.h"
2017-08-12 01:40:25 +02:00
#include "World.h"
2009-10-17 15:51:44 -07:00
2014-12-21 19:11:39 +01:00
void WorldSession :: HandleSplitItemOpcode ( WorldPackets :: Item :: SplitItem & splitItem )
2008-10-11 14:16:25 -05:00
{
2014-12-30 00:39:51 +01:00
if ( ! splitItem . Inv . Items . empty ())
2014-12-20 22:29:06 +01:00
{
2014-12-30 00:39:51 +01:00
TC_LOG_ERROR ( "network" , "HandleSplitItemOpcode - Invalid ItemCount (" SZFMTD ")" , splitItem . Inv . Items . size ());
2014-12-20 22:29:06 +01:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
TC_LOG_DEBUG ( "network" , "HandleSplitItemOpcode: receive FromPackSlot: %u, FromSlot: %u, ToPackSlot: %u, ToSlot: %u, Quantity: %u" ,
splitItem . FromPackSlot , splitItem . FromSlot , splitItem . ToPackSlot , splitItem . ToSlot , splitItem . Quantity );
2014-12-23 00:25:43 +01:00
2014-12-30 00:39:51 +01:00
uint16 src = (( splitItem . FromPackSlot << 8 ) | splitItem . FromSlot );
uint16 dst = (( splitItem . ToPackSlot << 8 ) | splitItem . ToSlot );
2009-10-17 15:51:44 -07:00
2010-04-07 23:25:02 +02:00
if ( src == dst )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
// check count - if zero it's fake packet
if ( ! splitItem . Quantity )
return ;
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
if ( ! _player -> IsValidPos ( splitItem . FromPackSlot , splitItem . FromSlot , true ))
2008-11-10 09:04:23 -06:00
{
2014-12-30 00:39:51 +01:00
_player -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND );
2008-11-10 09:04:23 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
if ( ! _player -> IsValidPos ( splitItem . ToPackSlot , splitItem . ToSlot , false )) // can be autostore pos
2008-11-10 09:04:23 -06:00
{
2014-12-30 00:39:51 +01:00
_player -> SendEquipError ( EQUIP_ERR_WRONG_SLOT );
2008-11-10 09:04:23 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
_player -> SplitItem ( src , dst , splitItem . Quantity );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-12-21 19:11:39 +01:00
void WorldSession :: HandleSwapInvItemOpcode ( WorldPackets :: Item :: SwapInvItem & swapInvItem )
2008-10-11 14:16:25 -05:00
{
2014-12-30 00:39:51 +01:00
if ( swapInvItem . Inv . Items . size () != 2 )
2014-12-20 22:29:06 +01:00
{
2014-12-30 00:39:51 +01:00
TC_LOG_ERROR ( "network" , "HandleSwapInvItemOpcode - Invalid itemCount (" SZFMTD ")" , swapInvItem . Inv . Items . size ());
2014-12-20 22:29:06 +01:00
return ;
}
2014-12-30 00:39:51 +01:00
TC_LOG_DEBUG ( "network" , "HandleSwapInvItemOpcode: receive Slot1: %u, Slot2: %u" ,
swapInvItem . Slot1 , swapInvItem . Slot2 );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent attempt swap same item to current position generated by client at special checting sequence
2014-12-30 00:39:51 +01:00
if ( swapInvItem . Slot1 == swapInvItem . Slot2 )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
if ( ! _player -> IsValidPos ( INVENTORY_SLOT_BAG_0 , swapInvItem . Slot1 , true ))
2008-11-10 09:04:23 -06:00
{
2014-12-30 00:39:51 +01:00
_player -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND );
2008-11-10 09:04:23 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
if ( ! _player -> IsValidPos ( INVENTORY_SLOT_BAG_0 , swapInvItem . Slot2 , true ))
2008-11-10 09:04:23 -06:00
{
2014-12-30 00:39:51 +01:00
_player -> SendEquipError ( EQUIP_ERR_WRONG_SLOT );
2008-11-10 09:04:23 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
if ( _player -> IsBankPos ( INVENTORY_SLOT_BAG_0 , swapInvItem . Slot1 ) && ! CanUseBank ())
2014-06-07 22:47:50 +02:00
{
2014-12-30 00:39:51 +01:00
TC_LOG_DEBUG ( "network" , "HandleSwapInvItemOpcode - Unit (%s) not found or you can't interact with him." , m_currentBankerGUID . ToString (). c_str ());
2014-06-07 22:47:50 +02:00
return ;
}
2014-12-30 00:39:51 +01:00
if ( _player -> IsBankPos ( INVENTORY_SLOT_BAG_0 , swapInvItem . Slot2 ) && ! CanUseBank ())
2014-06-07 22:47:50 +02:00
{
2014-12-30 00:39:51 +01:00
TC_LOG_DEBUG ( "network" , "HandleSwapInvItemOpcode - Unit (%s) not found or you can't interact with him." , m_currentBankerGUID . ToString (). c_str ());
2014-06-07 22:47:50 +02:00
return ;
}
2014-12-30 00:39:51 +01:00
uint16 src = (( INVENTORY_SLOT_BAG_0 << 8 ) | swapInvItem . Slot1 );
uint16 dst = (( INVENTORY_SLOT_BAG_0 << 8 ) | swapInvItem . Slot2 );
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
_player -> SwapItem ( src , dst );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-04-11 00:07:38 +02:00
void WorldSession :: HandleAutoEquipItemSlotOpcode ( WorldPackets :: Item :: AutoEquipItemSlot & autoEquipItemSlot )
2008-10-11 14:16:25 -05:00
{
// cheating attempt, client should never send opcode in that case
2015-04-11 00:07:38 +02:00
if ( autoEquipItemSlot . Inv . Items . size () != 1 || ! Player :: IsEquipmentPos ( INVENTORY_SLOT_BAG_0 , autoEquipItemSlot . ItemDstSlot ))
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2015-04-11 00:07:38 +02:00
Item * item = _player -> GetItemByGuid ( autoEquipItemSlot . Item );
uint16 dstPos = autoEquipItemSlot . ItemDstSlot | ( INVENTORY_SLOT_BAG_0 << 8 );
uint16 srcPos = autoEquipItemSlot . Inv . Items [ 0 ]. Slot | ( uint32 ( autoEquipItemSlot . Inv . Items [ 0 ]. ContainerSlot ) << 8 );
2009-10-17 15:51:44 -07:00
2015-04-11 00:07:38 +02:00
if ( ! item || item -> GetPos () != srcPos || srcPos == dstPos )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2015-04-11 00:07:38 +02:00
_player -> SwapItem ( srcPos , dstPos );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-12-21 19:11:39 +01:00
void WorldSession :: HandleSwapItem ( WorldPackets :: Item :: SwapItem & swapItem )
2008-10-11 14:16:25 -05:00
{
2014-12-30 00:39:51 +01:00
if ( swapItem . Inv . Items . size () != 2 )
2014-12-20 17:25:15 +01:00
{
2014-12-30 00:39:51 +01:00
TC_LOG_ERROR ( "network" , "HandleSwapItem - Invalid itemCount (" SZFMTD ")" , swapItem . Inv . Items . size ());
2014-12-20 17:25:15 +01:00
return ;
}
2014-12-20 22:29:06 +01:00
2014-12-30 00:39:51 +01:00
TC_LOG_DEBUG ( "network" , "HandleSwapItem: receive ContainerSlotA: %u, SlotA: %u, ContainerSlotB: %u, SlotB: %u" ,
swapItem . ContainerSlotA , swapItem . SlotA , swapItem . ContainerSlotB , swapItem . SlotB );
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
uint16 src = (( swapItem . ContainerSlotA << 8 ) | swapItem . SlotA );
uint16 dst = (( swapItem . ContainerSlotB << 8 ) | swapItem . SlotB );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent attempt swap same item to current position generated by client at special checting sequence
2010-04-07 23:25:02 +02:00
if ( src == dst )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
if ( ! _player -> IsValidPos ( swapItem . ContainerSlotA , swapItem . SlotA , true ))
2008-11-10 09:04:23 -06:00
{
2014-12-30 00:39:51 +01:00
_player -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND );
2008-11-10 09:04:23 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
if ( ! _player -> IsValidPos ( swapItem . ContainerSlotB , swapItem . SlotB , true ))
2008-11-10 09:04:23 -06:00
{
2014-12-30 00:39:51 +01:00
_player -> SendEquipError ( EQUIP_ERR_WRONG_SLOT );
2008-11-10 09:04:23 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
if ( _player -> IsBankPos ( swapItem . ContainerSlotA , swapItem . SlotA ) && ! CanUseBank ())
2014-06-07 22:47:50 +02:00
{
2014-12-30 00:39:51 +01:00
TC_LOG_DEBUG ( "network" , "HandleSwapItem - Unit (%s) not found or you can't interact with him." , m_currentBankerGUID . ToString (). c_str ());
2014-06-07 22:47:50 +02:00
return ;
}
2014-12-30 00:39:51 +01:00
if ( _player -> IsBankPos ( swapItem . ContainerSlotB , swapItem . SlotB ) && ! CanUseBank ())
2014-06-07 22:47:50 +02:00
{
2014-12-30 00:39:51 +01:00
TC_LOG_DEBUG ( "network" , "HandleSwapItem - Unit (%s) not found or you can't interact with him." , m_currentBankerGUID . ToString (). c_str ());
2014-06-07 22:47:50 +02:00
return ;
}
2010-04-07 22:59:46 +02:00
_player -> SwapItem ( src , dst );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-12-21 19:11:39 +01:00
void WorldSession :: HandleAutoEquipItemOpcode ( WorldPackets :: Item :: AutoEquipItem & autoEquipItem )
2008-10-11 14:16:25 -05:00
{
2014-12-30 00:39:51 +01:00
if ( autoEquipItem . Inv . Items . size () != 1 )
2014-12-20 17:25:15 +01:00
{
2014-12-30 00:39:51 +01:00
TC_LOG_ERROR ( "network" , "HandleAutoEquipItemOpcode - Invalid itemCount (" SZFMTD ")" , autoEquipItem . Inv . Items . size ());
2014-12-20 17:25:15 +01:00
return ;
}
2014-12-30 00:39:51 +01:00
TC_LOG_DEBUG ( "network" , "HandleAutoEquipItemOpcode: receive PackSlot: %u, Slot: %u" ,
autoEquipItem . PackSlot , autoEquipItem . Slot );
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
Item * srcItem = _player -> GetItemByPos ( autoEquipItem . PackSlot , autoEquipItem . Slot );
if ( ! srcItem )
return ; // only at cheat
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint16 dest ;
2014-12-30 00:39:51 +01:00
InventoryResult msg = _player -> CanEquipItem ( NULL_SLOT , dest , srcItem , ! srcItem -> IsBag ());
2010-04-07 22:59:46 +02:00
if ( msg != EQUIP_ERR_OK )
2008-10-11 14:16:25 -05:00
{
2014-12-30 00:39:51 +01:00
_player -> SendEquipError ( msg , srcItem );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
uint16 src = srcItem -> GetPos ();
if ( dest == src ) // prevent equip in same slot, only at cheat
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
Item * dstItem = _player -> GetItemByPos ( dest );
if ( ! dstItem ) // empty slot, simple case
2008-10-11 14:16:25 -05:00
{
2016-07-16 13:52:12 +02:00
if ( ! srcItem -> GetChildItem (). IsEmpty ())
{
InventoryResult childEquipResult = _player -> CanEquipChildItem ( srcItem );
if ( childEquipResult != EQUIP_ERR_OK )
{
_player -> SendEquipError ( msg , srcItem );
return ;
}
}
2014-12-30 00:39:51 +01:00
_player -> RemoveItem ( autoEquipItem . PackSlot , autoEquipItem . Slot , true );
_player -> EquipItem ( dest , srcItem , true );
2016-07-16 13:52:12 +02:00
if ( ! srcItem -> GetChildItem (). IsEmpty ())
_player -> EquipChildItem ( autoEquipItem . PackSlot , autoEquipItem . Slot , srcItem );
2008-10-11 14:16:25 -05:00
_player -> AutoUnequipOffhandIfNeed ();
}
else // have currently equipped item, not simple case
{
2014-12-30 00:39:51 +01:00
uint8 dstbag = dstItem -> GetBagSlot ();
uint8 dstslot = dstItem -> GetSlot ();
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
msg = _player -> CanUnequipItem ( dest , ! srcItem -> IsBag ());
2010-04-07 22:59:46 +02:00
if ( msg != EQUIP_ERR_OK )
2008-10-11 14:16:25 -05:00
{
2014-12-30 00:39:51 +01:00
_player -> SendEquipError ( msg , dstItem );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2019-06-03 20:40:34 +02:00
if ( ! dstItem -> HasItemFlag ( ITEM_FIELD_FLAG_CHILD ))
2008-10-11 14:16:25 -05:00
{
2016-07-16 13:52:12 +02:00
// check dest->src move possibility
ItemPosCountVec sSrc ;
uint16 eSrc = 0 ;
if ( _player -> IsInventoryPos ( src ))
{
msg = _player -> CanStoreItem ( autoEquipItem . PackSlot , autoEquipItem . Slot , sSrc , dstItem , true );
if ( msg != EQUIP_ERR_OK )
msg = _player -> CanStoreItem ( autoEquipItem . PackSlot , NULL_SLOT , sSrc , dstItem , true );
if ( msg != EQUIP_ERR_OK )
msg = _player -> CanStoreItem ( NULL_BAG , NULL_SLOT , sSrc , dstItem , true );
}
else if ( _player -> IsBankPos ( src ))
{
msg = _player -> CanBankItem ( autoEquipItem . PackSlot , autoEquipItem . Slot , sSrc , dstItem , true );
if ( msg != EQUIP_ERR_OK )
msg = _player -> CanBankItem ( autoEquipItem . PackSlot , NULL_SLOT , sSrc , dstItem , true );
if ( msg != EQUIP_ERR_OK )
msg = _player -> CanBankItem ( NULL_BAG , NULL_SLOT , sSrc , dstItem , true );
}
else if ( _player -> IsEquipmentPos ( src ))
{
msg = _player -> CanEquipItem ( autoEquipItem . Slot , eSrc , dstItem , true );
if ( msg == EQUIP_ERR_OK )
msg = _player -> CanUnequipItem ( eSrc , true );
}
if ( msg == EQUIP_ERR_OK && Player :: IsEquipmentPos ( dest ) && ! srcItem -> GetChildItem (). IsEmpty ())
msg = _player -> CanEquipChildItem ( srcItem );
2010-04-07 22:59:46 +02:00
if ( msg != EQUIP_ERR_OK )
2016-07-16 13:52:12 +02:00
{
_player -> SendEquipError ( msg , dstItem , srcItem );
return ;
}
// now do moves, remove...
_player -> RemoveItem ( dstbag , dstslot , false );
_player -> RemoveItem ( autoEquipItem . PackSlot , autoEquipItem . Slot , false );
// add to dest
_player -> EquipItem ( dest , srcItem , true );
// add to src
if ( _player -> IsInventoryPos ( src ))
_player -> StoreItem ( sSrc , dstItem , true );
else if ( _player -> IsBankPos ( src ))
_player -> BankItem ( sSrc , dstItem , true );
else if ( _player -> IsEquipmentPos ( src ))
_player -> EquipItem ( eSrc , dstItem , true );
if ( Player :: IsEquipmentPos ( dest ) && ! srcItem -> GetChildItem (). IsEmpty ())
_player -> EquipChildItem ( autoEquipItem . PackSlot , autoEquipItem . Slot , srcItem );
2008-10-11 14:16:25 -05:00
}
2016-07-16 13:52:12 +02:00
else
2008-10-11 14:16:25 -05:00
{
2019-06-03 20:40:34 +02:00
if ( Item * parentItem = _player -> GetItemByGuid ( dstItem -> GetCreator ()))
2016-07-16 13:52:12 +02:00
{
if ( Player :: IsEquipmentPos ( dest ))
{
_player -> AutoUnequipChildItem ( parentItem );
// dest is now empty
_player -> SwapItem ( src , dest );
// src is now empty
_player -> SwapItem ( parentItem -> GetPos (), src );
}
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_player -> AutoUnequipOffhandIfNeed ();
2016-12-30 20:38:54 +01:00
// if inventory item was moved, check if we can remove dependent auras, because they were not removed in Player::RemoveItem (update was set to false)
// do this after swaps are done, we pass nullptr because both weapons could be swapped and none of them should be ignored
if (( autoEquipItem . PackSlot == INVENTORY_SLOT_BAG_0 && autoEquipItem . Slot < INVENTORY_SLOT_BAG_END ) || ( dstbag == INVENTORY_SLOT_BAG_0 && dstslot < INVENTORY_SLOT_BAG_END ))
_player -> ApplyItemDependentAuras (( Item * ) nullptr , false );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2014-12-21 19:11:39 +01:00
void WorldSession :: HandleDestroyItemOpcode ( WorldPackets :: Item :: DestroyItem & destroyItem )
2008-10-11 14:16:25 -05:00
{
2014-12-30 00:39:51 +01:00
TC_LOG_DEBUG ( "network" , "HandleDestroyItemOpcode: receive ContainerId: %u, SlotNum: %u, Count: %u" ,
destroyItem . ContainerId , destroyItem . SlotNum , destroyItem . Count );
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
uint16 pos = ( destroyItem . ContainerId << 8 ) | destroyItem . SlotNum ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent drop unequipable items (in combat, for example) and non-empty bags
2010-04-07 19:14:10 +02:00
if ( _player -> IsEquipmentPos ( pos ) || _player -> IsBagPos ( pos ))
2008-10-11 14:16:25 -05:00
{
2011-04-29 16:48:15 +06:00
InventoryResult msg = _player -> CanUnequipItem ( pos , false );
2010-04-07 22:59:46 +02:00
if ( msg != EQUIP_ERR_OK )
2008-10-11 14:16:25 -05:00
{
2014-12-30 00:39:51 +01:00
_player -> SendEquipError ( msg , _player -> GetItemByPos ( pos ));
2008-10-11 14:16:25 -05:00
return ;
}
}
2009-10-17 15:51:44 -07:00
2014-12-30 00:39:51 +01:00
Item * item = _player -> GetItemByPos ( destroyItem . ContainerId , destroyItem . SlotNum );
if ( ! item )
2008-10-11 14:16:25 -05:00
{
2014-12-30 00:39:51 +01:00
_player -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2016-09-09 10:22:57 +02:00
if ( item -> GetTemplate () -> GetFlags () & ITEM_FLAG_NO_USER_DESTROY )
2010-07-11 23:53:48 +02:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_DROP_BOUND_ITEM , nullptr , nullptr );
2010-07-11 23:53:48 +02:00
return ;
}
2014-12-30 00:39:51 +01:00
if ( destroyItem . Count )
2008-10-11 14:16:25 -05:00
{
2014-12-30 00:39:51 +01:00
uint32 i_count = destroyItem . Count ;
_player -> DestroyItemCount ( item , i_count , true );
2008-10-11 14:16:25 -05:00
}
else
2014-12-30 00:39:51 +01:00
_player -> DestroyItem ( destroyItem . ContainerId , destroyItem . SlotNum , true );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-04-11 21:05:41 +02:00
void WorldSession :: HandleReadItem ( WorldPackets :: Item :: ReadItem & readItem )
2008-10-11 14:16:25 -05:00
{
2015-04-11 21:05:41 +02:00
Item * item = _player -> GetItemByPos ( readItem . PackSlot , readItem . Slot );
if ( item && item -> GetTemplate () -> GetPageText ())
2008-10-11 14:16:25 -05:00
{
2015-04-11 21:05:41 +02:00
InventoryResult msg = _player -> CanUseItem ( item );
2010-04-07 22:59:46 +02:00
if ( msg == EQUIP_ERR_OK )
2008-10-11 14:16:25 -05:00
{
2015-04-11 21:05:41 +02:00
WorldPackets :: Item :: ReadItemResultOK packet ;
packet . Item = item -> GetGUID ();
SendPacket ( packet . Write ());
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "network" , "STORAGE: Item page sent" );
2008-10-11 14:16:25 -05:00
}
else
{
2015-04-11 21:05:41 +02:00
/// @todo: 6.x research new values
/*WorldPackets::Item::ReadItemResultFailed packet;
packet.Item = item->GetGUID();
packet.Subcode = ??;
packet.Delay = ??;
SendPacket(packet.Write());*/
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "network" , "STORAGE: Unable to read item" );
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( msg , item , nullptr );
2008-10-11 14:16:25 -05:00
}
}
else
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , nullptr , nullptr );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-01-04 20:22:42 +01:00
void WorldSession :: HandleSellItemOpcode ( WorldPackets :: Item :: SellItem & packet )
2008-10-11 14:16:25 -05:00
{
2015-01-04 20:22:42 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: Received CMSG_SELL_ITEM: Vendor %s, Item %s, Amount: %u" ,
packet . VendorGUID . ToString (). c_str (), packet . ItemGUID . ToString (). c_str (), packet . Amount );
2009-10-17 15:51:44 -07:00
2015-01-04 20:22:42 +01:00
if ( packet . ItemGUID . IsEmpty ())
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2019-06-03 20:40:34 +02:00
Creature * creature = GetPlayer () -> GetNPCIfCanInteractWith ( packet . VendorGUID , UNIT_NPC_FLAG_VENDOR , UNIT_NPC_FLAG_2_NONE );
2011-10-07 11:08:09 -05:00
if ( ! creature )
2008-10-11 14:16:25 -05:00
{
2015-01-04 20:22:42 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: HandleSellItemOpcode - %s not found or you can not interact with him." , packet . VendorGUID . ToString (). c_str ());
_player -> SendSellError ( SELL_ERR_CANT_FIND_VENDOR , nullptr , packet . ItemGUID );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2018-03-21 11:05:17 +02:00
if (( creature -> GetCreatureTemplate () -> flags_extra & CREATURE_FLAG_EXTRA_NO_SELL_VENDOR ) != 0 )
{
_player -> SendSellError ( SELL_ERR_CANT_SELL_TO_THIS_MERCHANT , creature , packet . ItemGUID );
return ;
}
2008-10-11 14:16:25 -05:00
// remove fake death
2012-02-03 19:12:41 +02:00
if ( GetPlayer () -> HasUnitState ( UNIT_STATE_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2015-01-04 20:22:42 +01:00
Item * pItem = _player -> GetItemByGuid ( packet . ItemGUID );
2010-04-07 22:59:46 +02:00
if ( pItem )
2008-10-11 14:16:25 -05:00
{
// prevent sell not owner item
2010-04-08 08:20:08 +02:00
if ( _player -> GetGUID () != pItem -> GetOwnerGUID ())
2008-10-11 14:16:25 -05:00
{
2015-01-04 20:22:42 +01:00
_player -> SendSellError ( SELL_ERR_CANT_SELL_ITEM , creature , packet . ItemGUID );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent sell non empty bag by drag-and-drop at vendor's item list
2011-03-18 15:58:08 +06:00
if ( pItem -> IsNotEmptyBag ())
2008-10-11 14:16:25 -05:00
{
2015-01-04 20:22:42 +01:00
_player -> SendSellError ( SELL_ERR_CANT_SELL_ITEM , creature , packet . ItemGUID );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent sell currently looted item
2010-04-07 23:25:02 +02:00
if ( _player -> GetLootGUID () == pItem -> GetGUID ())
2008-10-11 14:16:25 -05:00
{
2015-01-04 20:22:42 +01:00
_player -> SendSellError ( SELL_ERR_CANT_SELL_ITEM , creature , packet . ItemGUID );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-01-24 23:10:08 +01:00
// prevent selling item for sellprice when the item is still refundable
// this probably happens when right clicking a refundable item, the client sends both
// CMSG_SELL_ITEM and CMSG_REFUND_ITEM (unverified)
2019-06-03 20:40:34 +02:00
if ( pItem -> HasItemFlag ( ITEM_FIELD_FLAG_REFUNDABLE ))
2011-01-24 23:10:08 +01:00
return ; // Therefore, no feedback to client
2008-10-11 14:16:25 -05:00
// special case at auto sell (sell all)
2015-01-04 20:22:42 +01:00
if ( packet . Amount == 0 )
packet . Amount = pItem -> GetCount ();
2008-10-11 14:16:25 -05:00
else
{
2008-11-14 16:28:45 -06:00
// prevent sell more items that exist in stack (possible only not from client)
2015-01-04 20:22:42 +01:00
if ( packet . Amount > pItem -> GetCount ())
2008-10-11 14:16:25 -05:00
{
2015-01-04 20:22:42 +01:00
_player -> SendSellError ( SELL_ERR_CANT_SELL_ITEM , creature , packet . ItemGUID );
2008-10-11 14:16:25 -05:00
return ;
}
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
ItemTemplate const * pProto = pItem -> GetTemplate ();
2010-04-07 22:59:46 +02:00
if ( pProto )
2008-10-11 14:16:25 -05:00
{
2014-12-21 13:35:43 +01:00
if ( pProto -> GetSellPrice () > 0 )
2008-10-11 14:16:25 -05:00
{
2017-08-17 02:00:42 -06:00
uint64 money = uint64 ( pProto -> GetSellPrice ()) * packet . Amount ;
if ( ! _player -> ModifyMoney ( money )) // ensure player doesn't exceed gold limit
{
_player -> SendSellError ( SELL_ERR_CANT_SELL_ITEM , creature , packet . ItemGUID );
return ;
}
2021-09-08 22:07:01 +02:00
_player -> UpdateCriteria ( CriteriaType :: MoneyEarnedFromSales , money );
_player -> UpdateCriteria ( CriteriaType :: SellItemsToVendors , 1 );
2017-08-17 02:00:42 -06:00
2015-01-04 20:22:42 +01:00
if ( packet . Amount < pItem -> GetCount ()) // need split items
2008-10-11 14:16:25 -05:00
{
2015-01-04 20:22:42 +01:00
Item * pNewItem = pItem -> CloneItem ( packet . Amount , _player );
2008-10-11 14:16:25 -05:00
if ( ! pNewItem )
{
2015-01-04 20:22:42 +01:00
TC_LOG_ERROR ( "network" , "WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u" , pItem -> GetEntry (), packet . Amount );
_player -> SendSellError ( SELL_ERR_CANT_SELL_ITEM , creature , packet . ItemGUID );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2015-01-04 20:22:42 +01:00
pItem -> SetCount ( pItem -> GetCount () - packet . Amount );
_player -> ItemRemovedQuestCheck ( pItem -> GetEntry (), packet . Amount );
2010-04-07 22:59:46 +02:00
if ( _player -> IsInWorld ())
pItem -> SendUpdateToPlayer ( _player );
2008-10-11 14:16:25 -05:00
pItem -> SetState ( ITEM_CHANGED , _player );
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
_player -> AddItemToBuyBackSlot ( pNewItem );
if ( _player -> IsInWorld ())
pNewItem -> SendUpdateToPlayer ( _player );
2008-10-11 14:16:25 -05:00
}
else
{
2010-04-07 22:59:46 +02:00
_player -> ItemRemovedQuestCheck ( pItem -> GetEntry (), pItem -> GetCount ());
_player -> RemoveItem ( pItem -> GetBagSlot (), pItem -> GetSlot (), true );
2017-06-04 01:00:45 +02:00
RemoveItemFromUpdateQueueOf ( pItem , _player );
2010-04-07 22:59:46 +02:00
_player -> AddItemToBuyBackSlot ( pItem );
2008-10-11 14:16:25 -05:00
}
}
else
2015-01-04 20:22:42 +01:00
_player -> SendSellError ( SELL_ERR_CANT_SELL_ITEM , creature , packet . ItemGUID );
2008-10-11 14:16:25 -05:00
return ;
}
}
2015-01-04 20:22:42 +01:00
_player -> SendSellError ( SELL_ERR_CANT_FIND_ITEM , creature , packet . ItemGUID );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2015-01-04 20:22:42 +01:00
void WorldSession :: HandleBuybackItem ( WorldPackets :: Item :: BuyBackItem & packet )
2008-10-11 14:16:25 -05:00
{
2015-01-04 20:22:42 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: Received CMSG_BUYBACK_ITEM: Vendor %s, Slot: %u" , packet . VendorGUID . ToString (). c_str (), packet . Slot );
2009-10-17 15:51:44 -07:00
2019-06-03 20:40:34 +02:00
Creature * creature = GetPlayer () -> GetNPCIfCanInteractWith ( packet . VendorGUID , UNIT_NPC_FLAG_VENDOR , UNIT_NPC_FLAG_2_NONE );
2011-10-07 11:08:09 -05:00
if ( ! creature )
2008-10-11 14:16:25 -05:00
{
2015-01-04 20:22:42 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: HandleBuybackItem - Unit (%s) not found or you can not interact with him." , packet . VendorGUID . ToString (). c_str ());
2020-08-14 17:06:03 +02:00
_player -> SendSellError ( SELL_ERR_CANT_FIND_VENDOR , nullptr , ObjectGuid :: Empty );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// remove fake death
2012-02-03 19:12:41 +02:00
if ( GetPlayer () -> HasUnitState ( UNIT_STATE_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2015-01-04 20:22:42 +01:00
Item * pItem = _player -> GetItemFromBuyBackSlot ( packet . Slot );
2010-04-07 22:59:46 +02:00
if ( pItem )
2008-10-11 14:16:25 -05:00
{
2019-06-03 20:40:34 +02:00
uint32 price = _player -> m_activePlayerData -> BuybackPrice [ packet . Slot - BUYBACK_SLOT_START ];
2012-07-24 15:27:42 +01:00
if ( ! _player -> HasEnoughMoney ( uint64 ( price )))
2008-10-11 14:16:25 -05:00
{
2011-10-07 11:08:09 -05:00
_player -> SendBuyError ( BUY_ERR_NOT_ENOUGHT_MONEY , creature , pItem -> GetEntry (), 0 );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
ItemPosCountVec dest ;
2011-04-29 16:48:15 +06:00
InventoryResult msg = _player -> CanStoreItem ( NULL_BAG , NULL_SLOT , dest , pItem , false );
2010-04-07 22:59:46 +02:00
if ( msg == EQUIP_ERR_OK )
2008-10-11 14:16:25 -05:00
{
2010-04-07 22:59:46 +02:00
_player -> ModifyMoney ( - ( int32 ) price );
2015-01-04 20:22:42 +01:00
_player -> RemoveItemFromBuyBackSlot ( packet . Slot , false );
2018-04-28 12:40:00 +01:00
_player -> MoveItemToInventory ( dest , pItem , true );
2008-10-11 14:16:25 -05:00
}
else
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( msg , pItem , nullptr );
2008-10-11 14:16:25 -05:00
return ;
}
else
2011-10-07 11:08:09 -05:00
_player -> SendBuyError ( BUY_ERR_CANT_FIND_ITEM , creature , 0 , 0 );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-02-13 00:45:13 +00:00
void WorldSession :: HandleBuyItemOpcode ( WorldPackets :: Item :: BuyItem & packet )
2008-10-11 14:16:25 -05:00
{
2010-04-30 22:35:37 +02:00
// client expects count starting at 1, and we send vendorslot+1 to client already
2015-02-13 00:45:13 +00:00
if ( packet . Muid > 0 )
-- packet . Muid ;
2010-04-30 22:35:37 +02:00
else
return ; // cheating
2012-08-04 19:11:13 +01:00
2015-02-13 00:45:13 +00:00
switch ( packet . ItemType )
2012-08-14 18:11:06 +01:00
{
2015-02-13 00:45:13 +00:00
case ITEM_VENDOR_TYPE_ITEM :
{
Item * bagItem = _player -> GetItemByGuid ( packet . ContainerGUID );
2012-08-04 19:11:13 +01:00
2015-02-13 00:45:13 +00:00
uint8 bag = NULL_BAG ;
if ( bagItem && bagItem -> IsBag ())
bag = bagItem -> GetSlot ();
else if ( packet . ContainerGUID == GetPlayer () -> GetGUID ()) // The client sends the player guid when trying to store an item in the default backpack
bag = INVENTORY_SLOT_BAG_0 ;
2012-08-04 19:11:13 +01:00
2015-02-13 00:45:13 +00:00
GetPlayer () -> BuyItemFromVendorSlot ( packet . VendorGUID , packet . Muid , packet . Item . ItemID ,
packet . Quantity , bag , packet . Slot );
break ;
}
case ITEM_VENDOR_TYPE_CURRENCY :
{
GetPlayer () -> BuyCurrencyFromVendorSlot ( packet . VendorGUID , packet . Muid , packet . Item . ItemID , packet . Quantity );
break ;
}
default :
{
TC_LOG_DEBUG ( "network" , "WORLD: received wrong itemType (%u) in HandleBuyItemOpcode" , packet . ItemType );
break ;
}
2012-08-14 18:11:06 +01:00
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-11-24 20:50:19 +02:00
void WorldSession :: HandleListInventoryOpcode ( WorldPackets :: NPC :: Hello & packet )
2008-10-11 14:16:25 -05:00
{
2013-06-11 19:54:27 -02:30
if ( ! GetPlayer () -> IsAlive ())
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2014-11-24 20:50:19 +02:00
SendListInventory ( packet . Unit );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-09-14 16:14:12 +02:00
void WorldSession :: SendListInventory ( ObjectGuid vendorGuid )
2008-10-11 14:16:25 -05:00
{
2019-06-03 20:40:34 +02:00
Creature * vendor = GetPlayer () -> GetNPCIfCanInteractWith ( vendorGuid , UNIT_NPC_FLAG_VENDOR , UNIT_NPC_FLAG_2_NONE );
2011-06-23 21:24:16 +02:00
if ( ! vendor )
2008-10-11 14:16:25 -05:00
{
2014-09-14 16:14:12 +02:00
TC_LOG_DEBUG ( "network" , "WORLD: SendListInventory - %s not found or you can not interact with him." , vendorGuid . ToString (). c_str ());
2020-08-14 17:06:03 +02:00
_player -> SendSellError ( SELL_ERR_CANT_FIND_VENDOR , nullptr , ObjectGuid :: Empty );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// remove fake death
2012-02-03 19:12:41 +02:00
if ( GetPlayer () -> HasUnitState ( UNIT_STATE_DIED ))
2009-04-06 13:31:14 +02:00
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Stop the npc if moving
2017-08-12 01:40:25 +02:00
vendor -> PauseMovement ( sWorld -> getIntConfig ( CONFIG_CREATURE_STOP_FOR_PLAYER ));
2017-08-12 17:35:46 +02:00
vendor -> SetHomePosition ( vendor -> GetPosition ());
2009-10-17 15:51:44 -07:00
2012-07-24 00:06:49 +01:00
VendorItemData const * vendorItems = vendor -> GetVendorItems ();
2013-07-22 19:52:18 +02:00
uint32 rawItemCount = vendorItems ? vendorItems -> GetItemCount () : 0 ;
2012-01-31 14:02:59 +01:00
2014-11-24 20:50:19 +02:00
WorldPackets :: NPC :: VendorInventory packet ;
packet . Vendor = vendor -> GetGUID ();
2009-10-17 15:51:44 -07:00
2014-11-24 20:50:19 +02:00
packet . Items . resize ( rawItemCount );
2012-07-24 00:59:55 +01:00
2012-07-24 00:06:49 +01:00
const float discountMod = _player -> GetReputationPriceDiscount ( vendor );
2008-10-11 14:16:25 -05:00
uint8 count = 0 ;
2013-07-22 19:52:18 +02:00
for ( uint32 slot = 0 ; slot < rawItemCount ; ++ slot )
2012-07-24 00:06:49 +01:00
{
VendorItem const * vendorItem = vendorItems -> GetItem ( slot );
2013-07-22 19:52:18 +02:00
if ( ! vendorItem )
continue ;
2012-01-31 14:02:59 +01:00
2014-11-24 20:50:19 +02:00
WorldPackets :: NPC :: VendorItem & item = packet . Items [ count ];
2017-10-09 20:03:25 +01:00
if ( PlayerConditionEntry const * playerCondition = sPlayerConditionStore . LookupEntry ( vendorItem -> PlayerConditionId ))
if ( ! ConditionMgr :: IsPlayerMeetingCondition ( _player , playerCondition ))
item . PlayerConditionFailed = playerCondition -> ID ;
2012-08-14 18:11:06 +01:00
if ( vendorItem -> Type == ITEM_VENDOR_TYPE_ITEM )
2012-07-24 00:06:49 +01:00
{
2012-08-14 18:11:06 +01:00
ItemTemplate const * itemTemplate = sObjectMgr -> GetItemTemplate ( vendorItem -> item );
2012-08-27 15:05:43 +02:00
if ( ! itemTemplate )
continue ;
2012-07-24 00:06:49 +01:00
2014-11-24 20:50:19 +02:00
int32 leftInStock = ! vendorItem -> maxcount ? - 1 : vendor -> GetVendorItemCurrentCount ( vendorItem );
2013-06-13 19:35:01 +02:00
if ( ! _player -> IsGameMaster ()) // ignore conditions if GM on
2012-08-14 18:11:06 +01:00
{
// Respect allowed class
2016-09-10 22:20:00 +02:00
if ( ! ( itemTemplate -> GetAllowableClass () & _player -> getClassMask ()) && itemTemplate -> GetBonding () == BIND_ON_ACQUIRE )
2012-08-14 18:11:06 +01:00
continue ;
// Only display items in vendor lists for the team the player is on
2016-09-09 10:22:57 +02:00
if (( itemTemplate -> GetFlags2 () & ITEM_FLAG2_FACTION_HORDE && _player -> GetTeam () == ALLIANCE ) ||
( itemTemplate -> GetFlags2 () & ITEM_FLAG2_FACTION_ALLIANCE && _player -> GetTeam () == HORDE ))
2012-08-14 18:11:06 +01:00
continue ;
// Items sold out are not displayed in list
if ( leftInStock == 0 )
continue ;
}
2012-07-24 00:06:49 +01:00
2015-10-25 13:20:28 +01:00
if ( ! sConditionMgr -> IsObjectMeetingVendorItemConditions ( vendor -> GetEntry (), vendorItem -> item , _player , vendor ))
2012-12-07 09:22:43 +01:00
{
2013-11-08 11:12:17 +01:00
TC_LOG_DEBUG ( "condition" , "SendListInventory: conditions not met for creature entry %u item %u" , vendor -> GetEntry (), vendorItem -> item );
2012-12-07 09:22:43 +01:00
continue ;
}
2012-12-01 01:49:44 +01:00
2014-12-21 13:35:43 +01:00
int32 price = vendorItem -> IsGoldRequired ( itemTemplate ) ? uint32 ( floor ( itemTemplate -> GetBuyPrice () * discountMod )) : 0 ;
2012-09-05 19:01:28 +01:00
2012-09-04 17:52:10 +03:00
if ( int32 priceMod = _player -> GetTotalAuraModifier ( SPELL_AURA_MOD_VENDOR_ITEMS_PRICES ))
2012-10-04 13:33:04 +02:00
price -= CalculatePct ( price , priceMod );
2012-08-14 18:11:06 +01:00
2014-11-24 20:50:19 +02:00
item . MuID = slot + 1 ; // client expects counting to start at 1
item . Durability = itemTemplate -> MaxDurability ;
item . ExtendedCostID = vendorItem -> ExtendedCost ;
item . Type = vendorItem -> Type ;
item . Quantity = leftInStock ;
2014-12-21 13:35:43 +01:00
item . StackCount = itemTemplate -> GetBuyCount ();
2014-11-24 20:50:19 +02:00
item . Price = price ;
2017-10-09 20:03:25 +01:00
item . DoNotFilterOnVendor = vendorItem -> IgnoreFiltering ;
2019-05-18 22:21:17 +02:00
item . Refundable = itemTemplate -> GetFlags () & ITEM_FLAG_ITEM_PURCHASE_RECORD && vendorItem -> ExtendedCost && itemTemplate -> GetMaxStackSize () == 1 ;
2012-08-14 18:11:06 +01:00
2014-11-24 20:50:19 +02:00
item . Item . ItemID = vendorItem -> item ;
2017-10-09 20:03:25 +01:00
if ( ! vendorItem -> BonusListIDs . empty ())
{
item . Item . ItemBonus = boost :: in_place ();
item . Item . ItemBonus -> BonusListIDs = vendorItem -> BonusListIDs ;
}
2012-07-24 00:06:49 +01:00
}
2012-08-14 18:11:06 +01:00
else if ( vendorItem -> Type == ITEM_VENDOR_TYPE_CURRENCY )
{
CurrencyTypesEntry const * currencyTemplate = sCurrencyTypesStore . LookupEntry ( vendorItem -> item );
2012-08-27 15:05:43 +02:00
if ( ! currencyTemplate )
continue ;
2012-08-01 14:31:09 +02:00
2013-07-22 19:52:18 +02:00
if ( ! vendorItem -> ExtendedCost )
2012-08-27 15:05:43 +02:00
continue ; // there's no price defined for currencies, only extendedcost is used
2012-07-24 00:59:55 +01:00
2014-11-24 20:50:19 +02:00
item . MuID = slot + 1 ; // client expects counting to start at 1
item . ExtendedCostID = vendorItem -> ExtendedCost ;
item . Item . ItemID = vendorItem -> item ;
item . Type = vendorItem -> Type ;
item . StackCount = vendorItem -> maxcount ;
2017-10-09 20:03:25 +01:00
item . DoNotFilterOnVendor = vendorItem -> IgnoreFiltering ;
2012-07-24 00:59:55 +01:00
}
2014-11-24 20:50:19 +02:00
else
continue ;
2012-07-24 00:06:49 +01:00
2014-11-24 20:50:19 +02:00
if ( ++ count >= MAX_VENDOR_ITEMS )
break ;
}
2012-07-24 00:06:49 +01:00
2014-11-24 20:50:19 +02:00
// Resize vector to real size (some items can be skipped due to checks)
packet . Items . resize ( count );
2012-07-24 00:06:49 +01:00
2021-10-03 21:50:21 +02:00
packet . Reason = AsUnderlyingType ( count ? VendorInventoryReason :: None : VendorInventoryReason :: Empty );
2014-11-24 20:50:19 +02:00
SendPacket ( packet . Write ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-01-26 12:59:18 +01:00
void WorldSession :: HandleAutoStoreBagItemOpcode ( WorldPackets :: Item :: AutoStoreBagItem & packet )
2008-10-11 14:16:25 -05:00
{
2015-01-26 12:59:18 +01:00
if ( ! packet . Inv . Items . empty ())
2014-12-20 22:29:06 +01:00
{
2015-01-26 12:59:18 +01:00
TC_LOG_ERROR ( "network" , "HandleAutoStoreBagItemOpcode - Invalid itemCount (" SZFMTD ")" , packet . Inv . Items . size ());
2014-12-20 22:29:06 +01:00
return ;
}
2015-01-26 12:59:18 +01:00
TC_LOG_DEBUG ( "network" , "HandleAutoStoreBagItemOpcode: receive ContainerSlotA: %u, SlotA: %u, ContainerSlotB: %u" ,
packet . ContainerSlotA , packet . SlotA , packet . ContainerSlotB );
2009-10-17 15:51:44 -07:00
2015-01-26 12:59:18 +01:00
Item * item = _player -> GetItemByPos ( packet . ContainerSlotA , packet . SlotA );
if ( ! item )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2015-01-26 12:59:18 +01:00
if ( ! _player -> IsValidPos ( packet . ContainerSlotB , NULL_SLOT , false )) // can be autostore pos
2008-11-10 09:04:23 -06:00
{
2015-01-26 12:59:18 +01:00
_player -> SendEquipError ( EQUIP_ERR_WRONG_SLOT );
2008-11-10 09:04:23 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2015-01-26 12:59:18 +01:00
uint16 src = item -> GetPos ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// check unequip potability for equipped items and bank bags
2015-01-26 12:59:18 +01:00
if ( _player -> IsEquipmentPos ( src ) || _player -> IsBagPos ( src ))
2008-10-11 14:16:25 -05:00
{
2015-01-26 12:59:18 +01:00
InventoryResult msg = _player -> CanUnequipItem ( src , ! _player -> IsBagPos ( src ));
2010-04-07 19:14:10 +02:00
if ( msg != EQUIP_ERR_OK )
2008-10-11 14:16:25 -05:00
{
2015-01-26 12:59:18 +01:00
_player -> SendEquipError ( msg , item );
2008-10-11 14:16:25 -05:00
return ;
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
ItemPosCountVec dest ;
2015-01-26 12:59:18 +01:00
InventoryResult msg = _player -> CanStoreItem ( packet . ContainerSlotB , NULL_SLOT , dest , item , false );
2010-04-07 22:59:46 +02:00
if ( msg != EQUIP_ERR_OK )
2008-10-11 14:16:25 -05:00
{
2015-01-26 12:59:18 +01:00
_player -> SendEquipError ( msg , item );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// no-op: placed in same slot
2010-04-07 23:25:02 +02:00
if ( dest . size () == 1 && dest [ 0 ]. pos == src )
2008-10-11 14:16:25 -05:00
{
// just remove grey item state
2015-01-26 12:59:18 +01:00
_player -> SendEquipError ( EQUIP_ERR_INTERNAL_BAG_ERROR , item );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2015-01-26 12:59:18 +01:00
_player -> RemoveItem ( packet . ContainerSlotA , packet . SlotA , true );
_player -> StoreItem ( dest , item , true );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2020-07-02 00:07:38 +02:00
void WorldSession :: SendEnchantmentLog ( ObjectGuid owner , ObjectGuid caster , ObjectGuid itemGuid , uint32 itemId , uint32 enchantId , uint32 enchantSlot )
2008-10-11 14:16:25 -05:00
{
2020-07-02 00:07:38 +02:00
WorldPackets :: Item :: EnchantmentLog enchantmentLog ;
enchantmentLog . Owner = owner ;
enchantmentLog . Caster = caster ;
enchantmentLog . ItemGUID = itemGuid ;
enchantmentLog . ItemID = itemId ;
enchantmentLog . Enchantment = enchantId ;
enchantmentLog . EnchantSlot = enchantSlot ;
GetPlayer () -> SendMessageToSet ( enchantmentLog . Write (), true );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-09-14 16:14:12 +02:00
void WorldSession :: SendItemEnchantTimeUpdate ( ObjectGuid Playerguid , ObjectGuid Itemguid , uint32 slot , uint32 Duration )
2008-10-11 14:16:25 -05:00
{
2015-05-24 22:06:58 +02:00
WorldPackets :: Item :: ItemEnchantTimeUpdate data ;
data . ItemGuid = Itemguid ;
data . DurationLeft = Duration ;
data . Slot = slot ;
data . OwnerGuid = Playerguid ;
SendPacket ( data . Write ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-04-18 23:50:51 +02:00
void WorldSession :: HandleWrapItem ( WorldPackets :: Item :: WrapItem & packet )
2008-10-11 14:16:25 -05:00
{
2015-04-18 23:50:51 +02:00
if ( packet . Inv . Items . size () != 2 )
{
TC_LOG_ERROR ( "network" , "HandleWrapItem - Invalid itemCount (" SZFMTD ")" , packet . Inv . Items . size ());
return ;
}
2009-10-17 15:51:44 -07:00
2015-04-18 23:50:51 +02:00
/// @todo: 6.x find better way for read
// Gift
uint8 giftContainerSlot = packet . Inv . Items [ 0 ]. ContainerSlot ;
uint8 giftSlot = packet . Inv . Items [ 0 ]. Slot ;
// Item
uint8 itemContainerSlot = packet . Inv . Items [ 1 ]. ContainerSlot ;
uint8 itemSlot = packet . Inv . Items [ 1 ]. Slot ;
2009-10-17 15:51:44 -07:00
2015-04-18 23:50:51 +02:00
TC_LOG_DEBUG ( "network" , "HandleWrapItem - Receive giftContainerSlot = %u, giftSlot = %u, itemContainerSlot = %u, itemSlot = %u" , giftContainerSlot , giftSlot , itemContainerSlot , itemSlot );
2009-10-17 15:51:44 -07:00
2015-04-18 23:50:51 +02:00
Item * gift = _player -> GetItemByPos ( giftContainerSlot , giftSlot );
2010-04-07 19:14:10 +02:00
if ( ! gift )
2008-10-11 14:16:25 -05:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , gift , nullptr );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2016-09-09 10:22:57 +02:00
if ( ! ( gift -> GetTemplate () -> GetFlags () & ITEM_FLAG_IS_WRAPPER )) // cheating: non-wrapper wrapper
2008-10-11 14:16:25 -05:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , gift , nullptr );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2015-04-18 23:50:51 +02:00
Item * item = _player -> GetItemByPos ( itemContainerSlot , itemSlot );
2010-04-07 22:59:46 +02:00
if ( ! item )
2008-10-11 14:16:25 -05:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , item , nullptr );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2015-04-18 23:50:51 +02:00
if ( item == gift ) // not possable with pacjket from real client
2008-10-11 14:16:25 -05:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_CANT_WRAP_WRAPPED , item , nullptr );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( item -> IsEquipped ())
2008-10-11 14:16:25 -05:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_CANT_WRAP_EQUIPPED , item , nullptr );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2019-06-03 20:40:34 +02:00
if ( ! item -> GetGiftCreator (). IsEmpty ()) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED);
2008-10-11 14:16:25 -05:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_CANT_WRAP_WRAPPED , item , nullptr );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( item -> IsBag ())
2008-10-11 14:16:25 -05:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_CANT_WRAP_BAGS , item , nullptr );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( item -> IsSoulBound ())
2008-10-11 14:16:25 -05:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_CANT_WRAP_BOUND , item , nullptr );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( item -> GetMaxStackCount () != 1 )
2008-10-11 14:16:25 -05:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_CANT_WRAP_STACKABLE , item , nullptr );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// maybe not correct check (it is better than nothing)
2014-12-21 13:35:43 +01:00
if ( item -> GetTemplate () -> GetMaxCount () > 0 )
2008-10-11 14:16:25 -05:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_CANT_WRAP_UNIQUE , item , nullptr );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2019-07-27 10:52:33 +02:00
CharacterDatabaseTransaction trans = CharacterDatabase . BeginTransaction ();
2012-05-30 08:01:02 +02:00
2019-07-27 01:00:37 +02:00
CharacterDatabasePreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_INS_CHAR_GIFT );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , item -> GetOwnerGUID (). GetCounter ());
stmt -> setUInt64 ( 1 , item -> GetGUID (). GetCounter ());
2012-05-30 08:01:02 +02:00
stmt -> setUInt32 ( 2 , item -> GetEntry ());
2019-06-03 20:40:34 +02:00
stmt -> setUInt32 ( 3 , item -> m_itemData -> DynamicFlags );
2012-05-30 08:01:02 +02:00
trans -> Append ( stmt );
2008-11-20 16:16:57 -06:00
item -> SetEntry ( gift -> GetEntry ());
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
switch ( item -> GetEntry ())
{
2015-04-18 23:50:51 +02:00
case 5042 :
item -> SetEntry ( 5043 );
break ;
case 5048 :
item -> SetEntry ( 5044 );
break ;
case 17303 :
item -> SetEntry ( 17302 );
break ;
case 17304 :
item -> SetEntry ( 17305 );
break ;
case 17307 :
item -> SetEntry ( 17308 );
break ;
case 21830 :
item -> SetEntry ( 21831 );
break ;
2008-10-11 14:16:25 -05:00
}
2015-04-18 23:50:51 +02:00
2019-06-03 20:40:34 +02:00
item -> SetGiftCreator ( _player -> GetGUID ());
item -> SetItemFlags ( ITEM_FIELD_FLAG_WRAPPED );
2008-10-11 14:16:25 -05:00
item -> SetState ( ITEM_CHANGED , _player );
2009-10-17 15:51:44 -07:00
2015-04-18 23:50:51 +02:00
if ( item -> GetState () == ITEM_NEW ) // save new item, to have alway for `character_gifts` record in `item_instance`
2008-10-11 14:16:25 -05:00
{
// after save it will be impossible to remove the item from the queue
2017-06-04 01:00:45 +02:00
RemoveItemFromUpdateQueueOf ( item , _player );
2020-09-04 13:38:24 +02:00
item -> SaveToDB ( trans ); // item gave inventory record unchanged and can be save standalone
2008-10-11 14:16:25 -05:00
}
2010-08-21 03:19:25 +02:00
CharacterDatabase . CommitTransaction ( trans );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 count = 1 ;
_player -> DestroyItemCount ( gift , count , true );
}
2009-10-17 15:51:44 -07:00
2016-01-18 19:52:49 +01:00
void WorldSession :: HandleSocketGems ( WorldPackets :: Item :: SocketGems & socketGems )
2008-10-11 14:16:25 -05:00
{
2016-01-18 19:52:49 +01:00
if ( ! socketGems . ItemGuid )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//cheat -> tried to socket same gem multiple times
2016-01-18 19:52:49 +01:00
if (( ! socketGems . GemItem [ 0 ]. IsEmpty () && ( socketGems . GemItem [ 0 ] == socketGems . GemItem [ 1 ] || socketGems . GemItem [ 0 ] == socketGems . GemItem [ 2 ])) ||
( ! socketGems . GemItem [ 1 ]. IsEmpty () && ( socketGems . GemItem [ 1 ] == socketGems . GemItem [ 2 ])))
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2016-01-18 19:52:49 +01:00
Item * itemTarget = _player -> GetItemByGuid ( socketGems . ItemGuid );
2010-04-07 19:14:10 +02:00
if ( ! itemTarget ) //missing item to socket
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-04-28 22:42:33 +02:00
ItemTemplate const * itemProto = itemTarget -> GetTemplate ();
2010-04-07 19:14:10 +02:00
if ( ! itemProto )
2009-02-03 19:12:17 -06:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//this slot is excepted when applying / removing meta gem bonus
2009-02-24 11:14:28 -06:00
uint8 slot = itemTarget -> IsEquipped () ? itemTarget -> GetSlot () : uint8 ( NULL_SLOT );
2009-10-17 15:51:44 -07:00
2016-07-10 14:41:18 +02:00
Item * gems [ MAX_GEM_SOCKETS ];
memset ( gems , 0 , sizeof ( gems ));
ItemDynamicFieldGems gemData [ MAX_GEM_SOCKETS ];
memset ( gemData , 0 , sizeof ( gemData ));
GemPropertiesEntry const * gemProperties [ MAX_GEM_SOCKETS ];
memset ( gemProperties , 0 , sizeof ( gemProperties ));
2019-06-03 20:40:34 +02:00
UF :: SocketedGem const * oldGemData [ MAX_GEM_SOCKETS ];
2016-07-10 14:41:18 +02:00
memset ( oldGemData , 0 , sizeof ( oldGemData ));
for ( uint32 i = 0 ; i < MAX_GEM_SOCKETS ; ++ i )
{
if ( Item * gem = _player -> GetItemByGuid ( socketGems . GemItem [ i ]))
{
gems [ i ] = gem ;
gemData [ i ]. ItemId = gem -> GetEntry ();
2019-06-03 20:40:34 +02:00
gemData [ i ]. Context = gem -> m_itemData -> Context ;
for ( std :: size_t b = 0 ; b < gem -> m_itemData -> BonusListIDs -> size () && b < 16 ; ++ b )
gemData [ i ]. BonusListIDs [ b ] = ( * gem -> m_itemData -> BonusListIDs )[ b ];
2009-10-17 15:51:44 -07:00
2016-07-10 14:41:18 +02:00
gemProperties [ i ] = sGemPropertiesStore . LookupEntry ( gem -> GetTemplate () -> GetGemProperties ());
}
oldGemData [ i ] = itemTarget -> GetGem ( i );
}
2009-10-17 15:51:44 -07:00
2014-03-10 12:58:03 +01:00
// Find first prismatic socket
2016-07-10 14:41:18 +02:00
uint32 firstPrismatic = 0 ;
2016-01-18 19:52:49 +01:00
while ( firstPrismatic < MAX_GEM_SOCKETS && itemTarget -> GetSocketColor ( firstPrismatic ))
2014-03-10 12:58:03 +01:00
++ firstPrismatic ;
2016-07-10 14:41:18 +02:00
for ( uint32 i = 0 ; i < MAX_GEM_SOCKETS ; ++ i ) //check for hack maybe
2008-10-11 14:16:25 -05:00
{
2016-07-10 14:41:18 +02:00
if ( ! gemProperties [ i ])
2009-02-03 19:12:17 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-02-03 19:12:17 -06:00
// tried to put gem in socket where no socket exists (take care about prismatic sockets)
2016-01-18 19:52:49 +01:00
if ( ! itemTarget -> GetSocketColor ( i ))
2009-02-03 19:12:17 -06:00
{
// no prismatic socket
2010-04-07 19:14:10 +02:00
if ( ! itemTarget -> GetEnchantmentId ( PRISMATIC_ENCHANTMENT_SLOT ))
2009-02-03 19:12:17 -06:00
return ;
2009-10-17 15:51:44 -07:00
2014-03-10 12:58:03 +01:00
if ( i != firstPrismatic )
2009-02-03 19:12:17 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2016-01-24 15:56:10 +01:00
// Gem must match socket color
2016-07-10 14:41:18 +02:00
if ( SocketColorToGemTypeMask [ itemTarget -> GetSocketColor ( i )] != gemProperties [ i ] -> Type )
2016-01-24 15:56:10 +01:00
{
// unless its red, blue, yellow or prismatic
2016-07-10 14:41:18 +02:00
if ( ! ( SocketColorToGemTypeMask [ itemTarget -> GetSocketColor ( i )] & SOCKET_COLOR_PRISMATIC ) || ! ( gemProperties [ i ] -> Type & SOCKET_COLOR_PRISMATIC ))
2016-01-24 15:56:10 +01:00
return ;
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// check unique-equipped conditions
2016-07-10 14:41:18 +02:00
for ( uint32 i = 0 ; i < MAX_GEM_SOCKETS ; ++ i )
2008-10-11 14:16:25 -05:00
{
2016-07-10 14:41:18 +02:00
if ( ! gems [ i ])
2009-02-15 11:58:27 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-02-15 11:58:27 -06:00
// continue check for case when attempt add 2 similar unique equipped gems in one item.
2016-07-10 14:41:18 +02:00
ItemTemplate const * iGemProto = gems [ i ] -> GetTemplate ();
2009-10-17 15:51:44 -07:00
2009-02-15 11:58:27 -06:00
// unique item (for new and already placed bit removed enchantments
2016-09-09 10:22:57 +02:00
if ( iGemProto -> GetFlags () & ITEM_FLAG_UNIQUE_EQUIPPABLE )
2008-10-11 14:16:25 -05:00
{
2016-07-10 14:41:18 +02:00
for ( uint32 j = 0 ; j < MAX_GEM_SOCKETS ; ++ j )
2008-10-11 14:16:25 -05:00
{
2010-04-07 23:25:02 +02:00
if ( i == j ) // skip self
2009-02-15 11:58:27 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2016-07-10 14:41:18 +02:00
if ( gems [ j ])
2008-10-11 14:16:25 -05:00
{
2016-07-10 14:41:18 +02:00
if ( iGemProto -> GetId () == gems [ j ] -> GetEntry ())
2009-02-15 11:58:27 -06:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED , itemTarget , nullptr );
2009-02-15 11:58:27 -06:00
return ;
}
}
2016-07-10 14:41:18 +02:00
else if ( oldGemData [ j ])
2009-02-15 11:58:27 -06:00
{
2019-06-03 20:40:34 +02:00
if ( int32 ( iGemProto -> GetId ()) == oldGemData [ j ] -> ItemID )
2009-02-15 11:58:27 -06:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED , itemTarget , nullptr );
2016-01-24 15:56:10 +01:00
return ;
2009-02-15 11:58:27 -06:00
}
2008-10-11 14:16:25 -05:00
}
}
2009-02-15 11:58:27 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-15 11:58:27 -06:00
// unique limit type item
int32 limit_newcount = 0 ;
2014-12-21 13:35:43 +01:00
if ( iGemProto -> GetItemLimitCategory ())
2009-02-15 11:58:27 -06:00
{
2014-12-21 13:35:43 +01:00
if ( ItemLimitCategoryEntry const * limitEntry = sItemLimitCategoryStore . LookupEntry ( iGemProto -> GetItemLimitCategory ()))
2008-10-11 14:16:25 -05:00
{
2010-08-05 22:08:07 +06:00
// NOTE: limitEntry->mode is not checked because if item has limit then it is applied in equip case
2009-02-15 11:58:27 -06:00
for ( int j = 0 ; j < MAX_GEM_SOCKETS ; ++ j )
{
2016-07-10 14:41:18 +02:00
if ( gems [ j ])
2009-02-15 11:58:27 -06:00
{
// new gem
2016-07-10 14:41:18 +02:00
if ( iGemProto -> GetItemLimitCategory () == gems [ j ] -> GetTemplate () -> GetItemLimitCategory ())
2009-02-15 11:58:27 -06:00
++ limit_newcount ;
}
2016-07-10 14:41:18 +02:00
else if ( oldGemData [ j ])
2009-02-15 11:58:27 -06:00
{
2010-11-08 17:11:05 +01:00
// existing gem
2019-06-03 20:40:34 +02:00
if ( ItemTemplate const * jProto = sObjectMgr -> GetItemTemplate ( oldGemData [ j ] -> ItemID ))
2016-01-24 15:56:10 +01:00
if ( iGemProto -> GetItemLimitCategory () == jProto -> GetItemLimitCategory ())
++ limit_newcount ;
2009-02-15 11:58:27 -06:00
}
}
2009-10-17 15:51:44 -07:00
2018-04-18 16:41:23 +01:00
if ( limit_newcount > 0 && uint32 ( limit_newcount ) > _player -> GetItemLimitCategoryQuantity ( limitEntry ))
2008-10-11 14:16:25 -05:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED , itemTarget , nullptr );
2008-10-11 14:16:25 -05:00
return ;
}
}
2009-02-15 11:58:27 -06:00
}
2009-10-17 15:51:44 -07:00
2009-02-15 11:58:27 -06:00
// for equipped item check all equipment for duplicate equipped gems
2010-04-07 19:14:10 +02:00
if ( itemTarget -> IsEquipped ())
2009-02-15 11:58:27 -06:00
{
2016-07-10 14:41:18 +02:00
if ( InventoryResult res = _player -> CanEquipUniqueItem ( gems [ i ], slot , std :: max ( limit_newcount , 0 )))
2009-02-15 11:58:27 -06:00
{
2020-08-14 17:06:03 +02:00
_player -> SendEquipError ( res , itemTarget , nullptr );
2009-02-15 11:58:27 -06:00
return ;
2008-10-11 14:16:25 -05:00
}
}
}
2009-10-17 15:51:44 -07:00
2009-01-16 14:17:24 -06:00
bool SocketBonusActivated = itemTarget -> GemsFitSockets (); //save state of socketbonus
2008-10-11 14:16:25 -05:00
_player -> ToggleMetaGemsActive ( slot , false ); //turn off all metagems (except for the target item)
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met
2009-10-17 15:51:44 -07:00
2016-08-15 00:03:38 +02:00
//remove ALL mods - gem can change item level
if ( itemTarget -> IsEquipped ())
_player -> _ApplyItemMods ( itemTarget , itemTarget -> GetSlot (), false );
2009-10-17 15:51:44 -07:00
2016-07-10 14:41:18 +02:00
for ( uint16 i = 0 ; i < MAX_GEM_SOCKETS ; ++ i )
2008-10-11 14:16:25 -05:00
{
2016-07-10 14:41:18 +02:00
if ( gems [ i ])
2008-10-11 14:16:25 -05:00
{
2016-12-09 20:00:20 +01:00
uint32 gemScalingLevel = _player -> getLevel ();
2019-10-26 23:58:29 +02:00
if ( uint32 fixedLevel = gems [ i ] -> GetModifier ( ITEM_MODIFIER_TIMEWALKER_LEVEL ))
2016-12-09 20:00:20 +01:00
gemScalingLevel = fixedLevel ;
itemTarget -> SetGem ( i , & gemData [ i ], gemScalingLevel );
2016-01-24 15:56:10 +01:00
2018-03-12 18:20:26 +01:00
if ( gemProperties [ i ] && gemProperties [ i ] -> EnchantId )
itemTarget -> SetEnchantment ( EnchantmentSlot ( SOCK_ENCHANTMENT_SLOT + i ), gemProperties [ i ] -> EnchantId , 0 , 0 , _player -> GetGUID ());
2016-01-24 15:56:10 +01:00
uint32 gemCount = 1 ;
2016-07-10 14:41:18 +02:00
_player -> DestroyItemCount ( gems [ i ], gemCount , true );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2016-08-15 00:03:38 +02:00
if ( itemTarget -> IsEquipped ())
_player -> _ApplyItemMods ( itemTarget , itemTarget -> GetSlot (), true );
if ( Item * childItem = _player -> GetChildItemByGuid ( itemTarget -> GetChildItem ()))
{
if ( childItem -> IsEquipped ())
_player -> _ApplyItemMods ( childItem , childItem -> GetSlot (), false );
childItem -> CopyArtifactDataFromParent ( itemTarget );
if ( childItem -> IsEquipped ())
_player -> _ApplyItemMods ( childItem , childItem -> GetSlot (), true );
}
2009-10-17 15:51:44 -07:00
2009-01-16 14:17:24 -06:00
bool SocketBonusToBeActivated = itemTarget -> GemsFitSockets (); //current socketbonus state
2010-04-07 19:14:10 +02:00
if ( SocketBonusActivated ^ SocketBonusToBeActivated ) //if there was a change...
2008-10-11 14:16:25 -05:00
{
2011-04-29 20:47:02 +02:00
_player -> ApplyEnchantment ( itemTarget , BONUS_ENCHANTMENT_SLOT , false );
2014-12-21 13:35:43 +01:00
itemTarget -> SetEnchantment ( BONUS_ENCHANTMENT_SLOT , ( SocketBonusToBeActivated ? itemTarget -> GetTemplate () -> GetSocketBonus () : 0 ), 0 , 0 , _player -> GetGUID ());
2011-04-29 20:47:02 +02:00
_player -> ApplyEnchantment ( itemTarget , BONUS_ENCHANTMENT_SLOT , true );
2008-10-11 14:16:25 -05:00
//it is not displayed, client has an inbuilt system to determine if the bonus is activated
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_player -> ToggleMetaGemsActive ( slot , true ); //turn on all metagems (except for target item)
2010-09-21 21:55:16 +02:00
2012-06-23 12:31:46 +02:00
_player -> RemoveTradeableItem ( itemTarget );
2011-10-18 10:44:45 +02:00
itemTarget -> ClearSoulboundTradeable ( _player ); // clear tradeable flag
2013-05-25 11:09:21 +02:00
itemTarget -> SendUpdateSockets ();
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-05-01 00:20:41 +02:00
void WorldSession :: HandleCancelTempEnchantmentOpcode ( WorldPackets :: Item :: CancelTempEnchantment & cancelTempEnchantment )
2008-10-11 14:16:25 -05:00
{
// apply only to equipped item
2015-05-01 00:20:41 +02:00
if ( ! Player :: IsEquipmentPos ( INVENTORY_SLOT_BAG_0 , cancelTempEnchantment . Slot ))
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2015-05-01 00:20:41 +02:00
Item * item = GetPlayer () -> GetItemByPos ( INVENTORY_SLOT_BAG_0 , cancelTempEnchantment . Slot );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! item )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! item -> GetEnchantmentId ( TEMP_ENCHANTMENT_SLOT ))
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
GetPlayer () -> ApplyEnchantment ( item , TEMP_ENCHANTMENT_SLOT , false );
2008-10-11 14:16:25 -05:00
item -> ClearEnchantment ( TEMP_ENCHANTMENT_SLOT );
}
2009-02-17 20:07:49 -06:00
2015-02-01 20:52:05 +01:00
void WorldSession :: HandleGetItemPurchaseData ( WorldPackets :: Item :: GetItemPurchaseData & packet )
2009-12-17 11:18:07 +01:00
{
2015-01-04 20:22:42 +01:00
Item * item = _player -> GetItemByGuid ( packet . ItemGUID );
2010-03-18 17:27:40 +01:00
if ( ! item )
2009-12-17 11:18:07 +01:00
{
2015-02-01 20:52:05 +01:00
TC_LOG_DEBUG ( "network" , "HandleGetItemPurchaseData: Item %s not found!" , packet . ItemGUID . ToString (). c_str ());
2009-12-17 11:18:07 +01:00
return ;
}
2015-02-01 20:52:05 +01:00
TC_LOG_DEBUG ( "network" , "HandleGetItemPurchaseData: Item %s" , packet . ItemGUID . ToString (). c_str ());
2010-04-30 19:20:59 +02:00
GetPlayer () -> SendRefundInfo ( item );
2009-12-17 18:35:59 +01:00
}
2016-02-02 01:06:44 +01:00
void WorldSession :: HandleItemRefund ( WorldPackets :: Item :: ItemPurchaseRefund & packet )
2009-12-17 18:35:59 +01:00
{
2016-02-02 01:06:44 +01:00
Item * item = _player -> GetItemByGuid ( packet . ItemGUID );
2010-03-18 17:27:40 +01:00
if ( ! item )
2009-12-17 18:35:59 +01:00
{
2016-02-02 01:06:44 +01:00
TC_LOG_DEBUG ( "network" , "WorldSession::HandleItemRefund: Item (%s) not found!" , packet . ItemGUID . ToString (). c_str ());
2009-12-17 18:35:59 +01:00
return ;
}
2014-06-23 22:40:26 +02:00
// Don't try to refund item currently being disenchanted
2016-02-02 01:06:44 +01:00
if ( _player -> GetLootGUID () == packet . ItemGUID )
2014-06-23 22:40:26 +02:00
return ;
2010-04-30 19:20:59 +02:00
GetPlayer () -> RefundItem ( item );
2009-12-17 11:18:07 +01:00
}
2010-04-14 12:43:42 +04:00
2014-09-14 16:14:12 +02:00
bool WorldSession :: CanUseBank ( ObjectGuid bankerGUID ) const
2014-06-07 22:47:50 +02:00
{
// bankerGUID parameter is optional, set to 0 by default.
if ( ! bankerGUID )
bankerGUID = m_currentBankerGUID ;
bool isUsingBankCommand = ( bankerGUID == GetPlayer () -> GetGUID () && bankerGUID == m_currentBankerGUID );
if ( ! isUsingBankCommand )
{
2019-06-03 20:40:34 +02:00
Creature * creature = GetPlayer () -> GetNPCIfCanInteractWith ( bankerGUID , UNIT_NPC_FLAG_BANKER , UNIT_NPC_FLAG_2_NONE );
2014-06-07 22:47:50 +02:00
if ( ! creature )
return false ;
}
return true ;
2014-06-07 23:40:37 +02:00
}
2015-09-09 14:52:32 +02:00
void WorldSession :: HandleUseCritterItem ( WorldPackets :: Item :: UseCritterItem & useCritterItem )
{
Item * item = _player -> GetItemByGuid ( useCritterItem . ItemGuid );
if ( ! item )
return ;
2020-06-05 00:27:40 +02:00
if ( item -> GetBonus () -> EffectCount < 2 )
2015-09-09 14:52:32 +02:00
return ;
2020-06-05 00:27:40 +02:00
int32 spellToLearn = item -> GetEffect ( 1 ) -> SpellID ;
2020-04-08 13:36:59 +02:00
if ( BattlePetSpeciesEntry const * entry = sSpellMgr -> GetBattlePetSpecies ( uint32 ( spellToLearn )))
2016-04-25 22:03:34 +02:00
{
2021-10-16 12:15:03 +02:00
GetBattlePetMgr () -> AddPet ( entry -> ID , BattlePetMgr :: SelectPetDisplay ( entry ), BattlePetMgr :: RollPetBreed ( entry -> ID ), BattlePetMgr :: GetDefaultPetQuality ( entry -> ID ));
2021-09-08 22:07:01 +02:00
_player -> UpdateCriteria ( CriteriaType :: UniquePetsOwned );
2016-04-25 22:03:34 +02:00
}
2015-09-09 14:52:32 +02:00
_player -> DestroyItem ( item -> GetBagSlot (), item -> GetSlot (), true );
}
2016-06-21 20:33:51 +02:00
2017-07-05 19:12:47 +02:00
void WorldSession :: HandleSortBags ( WorldPackets :: Item :: SortBags & /*sortBags*/ )
{
// TODO: Implement sorting
// Placeholder to prevent completely locking out bags clientside
2020-09-19 12:44:42 +02:00
SendPacket ( WorldPackets :: Item :: BagCleanupFinished (). Write ());
2017-07-05 19:12:47 +02:00
}
void WorldSession :: HandleSortBankBags ( WorldPackets :: Item :: SortBankBags & /*sortBankBags*/ )
{
// TODO: Implement sorting
// Placeholder to prevent completely locking out bags clientside
2020-09-19 12:44:42 +02:00
SendPacket ( WorldPackets :: Item :: BagCleanupFinished (). Write ());
2017-07-05 19:12:47 +02:00
}
void WorldSession :: HandleSortReagentBankBags ( WorldPackets :: Item :: SortReagentBankBags & /*sortReagentBankBags*/ )
{
// TODO: Implement sorting
// Placeholder to prevent completely locking out bags clientside
2020-09-19 12:44:42 +02:00
SendPacket ( WorldPackets :: Item :: BagCleanupFinished (). Write ());
2017-07-05 19:12:47 +02:00
}
2017-09-11 22:35:55 +02:00
void WorldSession :: HandleRemoveNewItem ( WorldPackets :: Item :: RemoveNewItem & removeNewItem )
{
Item * item = _player -> GetItemByGuid ( removeNewItem . ItemGuid );
if ( ! item )
{
TC_LOG_DEBUG ( "network" , "WorldSession::HandleRemoveNewItem: Item (%s) not found for %s!" , removeNewItem . ItemGuid . ToString (). c_str (), GetPlayerInfo (). c_str ());
return ;
}
2019-06-03 20:40:34 +02:00
if ( item -> HasItemFlag ( ITEM_FIELD_FLAG_NEW_ITEM ))
2017-09-11 22:35:55 +02:00
{
2019-06-03 20:40:34 +02:00
item -> RemoveItemFlag ( ITEM_FIELD_FLAG_NEW_ITEM );
2017-09-11 22:35:55 +02:00
item -> SetState ( ITEM_CHANGED , _player );
}
}