2008-10-11 14:16:25 -05:00
/*
2009-02-04 12:42:26 +01:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2010-01-16 20:19:18 +03:00
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
2008-10-11 14:16:25 -05: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
2008-10-14 11:57:03 -05:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-11 14:16:25 -05:00
* 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, write to the Free Software
2008-10-14 11:57:03 -05:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-11 14:16:25 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
#include "Common.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "World.h"
#include "ObjectAccessor.h"
#include "Log.h"
#include "Opcodes.h"
#include "Player.h"
#include "Item.h"
#include "SocialMgr.h"
#include "Language.h"
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
enum TradeStatus
{
TRADE_STATUS_BUSY = 0 ,
TRADE_STATUS_BEGIN_TRADE = 1 ,
TRADE_STATUS_OPEN_WINDOW = 2 ,
TRADE_STATUS_TRADE_CANCELED = 3 ,
TRADE_STATUS_TRADE_ACCEPT = 4 ,
TRADE_STATUS_BUSY_2 = 5 ,
TRADE_STATUS_NO_TARGET = 6 ,
TRADE_STATUS_BACK_TO_TRADE = 7 ,
TRADE_STATUS_TRADE_COMPLETE = 8 ,
// 9?
TRADE_STATUS_TARGET_TO_FAR = 10 ,
TRADE_STATUS_WRONG_FACTION = 11 ,
TRADE_STATUS_CLOSE_WINDOW = 12 ,
// 13?
TRADE_STATUS_IGNORE_YOU = 14 ,
TRADE_STATUS_YOU_STUNNED = 15 ,
TRADE_STATUS_TARGET_STUNNED = 16 ,
TRADE_STATUS_YOU_DEAD = 17 ,
TRADE_STATUS_TARGET_DEAD = 18 ,
TRADE_STATUS_YOU_LOGOUT = 19 ,
TRADE_STATUS_TARGET_LOGOUT = 20 ,
TRADE_STATUS_TRIAL_ACCOUNT = 21 , // Trial accounts can not perform that action
TRADE_STATUS_ONLY_CONJURED = 22 // You can only trade conjured items... (cross realm BG related).
};
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: SendTradeStatus ( uint32 status )
{
WorldPacket data ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
switch ( status )
{
case TRADE_STATUS_BEGIN_TRADE :
data . Initialize ( SMSG_TRADE_STATUS , 4 + 8 );
data << uint32 ( status );
data << uint64 ( 0 );
break ;
case TRADE_STATUS_OPEN_WINDOW :
data . Initialize ( SMSG_TRADE_STATUS , 4 + 4 );
data << uint32 ( status );
data << uint32 ( 0 ); // added in 2.4.0
break ;
case TRADE_STATUS_CLOSE_WINDOW :
data . Initialize ( SMSG_TRADE_STATUS , 4 + 4 + 1 + 4 );
data << uint32 ( status );
data << uint32 ( 0 );
data << uint8 ( 0 );
data << uint32 ( 0 );
break ;
case TRADE_STATUS_ONLY_CONJURED :
data . Initialize ( SMSG_TRADE_STATUS , 4 + 1 );
data << uint32 ( status );
data << uint8 ( 0 );
break ;
default :
data . Initialize ( SMSG_TRADE_STATUS , 4 );
data << uint32 ( status );
break ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleIgnoreTradeOpcode ( WorldPacket & /*recvPacket*/ )
{
sLog . outDebug ( "WORLD: Ignore Trade %u" , _player -> GetGUIDLow ());
// recvPacket.print_storage();
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleBusyTradeOpcode ( WorldPacket & /*recvPacket*/ )
{
sLog . outDebug ( "WORLD: Busy Trade %u" , _player -> GetGUIDLow ());
// recvPacket.print_storage();
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: SendUpdateTrade ()
{
Item * item = NULL ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( ! _player || ! _player -> pTrader )
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// reset trade status
if ( _player -> acceptTrade )
{
_player -> acceptTrade = false ;
SendTradeStatus ( TRADE_STATUS_BACK_TO_TRADE );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( _player -> pTrader -> acceptTrade )
{
_player -> pTrader -> acceptTrade = false ;
_player -> pTrader -> GetSession () -> SendTradeStatus ( TRADE_STATUS_BACK_TO_TRADE );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_TRADE_STATUS_EXTENDED , ( 100 )); // guess size
data << ( uint8 ) 1 ; // can be different (only seen 0 and 1)
data << ( uint32 ) 0 ; // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?)
data << ( uint32 ) TRADE_SLOT_COUNT ; // trade slots count/number?, = next field in most cases
data << ( uint32 ) TRADE_SLOT_COUNT ; // trade slots count/number?, = prev field in most cases
data << ( uint32 ) _player -> pTrader -> tradeGold ; // trader gold
data << ( uint32 ) 0 ; // spell casted on lowest slot item
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( uint8 i = 0 ; i < TRADE_SLOT_COUNT ; ++ i )
2008-10-11 14:16:25 -05:00
{
2010-02-15 13:55:16 +01:00
item = ( _player -> pTrader -> tradeItems [ i ] != 0 ? _player -> pTrader -> GetItemByGuid ( _player -> pTrader -> tradeItems [ i ] ) : NULL );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data << ( uint8 ) i ; // trade slot number, if not specified, then end of packet
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( item )
{
data << ( uint32 ) item -> GetProto () -> ItemId ; // entry
// display id
data << ( uint32 ) item -> GetProto () -> DisplayInfoID ;
// stack count
data << ( uint32 ) item -> GetUInt32Value ( ITEM_FIELD_STACK_COUNT );
data << ( uint32 ) 0 ; // probably gift=1, created_by=0?
// gift creator
data << ( uint64 ) item -> GetUInt64Value ( ITEM_FIELD_GIFTCREATOR );
data << ( uint32 ) item -> GetEnchantmentId ( PERM_ENCHANTMENT_SLOT );
2009-10-17 16:20:24 -07:00
for ( uint8 j = 0 ; j < 3 ; ++ j )
2008-10-11 14:16:25 -05:00
data << ( uint32 ) 0 ; // enchantment id (permanent/gems?)
// creator
data << ( uint64 ) item -> GetUInt64Value ( ITEM_FIELD_CREATOR );
data << ( uint32 ) item -> GetSpellCharges (); // charges
data << ( uint32 ) item -> GetItemSuffixFactor (); // SuffixFactor
// random properties id
2009-12-21 14:48:30 -07:00
data << ( int32 ) item -> GetItemRandomPropertyId ();
2008-10-11 14:16:25 -05:00
data << ( uint32 ) item -> GetProto () -> LockID ; // lock id
// max durability
data << ( uint32 ) item -> GetUInt32Value ( ITEM_FIELD_MAXDURABILITY );
// durability
data << ( uint32 ) item -> GetUInt32Value ( ITEM_FIELD_DURABILITY );
}
else
{
2009-10-17 16:20:24 -07:00
for ( uint8 j = 0 ; j < 18 ; j ++ )
2008-10-11 14:16:25 -05:00
data << uint32 ( 0 );
}
}
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//==============================================================
// transfer the items to the players
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: moveItems ( Item * myItems [], Item * hisItems [])
{
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < TRADE_SLOT_TRADED_COUNT ; ++ i )
2008-10-11 14:16:25 -05:00
{
ItemPosCountVec traderDst ;
ItemPosCountVec playerDst ;
bool traderCanTrade = ( myItems [ i ] == NULL || _player -> pTrader -> CanStoreItem ( NULL_BAG , NULL_SLOT , traderDst , myItems [ i ], false ) == EQUIP_ERR_OK );
bool playerCanTrade = ( hisItems [ i ] == NULL || _player -> CanStoreItem ( NULL_BAG , NULL_SLOT , playerDst , hisItems [ i ], false ) == EQUIP_ERR_OK );
if ( traderCanTrade && playerCanTrade )
{
// Ok, if trade item exists and can be stored
// If we trade in both directions we had to check, if the trade will work before we actually do it
// A roll back is not possible after we stored it
if ( myItems [ i ])
{
// logging
sLog . outDebug ( "partner storing: %u" , myItems [ i ] -> GetGUIDLow ());
if ( _player -> GetSession () -> GetSecurity () > SEC_PLAYER && sWorld . getConfig ( CONFIG_GM_LOG_TRADE ) )
2008-11-25 16:36:50 -06:00
{
sLog . outCommand ( _player -> GetSession () -> GetAccountId (), "GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)" ,
2008-10-11 14:16:25 -05:00
_player -> GetName (), _player -> GetSession () -> GetAccountId (),
myItems [ i ] -> GetProto () -> Name1 , myItems [ i ] -> GetEntry (), myItems [ i ] -> GetCount (),
_player -> pTrader -> GetName (), _player -> pTrader -> GetSession () -> GetAccountId ());
2008-11-25 16:36:50 -06:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// store
_player -> pTrader -> MoveItemToInventory ( traderDst , myItems [ i ], true , true );
}
if ( hisItems [ i ])
{
// logging
sLog . outDebug ( "player storing: %u" , hisItems [ i ] -> GetGUIDLow ());
if ( _player -> pTrader -> GetSession () -> GetSecurity () > SEC_PLAYER && sWorld . getConfig ( CONFIG_GM_LOG_TRADE ) )
2008-11-25 16:36:50 -06:00
{
sLog . outCommand ( _player -> pTrader -> GetSession () -> GetAccountId (), "GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)" ,
2008-10-11 14:16:25 -05:00
_player -> pTrader -> GetName (), _player -> pTrader -> GetSession () -> GetAccountId (),
hisItems [ i ] -> GetProto () -> Name1 , hisItems [ i ] -> GetEntry (), hisItems [ i ] -> GetCount (),
_player -> GetName (), _player -> GetSession () -> GetAccountId ());
2008-11-25 16:36:50 -06:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// store
_player -> MoveItemToInventory ( playerDst , hisItems [ i ], true , true );
}
}
else
{
// in case of fatal error log error message
// return the already removed items to the original owner
if ( myItems [ i ])
{
if ( ! traderCanTrade )
sLog . outError ( "trader can't store item: %u" , myItems [ i ] -> GetGUIDLow ());
if ( _player -> CanStoreItem ( NULL_BAG , NULL_SLOT , playerDst , myItems [ i ], false ) == EQUIP_ERR_OK )
_player -> MoveItemToInventory ( playerDst , myItems [ i ], true , true );
else
sLog . outError ( "player can't take item back: %u" , myItems [ i ] -> GetGUIDLow ());
}
// return the already removed items to the original owner
if ( hisItems [ i ])
{
if ( ! playerCanTrade )
sLog . outError ( "player can't store item: %u" , hisItems [ i ] -> GetGUIDLow ());
if ( _player -> pTrader -> CanStoreItem ( NULL_BAG , NULL_SLOT , traderDst , hisItems [ i ], false ) == EQUIP_ERR_OK )
_player -> pTrader -> MoveItemToInventory ( traderDst , hisItems [ i ], true , true );
else
sLog . outError ( "trader can't take item back: %u" , hisItems [ i ] -> GetGUIDLow ());
}
}
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//==============================================================
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleAcceptTradeOpcode ( WorldPacket & /*recvPacket*/ )
{
Item * myItems [ TRADE_SLOT_TRADED_COUNT ] = { NULL , NULL , NULL , NULL , NULL , NULL };
Item * hisItems [ TRADE_SLOT_TRADED_COUNT ] = { NULL , NULL , NULL , NULL , NULL , NULL };
bool myCanCompleteTrade = true , hisCanCompleteTrade = true ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( ! GetPlayer () -> pTrader )
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// not accept case incorrect money amount
if ( _player -> tradeGold > _player -> GetMoney () )
{
SendNotification ( LANG_NOT_ENOUGH_GOLD );
_player -> pTrader -> GetSession () -> SendTradeStatus ( TRADE_STATUS_BACK_TO_TRADE );
_player -> acceptTrade = false ;
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// not accept case incorrect money amount
if ( _player -> pTrader -> tradeGold > _player -> pTrader -> GetMoney () )
{
_player -> pTrader -> GetSession ( ) -> SendNotification ( LANG_NOT_ENOUGH_GOLD );
SendTradeStatus ( TRADE_STATUS_BACK_TO_TRADE );
_player -> pTrader -> acceptTrade = false ;
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// not accept if some items now can't be trade (cheating)
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < TRADE_SLOT_TRADED_COUNT ; ++ i )
2008-10-11 14:16:25 -05:00
{
2010-02-15 13:55:16 +01:00
if ( _player -> tradeItems [ i ] != 0 )
2008-10-11 14:16:25 -05:00
{
2010-02-15 13:55:16 +01:00
if ( Item * item = _player -> GetItemByGuid ( _player -> tradeItems [ i ] ))
2008-10-11 14:16:25 -05:00
{
2010-02-15 13:55:16 +01:00
if ( ! item -> CanBeTraded ())
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_TRADE_CANCELED );
return ;
}
}
}
2010-02-15 13:55:16 +01:00
if ( _player -> pTrader -> tradeItems [ i ] != 0 )
2008-10-11 14:16:25 -05:00
{
2010-02-15 13:55:16 +01:00
if ( Item * item = _player -> pTrader -> GetItemByGuid ( _player -> pTrader -> tradeItems [ i ]) )
2008-10-11 14:16:25 -05:00
{
2010-02-15 13:55:16 +01:00
if ( ! item -> CanBeTraded ())
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_TRADE_CANCELED );
return ;
}
}
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_player -> acceptTrade = true ;
if ( _player -> pTrader -> acceptTrade )
{
// inform partner client
_player -> pTrader -> GetSession () -> SendTradeStatus ( TRADE_STATUS_TRADE_ACCEPT );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// store items in local list and set 'in-trade' flag
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < TRADE_SLOT_TRADED_COUNT ; ++ i )
2008-10-11 14:16:25 -05:00
{
2010-02-15 13:55:16 +01:00
if ( _player -> tradeItems [ i ] != 0 )
2008-10-11 14:16:25 -05:00
{
//Can return NULL
2010-02-15 13:55:16 +01:00
myItems [ i ] = _player -> GetItemByGuid ( _player -> tradeItems [ i ] );
2008-10-11 14:16:25 -05:00
if ( myItems [ i ])
2010-02-15 13:55:16 +01:00
{
2008-10-11 14:16:25 -05:00
myItems [ i ] -> SetInTrade ();
2010-02-15 13:55:16 +01:00
sLog . outDebug ( "Player trade item bag: %u slot: %u" , myItems [ i ] -> GetBagSlot (), myItems [ i ] -> GetSlot ());
}
2008-10-11 14:16:25 -05:00
}
2010-02-15 13:55:16 +01:00
if ( _player -> pTrader -> tradeItems [ i ] != 0 )
2008-10-11 14:16:25 -05:00
{
//Can return NULL
2010-02-15 13:55:16 +01:00
hisItems [ i ] = _player -> pTrader -> GetItemByGuid ( _player -> pTrader -> tradeItems [ i ]);
if ( hisItems [ i ])
{
2008-10-11 14:16:25 -05:00
hisItems [ i ] -> SetInTrade ();
2010-02-15 13:55:16 +01:00
sLog . outDebug ( "Player trade item bag: %u slot: %u" , hisItems [ i ] -> GetBagSlot (), hisItems [ i ] -> GetSlot ());
}
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// test if item will fit in each inventory
hisCanCompleteTrade = ( _player -> pTrader -> CanStoreItems ( myItems , TRADE_SLOT_TRADED_COUNT ) == EQUIP_ERR_OK );
myCanCompleteTrade = ( _player -> CanStoreItems ( hisItems , TRADE_SLOT_TRADED_COUNT ) == EQUIP_ERR_OK );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// clear 'in-trade' flag
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < TRADE_SLOT_TRADED_COUNT ; ++ i )
2008-10-11 14:16:25 -05:00
{
if ( myItems [ i ]) myItems [ i ] -> SetInTrade ( false );
if ( hisItems [ i ]) hisItems [ i ] -> SetInTrade ( false );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// in case of missing space report error
if ( ! myCanCompleteTrade )
{
SendNotification ( LANG_NOT_FREE_TRADE_SLOTS );
GetPlayer ( ) -> pTrader -> GetSession ( ) -> SendNotification ( LANG_NOT_PARTNER_FREE_TRADE_SLOTS );
SendTradeStatus ( TRADE_STATUS_BACK_TO_TRADE );
_player -> pTrader -> GetSession () -> SendTradeStatus ( TRADE_STATUS_BACK_TO_TRADE );
return ;
}
else if ( ! hisCanCompleteTrade )
{
SendNotification ( LANG_NOT_PARTNER_FREE_TRADE_SLOTS );
GetPlayer () -> pTrader -> GetSession () -> SendNotification ( LANG_NOT_FREE_TRADE_SLOTS );
SendTradeStatus ( TRADE_STATUS_BACK_TO_TRADE );
_player -> pTrader -> GetSession () -> SendTradeStatus ( TRADE_STATUS_BACK_TO_TRADE );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// execute trade: 1. remove
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < TRADE_SLOT_TRADED_COUNT ; ++ i )
2008-10-11 14:16:25 -05:00
{
2010-02-15 13:55:16 +01:00
Item * iPtr = NULL ;
if ( myItems [ i ])
2008-10-11 14:16:25 -05:00
{
2010-02-15 13:55:16 +01:00
myItems [ i ] -> SetUInt64Value ( ITEM_FIELD_GIFTCREATOR , _player -> GetGUID ());
iPtr = _player -> GetItemByGuid ( _player -> tradeItems [ i ]);
_player -> MoveItemFromInventory ( iPtr -> GetBagSlot (), iPtr -> GetSlot (), true );
2008-10-11 14:16:25 -05:00
}
2010-02-15 13:55:16 +01:00
if ( hisItems [ i ])
2008-10-11 14:16:25 -05:00
{
hisItems [ i ] -> SetUInt64Value ( ITEM_FIELD_GIFTCREATOR , _player -> pTrader -> GetGUID ());
2010-02-15 13:55:16 +01:00
iPtr = _player -> pTrader -> GetItemByGuid ( _player -> pTrader -> tradeItems [ i ]);
_player -> pTrader -> MoveItemFromInventory ( iPtr -> GetBagSlot (), iPtr -> GetSlot (), true );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// execute trade: 2. store
moveItems ( myItems , hisItems );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// logging money
if ( sWorld . getConfig ( CONFIG_GM_LOG_TRADE ))
{
if ( _player -> GetSession () -> GetSecurity () > SEC_PLAYER && _player -> tradeGold > 0 )
2008-11-25 16:36:50 -06:00
{
sLog . outCommand ( _player -> GetSession () -> GetAccountId (), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)" ,
2008-10-11 14:16:25 -05:00
_player -> GetName (), _player -> GetSession () -> GetAccountId (),
_player -> tradeGold ,
_player -> pTrader -> GetName (), _player -> pTrader -> GetSession () -> GetAccountId ());
2008-11-25 16:36:50 -06:00
}
2008-10-11 14:16:25 -05:00
if ( _player -> pTrader -> GetSession () -> GetSecurity () > SEC_PLAYER && _player -> pTrader -> tradeGold > 0 )
2008-11-25 16:36:50 -06:00
{
sLog . outCommand ( _player -> pTrader -> GetSession () -> GetAccountId (), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)" ,
2008-10-11 14:16:25 -05:00
_player -> pTrader -> GetName (), _player -> pTrader -> GetSession () -> GetAccountId (),
_player -> pTrader -> tradeGold ,
_player -> GetName (), _player -> GetSession () -> GetAccountId ());
2008-11-25 16:36:50 -06:00
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// update money
_player -> ModifyMoney ( - int32 ( _player -> tradeGold ) );
_player -> ModifyMoney ( _player -> pTrader -> tradeGold );
_player -> pTrader -> ModifyMoney ( - int32 ( _player -> pTrader -> tradeGold ) );
_player -> pTrader -> ModifyMoney ( _player -> tradeGold );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_player -> ClearTrade ();
_player -> pTrader -> ClearTrade ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
CharacterDatabase . BeginTransaction ();
_player -> SaveInventoryAndGoldToDB ();
_player -> pTrader -> SaveInventoryAndGoldToDB ();
CharacterDatabase . CommitTransaction ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_player -> pTrader -> GetSession () -> SendTradeStatus ( TRADE_STATUS_TRADE_COMPLETE );
SendTradeStatus ( TRADE_STATUS_TRADE_COMPLETE );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_player -> pTrader -> pTrader = NULL ;
_player -> pTrader = NULL ;
}
else
{
_player -> pTrader -> GetSession () -> SendTradeStatus ( TRADE_STATUS_TRADE_ACCEPT );
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleUnacceptTradeOpcode ( WorldPacket & /*recvPacket*/ )
{
if ( ! GetPlayer () -> pTrader )
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_player -> pTrader -> GetSession () -> SendTradeStatus ( TRADE_STATUS_BACK_TO_TRADE );
_player -> acceptTrade = false ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleBeginTradeOpcode ( WorldPacket & /*recvPacket*/ )
{
if ( ! _player -> pTrader )
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_player -> pTrader -> GetSession () -> SendTradeStatus ( TRADE_STATUS_OPEN_WINDOW );
_player -> pTrader -> ClearTrade ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SendTradeStatus ( TRADE_STATUS_OPEN_WINDOW );
_player -> ClearTrade ();
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: SendCancelTrade ()
{
SendTradeStatus ( TRADE_STATUS_TRADE_CANCELED );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleCancelTradeOpcode ( WorldPacket & /*recvPacket*/ )
{
// sended also after LOGOUT COMPLETE
2009-09-01 16:47:49 -05:00
if ( _player ) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
2008-10-11 14:16:25 -05:00
_player -> TradeCancel ( true );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleInitiateTradeOpcode ( WorldPacket & recvPacket )
{
2009-05-14 16:50:47 -05:00
if ( GetPlayer () -> pTrader )
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
uint64 ID ;
2009-10-17 15:51:44 -07:00
2009-05-14 16:50:47 -05:00
if ( ! GetPlayer () -> isAlive ())
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_YOU_DEAD );
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-14 16:50:47 -05:00
if ( GetPlayer () -> hasUnitState ( UNIT_STAT_STUNNED ))
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_YOU_STUNNED );
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-14 16:50:47 -05:00
if ( isLogingOut ())
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_YOU_LOGOUT );
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-14 16:50:47 -05:00
if ( GetPlayer () -> isInFlight ())
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_TARGET_TO_FAR );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recvPacket >> ID ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Player * pOther = ObjectAccessor :: FindPlayer ( ID );
2009-10-17 15:51:44 -07:00
2009-05-14 16:50:47 -05:00
if ( ! pOther )
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_NO_TARGET );
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-14 16:50:47 -05:00
if ( pOther == GetPlayer () || pOther -> pTrader )
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_BUSY );
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-14 16:50:47 -05:00
if ( ! pOther -> isAlive ())
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_TARGET_DEAD );
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-14 16:50:47 -05:00
if ( pOther -> isInFlight ())
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_TARGET_TO_FAR );
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-14 16:50:47 -05:00
if ( pOther -> hasUnitState ( UNIT_STAT_STUNNED ))
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_TARGET_STUNNED );
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-14 16:50:47 -05:00
if ( pOther -> GetSession () -> isLogingOut ())
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_TARGET_LOGOUT );
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-14 16:50:47 -05:00
if ( pOther -> GetSocial () -> HasIgnore ( GetPlayer () -> GetGUIDLow ()))
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_IGNORE_YOU );
return ;
}
2009-10-17 15:51:44 -07:00
2009-01-15 21:59:40 -05:00
if ( ! sWorld . getConfig ( CONFIG_ALLOW_TWO_SIDE_TRADE ) && pOther -> GetTeam () != _player -> GetTeam () )
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_WRONG_FACTION );
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-14 16:50:47 -05:00
if ( ! pOther -> IsWithinDistInMap ( _player , 10.0f , false ))
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_TARGET_TO_FAR );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// OK start trade
_player -> pTrader = pOther ;
pOther -> pTrader = _player ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_TRADE_STATUS , 12 );
data << ( uint32 ) TRADE_STATUS_BEGIN_TRADE ;
data << ( uint64 ) _player -> GetGUID ();
_player -> pTrader -> GetSession () -> SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleSetTradeGoldOpcode ( WorldPacket & recvPacket )
{
if ( ! _player -> pTrader )
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 gold ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recvPacket >> gold ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// gold can be incorrect, but this is checked at trade finished.
_player -> tradeGold = gold ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_player -> pTrader -> GetSession () -> SendUpdateTrade ();
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleSetTradeItemOpcode ( WorldPacket & recvPacket )
{
if ( ! _player -> pTrader )
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// send update
uint8 tradeSlot ;
uint8 bag ;
uint8 slot ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recvPacket >> tradeSlot ;
recvPacket >> bag ;
recvPacket >> slot ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// invalid slot number
if ( tradeSlot >= TRADE_SLOT_COUNT )
{
SendTradeStatus ( TRADE_STATUS_TRADE_CANCELED );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// check cheating, can't fail with correct client operations
Item * item = _player -> GetItemByPos ( bag , slot );
2009-09-18 14:10:37 -07:00
if ( ! item || ( tradeSlot != TRADE_SLOT_NONTRADED && ! item -> CanBeTraded ()))
2008-10-11 14:16:25 -05:00
{
SendTradeStatus ( TRADE_STATUS_TRADE_CANCELED );
return ;
}
2009-10-17 15:51:44 -07:00
2010-02-15 13:55:16 +01:00
uint64 iGUID = item -> GetGUID ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent place single item into many trade slots using cheating and client bugs
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < TRADE_SLOT_COUNT ; ++ i )
2008-10-11 14:16:25 -05:00
{
2010-02-15 13:55:16 +01:00
if ( _player -> tradeItems [ i ] == iGUID )
2008-10-11 14:16:25 -05:00
{
// cheating attempt
SendTradeStatus ( TRADE_STATUS_TRADE_CANCELED );
return ;
}
}
2009-10-17 15:51:44 -07:00
2010-02-15 13:55:16 +01:00
_player -> tradeItems [ tradeSlot ] = iGUID ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_player -> pTrader -> GetSession () -> SendUpdateTrade ();
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleClearTradeItemOpcode ( WorldPacket & recvPacket )
{
if ( ! _player -> pTrader )
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint8 tradeSlot ;
recvPacket >> tradeSlot ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// invalid slot number
if ( tradeSlot >= TRADE_SLOT_COUNT )
return ;
2009-10-17 15:51:44 -07:00
2010-02-15 13:55:16 +01:00
_player -> tradeItems [ tradeSlot ] = 0 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_player -> pTrader -> GetSession () -> SendUpdateTrade ();
}
2009-02-17 20:07:49 -06:00