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"
2022-12-30 14:08:01 +01:00
#include "GossipDef.h"
2017-05-18 23:52:58 +02:00
#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"
#include "Player.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
{
2023-01-08 21:16:53 +01:00
TC_LOG_ERROR ( "network" , "HandleSplitItemOpcode - Invalid ItemCount ({})" , splitItem . Inv . Items . size ());
2014-12-20 22:29:06 +01:00
return ;
}
2009-10-17 15:51:44 -07:00
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleSplitItemOpcode: receive FromPackSlot: {}, FromSlot: {}, ToPackSlot: {}, ToSlot: {}, Quantity: {}" ,
2014-12-30 00:39:51 +01:00
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
{
2023-01-08 21:16:53 +01:00
TC_LOG_ERROR ( "network" , "HandleSwapInvItemOpcode - Invalid itemCount ({})" , swapInvItem . Inv . Items . size ());
2014-12-20 22:29:06 +01:00
return ;
}
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleSwapInvItemOpcode: receive Slot1: {}, Slot2: {}" ,
2014-12-30 00:39:51 +01:00
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
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleSwapInvItemOpcode - Unit ({}) not found or you can't interact with him." , _player -> PlayerTalkClass -> GetInteractionData (). SourceGuid . ToString ());
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
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleSwapInvItemOpcode - Unit ({}) not found or you can't interact with him." , _player -> PlayerTalkClass -> GetInteractionData (). SourceGuid . ToString ());
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
{
2023-01-08 21:16:53 +01:00
TC_LOG_ERROR ( "network" , "HandleSwapItem - Invalid itemCount ({})" , swapItem . Inv . Items . size ());
2014-12-20 17:25:15 +01:00
return ;
}
2014-12-20 22:29:06 +01:00
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleSwapItem: receive ContainerSlotA: {}, SlotA: {}, ContainerSlotB: {}, SlotB: {}" ,
2014-12-30 00:39:51 +01:00
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
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleSwapItem - Unit ({}) not found or you can't interact with him." , _player -> PlayerTalkClass -> GetInteractionData (). SourceGuid . ToString ());
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
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleSwapItem - Unit ({}) not found or you can't interact with him." , _player -> PlayerTalkClass -> GetInteractionData (). SourceGuid . ToString ());
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
{
2023-01-08 21:16:53 +01:00
TC_LOG_ERROR ( "network" , "HandleAutoEquipItemOpcode - Invalid itemCount ({})" , autoEquipItem . Inv . Items . size ());
2014-12-20 17:25:15 +01:00
return ;
}
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleAutoEquipItemOpcode: receive PackSlot: {}, Slot: {}" ,
2014-12-30 00:39:51 +01:00
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
2024-05-13 00:30:31 +02:00
if (( autoEquipItem . PackSlot == INVENTORY_SLOT_BAG_0 && autoEquipItem . Slot < REAGENT_BAG_SLOT_END ) || ( dstbag == INVENTORY_SLOT_BAG_0 && dstslot < REAGENT_BAG_SLOT_END ))
2016-12-30 20:38:54 +01:00
_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
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleDestroyItemOpcode: receive ContainerId: {}, SlotNum: {}, Count: {}" ,
2014-12-30 00:39:51 +01:00
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
2020-02-01 17:45:58 +04:00
if ( item -> GetTemplate () -> HasFlag ( 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 )
2026-05-24 21:30:08 +02:00
_player -> DestroyItemCount ( item , destroyItem . 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
2026-03-01 15:45:26 +01:00
void WorldSession :: HandleSellItemOpcode ( WorldPackets :: Item :: SellItem const & sellItem )
2008-10-11 14:16:25 -05:00
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: Received CMSG_SELL_ITEM: Vendor {}, Item {}, Amount: {}" ,
2026-03-01 15:45:26 +01:00
sellItem . VendorGUID , sellItem . ItemGUID , sellItem . Amount );
2009-10-17 15:51:44 -07:00
2026-03-01 15:45:26 +01:00
Creature * creature = GetPlayer () -> GetNPCIfCanInteractWith ( sellItem . 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
{
2026-03-01 15:45:26 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: HandleSellItemOpcode - {} not found or you can not interact with him." , sellItem . VendorGUID );
_player -> SendSellError ( SELL_ERR_CANT_FIND_VENDOR , nullptr , sellItem . 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 )
{
2026-03-01 15:45:26 +01:00
_player -> SendSellError ( SELL_ERR_CANT_SELL_TO_THIS_MERCHANT , creature , sellItem . ItemGUID );
2018-03-21 11:05:17 +02:00
return ;
}
2026-03-01 15:45:26 +01:00
Item * pItem = _player -> GetItemByGuid ( sellItem . ItemGUID );
if ( ! pItem )
2008-10-11 14:16:25 -05:00
{
2026-03-01 15:45:26 +01:00
_player -> SendSellError ( SELL_ERR_CANT_FIND_ITEM , creature , sellItem . ItemGUID );
return ;
}
2017-08-17 02:00:42 -06:00
2026-03-01 15:45:26 +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)
if ( pItem -> IsRefundable ())
return ;
2024-05-12 14:31:49 +02:00
2026-03-01 15:45:26 +01:00
// remove fake death
if ( GetPlayer () -> HasUnitState ( UNIT_STATE_DIED ))
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
2024-05-12 14:31:49 +02:00
2026-03-01 15:45:26 +01:00
uint32 amount = sellItem . Amount ? sellItem . Amount : pItem -> GetCount ();
2017-08-17 02:00:42 -06:00
2026-03-01 15:45:26 +01:00
Optional < SellResult > sellResult = _player -> CanSellItemToVendor ( pItem , amount );
if ( ! sellResult )
sellResult = _player -> SellItemToVendor ( pItem , amount );
2017-08-17 02:00:42 -06:00
2026-03-01 15:45:26 +01:00
if ( sellResult )
_player -> SendSellError ( * sellResult , creature , sellItem . ItemGUID );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2026-02-12 22:12:40 +01:00
void WorldSession :: HandleSellAllJunkItems ( WorldPackets :: Item :: SellAllJunkItems const & sellAllJunkItems )
{
Creature * creature = GetPlayer () -> GetNPCIfCanInteractWith ( sellAllJunkItems . VendorGUID , UNIT_NPC_FLAG_VENDOR , UNIT_NPC_FLAG_2_NONE );
if ( ! creature )
{
_player -> SendSellError ( SELL_ERR_CANT_FIND_VENDOR , nullptr , ObjectGuid :: Empty );
return ;
}
if (( creature -> GetCreatureTemplate () -> flags_extra & CREATURE_FLAG_EXTRA_NO_SELL_VENDOR ) != 0 )
{
_player -> SendSellError ( SELL_ERR_CANT_SELL_TO_THIS_MERCHANT , creature , ObjectGuid :: Empty );
return ;
}
2026-03-01 16:56:03 +01:00
// remove fake death
if ( GetPlayer () -> HasUnitState ( UNIT_STATE_DIED ))
GetPlayer () -> RemoveAurasByType ( SPELL_AURA_FEIGN_DEATH );
// collect junk items first
2026-02-12 22:12:40 +01:00
std :: vector < Item *> junkItems ;
_player -> ForEachItem ( ItemSearchLocation :: Inventory , [ this , & junkItems ]( Item * item )
{
if ( item -> GetQuality () != ITEM_QUALITY_POOR )
return ItemSearchCallbackResult :: Continue ;
if ( item -> IsRefundable ())
return ItemSearchCallbackResult :: Continue ;
// check per-bag junk sell exclusion
if ( item -> GetBagSlot () == INVENTORY_SLOT_BAG_0 )
{
if ( _player -> IsBackpackSellJunkDisabled ())
return ItemSearchCallbackResult :: Continue ;
}
else
{
uint32 bagIndex = item -> GetBagSlot () - INVENTORY_SLOT_BAG_START ;
if ( bagIndex < _player -> m_activePlayerData -> BagSlotFlags . size ()
&& _player -> GetBagSlotFlags ( bagIndex ). HasFlag ( BagSlotFlags :: ExcludeJunkSell ))
return ItemSearchCallbackResult :: Continue ;
}
2026-03-01 16:56:03 +01:00
Optional < SellResult > sellError = _player -> CanSellItemToVendor ( item , item -> GetCount ());
if ( ! sellError )
junkItems . push_back ( item );
2026-02-12 22:12:40 +01:00
return ItemSearchCallbackResult :: Continue ;
});
2026-03-01 16:56:03 +01:00
auto itr = junkItems . begin ();
auto end = junkItems . end ();
Optional < SellResult > sellError ;
2026-02-12 22:12:40 +01:00
2026-03-01 16:56:03 +01:00
// stop on first sell failure (gold cap reached)
for (; itr != end && ! sellError ; ++ itr )
sellError = _player -> SellItemToVendor ( * itr , ( * itr ) -> GetCount ());
2026-02-12 22:12:40 +01:00
}
2015-01-04 20:22:42 +01:00
void WorldSession :: HandleBuybackItem ( WorldPackets :: Item :: BuyBackItem & packet )
2008-10-11 14:16:25 -05:00
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: Received CMSG_BUYBACK_ITEM: Vendor {}, Slot: {}" , packet . VendorGUID . ToString (), 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
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: HandleBuybackItem - Unit ({}) not found or you can not interact with him." , packet . VendorGUID . ToString ());
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 );
2019-07-17 20:48:21 +02:00
_player -> ItemAddedQuestCheck ( pItem -> GetEntry (), pItem -> GetCount ());
_player -> StoreItem ( 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 :
{
uint8 bag = NULL_BAG ;
2025-02-02 23:59:23 +01:00
if ( packet . ContainerGUID == GetPlayer () -> GetGUID ()) // The client sends the player guid when trying to store an item in the default backpack
2015-02-13 00:45:13 +00:00
bag = INVENTORY_SLOT_BAG_0 ;
2025-02-02 23:59:23 +01:00
else if ( Item * bagItem = _player -> GetItemByGuid ( packet . ContainerGUID ))
bag = bagItem -> GetSlot ();
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 :
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: received wrong itemType ({}) in HandleBuyItemOpcode" , packet . ItemType );
2015-02-13 00:45:13 +00:00
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
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: SendListInventory - {} not found or you can not interact with him." , vendorGuid . ToString ());
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
2025-07-05 22:34:45 +02:00
GetPlayer () -> PlayerTalkClass -> GetInteractionData (). StartInteraction ( vendorGuid , PlayerInteractionType :: Vendor );
2008-10-11 14:16:25 -05:00
// Stop the npc if moving
2021-01-22 19:48:50 +01:00
if ( uint32 pause = vendor -> GetMovementTemplate (). GetInteractionPauseTimer ())
vendor -> PauseMovement ( pause );
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 ];
2024-03-27 21:38:08 +01:00
if ( ! ConditionMgr :: IsPlayerMeetingCondition ( _player , vendorItem -> PlayerConditionId ))
item . PlayerConditionFailed = vendorItem -> PlayerConditionId ;
2017-10-09 20:03:25 +01:00
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
2026-05-18 00:28:59 +02:00
int32 leftInStock = ! vendorItem -> maxcount ? - 1 : int32 ( 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
2019-07-01 21:36:32 +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
2020-02-01 17:45:58 +04:00
if (( itemTemplate -> HasFlag ( ITEM_FLAG2_FACTION_HORDE ) && _player -> GetTeam () == ALLIANCE ) ||
( itemTemplate -> HasFlag ( 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
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "condition" , "SendListInventory: conditions not met for creature entry {} item {}" , vendor -> GetEntry (), vendorItem -> item );
2012-12-07 09:22:43 +01:00
continue ;
}
2012-12-01 01:49:44 +01:00
2026-04-22 20:20:11 +02:00
uint64 basePrice = itemTemplate -> GetBuyPrice ();
if ( ItemExtendedCostEntry const * iece = sItemExtendedCostStore . LookupEntry ( vendorItem -> ExtendedCost ))
basePrice = iece -> Money ;
uint64 price = uint64 ( floor ( basePrice * discountMod ));
2012-09-05 19:01:28 +01:00
2026-04-08 18:40:58 +02:00
if ( float 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
2026-04-22 20:20:11 +02:00
if ( basePrice > 0 )
price = std :: max ( uint64 ( 1 ), price );
2014-11-24 20:50:19 +02:00
item . MuID = slot + 1 ; // client expects counting to start at 1
item . Type = vendorItem -> Type ;
item . Item . ItemID = vendorItem -> item ;
2017-10-09 20:03:25 +01:00
if ( ! vendorItem -> BonusListIDs . empty ())
{
2022-01-23 20:31:52 +01:00
item . Item . ItemBonus . emplace ();
2017-10-09 20:03:25 +01:00
item . Item . ItemBonus -> BonusListIDs = vendorItem -> BonusListIDs ;
}
2026-05-18 00:28:59 +02:00
item . Quantity = leftInStock ;
item . Price = price ;
item . StackCount = itemTemplate -> GetBuyCount ();
item . ExtendedCostID = vendorItem -> ExtendedCost ;
item . DoNotFilterOnVendor = vendorItem -> IgnoreFiltering ;
item . Refundable = itemTemplate -> HasFlag ( ITEM_FLAG_ITEM_PURCHASE_RECORD ) && vendorItem -> ExtendedCost && itemTemplate -> GetMaxStackSize () == 1 ;
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 . Type = vendorItem -> Type ;
2026-05-18 00:28:59 +02:00
item . Item . ItemID = vendorItem -> item ;
2014-11-24 20:50:19 +02:00
item . StackCount = vendorItem -> maxcount ;
2026-05-18 00:28:59 +02:00
item . ExtendedCostID = vendorItem -> ExtendedCost ;
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
{
2023-01-08 21:16:53 +01:00
TC_LOG_ERROR ( "network" , "HandleAutoStoreBagItemOpcode - Invalid itemCount ({})" , packet . Inv . Items . size ());
2014-12-20 22:29:06 +01:00
return ;
}
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleAutoStoreBagItemOpcode: receive ContainerSlotA: {}, SlotA: {}, ContainerSlotB: {}" ,
2015-01-26 12:59:18 +01:00
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 )
{
2023-01-08 21:16:53 +01:00
TC_LOG_ERROR ( "network" , "HandleWrapItem - Invalid itemCount ({})" , packet . Inv . Items . size ());
2015-04-18 23:50:51 +02:00
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
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleWrapItem - Receive giftContainerSlot = {}, giftSlot = {}, itemContainerSlot = {}, itemSlot = {}" , 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
2020-02-01 17:45:58 +04:00
if ( ! gift -> GetTemplate () -> HasFlag ( 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 ())
{
2024-05-12 18:19:17 +02:00
case ITEM_RED_RIBBONED_WRAPPING_PAPER :
item -> SetEntry ( ITEM_RED_RIBBONED_GIFT );
2015-04-18 23:50:51 +02:00
break ;
2024-05-12 18:19:17 +02:00
case ITEM_BLUE_RIBBONED_WRAPPING_PAPER :
item -> SetEntry ( ITEM_BLUE_RIBBONED_GIFT );
2015-04-18 23:50:51 +02:00
break ;
2024-05-12 18:19:17 +02:00
case ITEM_BLUE_RIBBONED_HOLIDAY_WRAPPING_PAPER :
item -> SetEntry ( ITEM_BLUE_RIBBONED_HOLIDAY_GIFT );
2015-04-18 23:50:51 +02:00
break ;
2024-05-12 18:19:17 +02:00
case ITEM_GREEN_RIBBONED_WRAPPING_PAPER :
item -> SetEntry ( ITEM_GREEN_RIBBONED_HOLIDAY_GIFT );
2015-04-18 23:50:51 +02:00
break ;
2024-05-12 18:19:17 +02:00
case ITEM_PURPLE_RIBBONED_WRAPPING_PAPER :
item -> SetEntry ( ITEM_PURPLE_RIBBONED_HOLIDAY_GIFT );
2015-04-18 23:50:51 +02:00
break ;
2024-05-12 18:19:17 +02:00
case ITEM_EMPTY_WRAPPER :
item -> SetEntry ( ITEM_WRAPPED_GIFT );
break ;
default :
2015-04-18 23:50:51 +02:00
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 ());
2022-03-26 18:59:44 +01:00
item -> ReplaceAllItemFlags ( 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 ;
2022-12-04 15:13:20 +01:00
for ( std :: size_t b = 0 ; b < gem -> GetBonusListIDs (). size () && b < 16 ; ++ b )
gemData [ i ]. BonusListIDs [ b ] = gem -> GetBonusListIDs ()[ 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
2025-04-26 12:17:25 +02:00
uint32 acceptableGemTypeMask = SocketColorToGemTypeMask [ itemTarget -> GetSocketColor ( i )];
2009-02-03 19:12:17 -06:00
// tried to put gem in socket where no socket exists (take care about prismatic sockets)
2025-04-26 12:17:25 +02:00
switch ( itemTarget -> GetSocketColor ( i ))
2009-02-03 19:12:17 -06:00
{
2025-04-26 12:17:25 +02:00
case 0 :
{
// no prismatic socket
if ( ! itemTarget -> GetEnchantmentId ( PRISMATIC_ENCHANTMENT_SLOT ))
return ;
2009-10-17 15:51:44 -07:00
2025-04-26 12:17:25 +02:00
if ( i != firstPrismatic )
return ;
acceptableGemTypeMask = SOCKET_COLOR_RED | SOCKET_COLOR_YELLOW | SOCKET_COLOR_BLUE ;
break ;
}
case 2 :
case 3 :
case 4 :
// red, blue and yellow sockets accept any red/blue/yellow gem
acceptableGemTypeMask = SOCKET_COLOR_RED | SOCKET_COLOR_YELLOW | SOCKET_COLOR_BLUE ;
break ;
default :
break ;
2009-02-03 19:12:17 -06:00
}
2009-10-17 15:51:44 -07:00
2016-01-24 15:56:10 +01:00
// Gem must match socket color
2025-04-26 12:17:25 +02:00
if ( ! ( acceptableGemTypeMask & gemProperties [ i ] -> Type ))
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
2020-02-01 17:45:58 +04:00
if ( iGemProto -> HasFlag ( 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 ;
2025-10-05 15:13:57 +02:00
if ( gems [ i ] -> GetItemLimitCategory ())
2009-02-15 11:58:27 -06:00
{
2025-10-05 15:13:57 +02:00
if ( ItemLimitCategoryEntry const * limitEntry = sItemLimitCategoryStore . LookupEntry ( gems [ i ] -> GetItemLimitCategory ()))
2008-10-11 14:16:25 -05:00
{
2020-07-12 15:36:55 +02:00
// NOTE: limitEntry->Flags 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
2025-10-05 15:13:57 +02:00
if ( gems [ i ] -> GetItemLimitCategory () == gems [ j ] -> 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 ))
2025-10-05 15:13:57 +02:00
{
BonusData oldGemBonus ;
oldGemBonus . Initialize ( jProto );
for ( uint16 bonusListID : oldGemData [ j ] -> BonusListIDs )
oldGemBonus . AddBonusList ( bonusListID );
if ( gems [ i ] -> GetItemLimitCategory () == oldGemBonus . LimitCategory )
2016-01-24 15:56:10 +01:00
++ limit_newcount ;
2025-10-05 15:13:57 +02:00
}
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
{
2019-07-01 21:36:32 +02: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
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleGetItemPurchaseData: Item {} not found!" , packet . ItemGUID . ToString ());
2009-12-17 11:18:07 +01:00
return ;
}
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "HandleGetItemPurchaseData: Item {}" , packet . ItemGUID . ToString ());
2015-02-01 20:52:05 +01:00
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
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "WorldSession::HandleItemRefund: Item ({}) not found!" , packet . ItemGUID . ToString ());
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 )
2022-12-30 14:08:01 +01:00
bankerGUID = _player -> PlayerTalkClass -> GetInteractionData (). SourceGuid ;
2014-06-07 22:47:50 +02:00
2022-12-30 14:08:01 +01:00
bool isUsingBankCommand = ( bankerGUID == GetPlayer () -> GetGUID () && bankerGUID == _player -> PlayerTalkClass -> GetInteractionData (). SourceGuid );
2014-06-07 22:47:50 +02:00
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 ;
2021-10-16 13:22:42 +02:00
for ( ItemEffectEntry const * itemEffect : item -> GetEffects ())
{
2022-04-22 20:57:05 +02:00
if ( itemEffect -> TriggerType != ITEM_SPELLTRIGGER_ON_LEARN )
2021-10-16 13:22:42 +02:00
continue ;
2020-04-08 13:36:59 +02:00
2022-06-09 13:58:54 +02:00
if ( BattlePetSpeciesEntry const * speciesEntry = BattlePets :: BattlePetMgr :: GetBattlePetSpeciesBySpell ( uint32 ( itemEffect -> SpellID )))
2021-12-17 14:05:01 +01:00
GetBattlePetMgr () -> AddPet ( speciesEntry -> ID , BattlePets :: BattlePetMgr :: SelectPetDisplay ( speciesEntry ),
BattlePets :: BattlePetMgr :: RollPetBreed ( speciesEntry -> ID ), BattlePets :: BattlePetMgr :: GetDefaultPetQuality ( speciesEntry -> ID ));
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
2024-08-02 13:25:41 +02:00
void WorldSession :: HandleSortAccountBankBags ( WorldPackets :: Item :: SortAccountBankBags & /*sortAccountBankBags*/ )
{
// TODO: Implement sorting
// Placeholder to prevent completely locking out bags clientside
SendPacket ( WorldPackets :: Item :: BagCleanupFinished (). Write ());
}
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
}
2017-09-11 22:35:55 +02:00
void WorldSession :: HandleRemoveNewItem ( WorldPackets :: Item :: RemoveNewItem & removeNewItem )
{
Item * item = _player -> GetItemByGuid ( removeNewItem . ItemGuid );
if ( ! item )
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "network" , "WorldSession::HandleRemoveNewItem: Item ({}) not found for {}!" , removeNewItem . ItemGuid . ToString (), GetPlayerInfo ());
2017-09-11 22:35:55 +02:00
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 );
}
}
2024-04-29 00:06:02 +02:00
void WorldSession :: HandleChangeBagSlotFlag ( WorldPackets :: Item :: ChangeBagSlotFlag const & changeBagSlotFlag )
{
if ( changeBagSlotFlag . BagIndex >= _player -> m_activePlayerData -> BagSlotFlags . size ())
return ;
if ( changeBagSlotFlag . On )
_player -> SetBagSlotFlag ( changeBagSlotFlag . BagIndex , changeBagSlotFlag . FlagToChange );
else
_player -> RemoveBagSlotFlag ( changeBagSlotFlag . BagIndex , changeBagSlotFlag . FlagToChange );
}
void WorldSession :: HandleSetBackpackAutosortDisabled ( WorldPackets :: Item :: SetBackpackAutosortDisabled const & setBackpackAutosortDisabled )
{
_player -> SetBackpackAutoSortDisabled ( setBackpackAutosortDisabled . Disable );
}
void WorldSession :: HandleSetBackpackSellJunkDisabled ( WorldPackets :: Item :: SetBackpackSellJunkDisabled const & setBackpackSellJunkDisabled )
{
_player -> SetBackpackSellJunkDisabled ( setBackpackSellJunkDisabled . Disable );
}
void WorldSession :: HandleSetBankAutosortDisabled ( WorldPackets :: Item :: SetBankAutosortDisabled const & setBankAutosortDisabled )
{
_player -> SetBankAutoSortDisabled ( setBankAutosortDisabled . Disable );
}