root/trunk/src/game/TradeHandler.cpp @ 26

Revision 2, 22.1 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18
19#include "Common.h"
20#include "WorldPacket.h"
21#include "WorldSession.h"
22#include "World.h"
23#include "ObjectAccessor.h"
24#include "Log.h"
25#include "Opcodes.h"
26#include "Player.h"
27#include "Item.h"
28#include "SocialMgr.h"
29
30enum TradeStatus
31{
32    TRADE_STATUS_BUSY           = 0,
33    TRADE_STATUS_BEGIN_TRADE    = 1,
34    TRADE_STATUS_OPEN_WINDOW    = 2,
35    TRADE_STATUS_TRADE_CANCELED = 3,
36    TRADE_STATUS_TRADE_ACCEPT   = 4,
37    TRADE_STATUS_BUSY_2         = 5,
38    TRADE_STATUS_NO_TARGET      = 6,
39    TRADE_STATUS_BACK_TO_TRADE  = 7,
40    TRADE_STATUS_TRADE_COMPLETE = 8,
41    // 9?
42    TRADE_STATUS_TARGET_TO_FAR  = 10,
43    TRADE_STATUS_WRONG_FACTION  = 11,
44    TRADE_STATUS_CLOSE_WINDOW   = 12,
45    // 13?
46    TRADE_STATUS_IGNORE_YOU     = 14,
47    TRADE_STATUS_YOU_STUNNED    = 15,
48    TRADE_STATUS_TARGET_STUNNED = 16,
49    TRADE_STATUS_YOU_DEAD       = 17,
50    TRADE_STATUS_TARGET_DEAD    = 18,
51    TRADE_STATUS_YOU_LOGOUT     = 19,
52    TRADE_STATUS_TARGET_LOGOUT  = 20,
53    TRADE_STATUS_TRIAL_ACCOUNT  = 21,                       // Trial accounts can not perform that action
54    TRADE_STATUS_ONLY_CONJURED  = 22                        // You can only trade conjured items... (cross realm BG related).
55};
56
57void WorldSession::SendTradeStatus(uint32 status)
58{
59    WorldPacket data;
60
61    switch(status)
62    {
63        case TRADE_STATUS_BEGIN_TRADE:
64            data.Initialize(SMSG_TRADE_STATUS, 4+8);
65            data << uint32(status);
66            data << uint64(0);
67            break;
68        case TRADE_STATUS_OPEN_WINDOW:
69            data.Initialize(SMSG_TRADE_STATUS, 4+4);
70            data << uint32(status);
71            data << uint32(0);                              // added in 2.4.0
72            break;
73        case TRADE_STATUS_CLOSE_WINDOW:
74            data.Initialize(SMSG_TRADE_STATUS, 4+4+1+4);
75            data << uint32(status);
76            data << uint32(0);
77            data << uint8(0);
78            data << uint32(0);
79            break;
80        case TRADE_STATUS_ONLY_CONJURED:
81            data.Initialize(SMSG_TRADE_STATUS, 4+1);
82            data << uint32(status);
83            data << uint8(0);
84            break;
85        default:
86            data.Initialize(SMSG_TRADE_STATUS, 4);
87            data << uint32(status);
88            break;
89    }
90
91    SendPacket(&data);
92}
93
94void WorldSession::HandleIgnoreTradeOpcode(WorldPacket& /*recvPacket*/)
95{
96    sLog.outDebug( "WORLD: Ignore Trade %u",_player->GetGUIDLow());
97    // recvPacket.print_storage();
98}
99
100void WorldSession::HandleBusyTradeOpcode(WorldPacket& /*recvPacket*/)
101{
102    sLog.outDebug( "WORLD: Busy Trade %u",_player->GetGUIDLow());
103    // recvPacket.print_storage();
104}
105
106void WorldSession::SendUpdateTrade()
107{
108    Item *item = NULL;
109
110    if( !_player || !_player->pTrader )
111        return;
112
113    // reset trade status
114    if (_player->acceptTrade)
115    {
116        _player->acceptTrade = false;
117        SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
118    }
119
120    if (_player->pTrader->acceptTrade)
121    {
122        _player->pTrader->acceptTrade = false;
123        _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
124    }
125
126    WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, (100));    // guess size
127    data << (uint8 ) 1;                                     // can be different (only seen 0 and 1)
128    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?)
129    data << (uint32) TRADE_SLOT_COUNT;                      // trade slots count/number?, = next field in most cases
130    data << (uint32) TRADE_SLOT_COUNT;                      // trade slots count/number?, = prev field in most cases
131    data << (uint32) _player->pTrader->tradeGold;           // trader gold
132    data << (uint32) 0;                                     // spell casted on lowest slot item
133
134    for(uint8 i = 0; i < TRADE_SLOT_COUNT; i++)
135    {
136        item = (_player->pTrader->tradeItems[i] != NULL_SLOT ? _player->pTrader->GetItemByPos( _player->pTrader->tradeItems[i] ) : NULL);
137
138        data << (uint8) i;                                  // trade slot number, if not specified, then end of packet
139
140        if(item)
141        {
142            data << (uint32) item->GetProto()->ItemId;      // entry
143                                                            // display id
144            data << (uint32) item->GetProto()->DisplayInfoID;
145                                                            // stack count
146            data << (uint32) item->GetUInt32Value(ITEM_FIELD_STACK_COUNT);
147            data << (uint32) 0;                             // probably gift=1, created_by=0?
148                                                            // gift creator
149            data << (uint64) item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR);
150            data << (uint32) item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT);
151            for(uint8 j = 0; j < 3; ++j)
152                data << (uint32) 0;                         // enchantment id (permanent/gems?)
153                                                            // creator
154            data << (uint64) item->GetUInt64Value(ITEM_FIELD_CREATOR);
155            data << (uint32) item->GetSpellCharges();       // charges
156            data << (uint32) item->GetItemSuffixFactor();   // SuffixFactor
157                                                            // random properties id
158            data << (uint32) item->GetItemRandomPropertyId();
159            data << (uint32) item->GetProto()->LockID;      // lock id
160                                                            // max durability
161            data << (uint32) item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY);
162                                                            // durability
163            data << (uint32) item->GetUInt32Value(ITEM_FIELD_DURABILITY);
164        }
165        else
166        {
167            for(uint8 j = 0; j < 18; j++)
168                data << uint32(0);
169        }
170    }
171    SendPacket(&data);
172}
173
174//==============================================================
175// transfer the items to the players
176
177void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
178{
179    for(int i=0; i<TRADE_SLOT_TRADED_COUNT; i++)
180    {
181        ItemPosCountVec traderDst;
182        ItemPosCountVec playerDst;
183        bool traderCanTrade = (myItems[i]==NULL || _player->pTrader->CanStoreItem( NULL_BAG, NULL_SLOT, traderDst, myItems[i], false ) == EQUIP_ERR_OK);
184        bool playerCanTrade = (hisItems[i]==NULL || _player->CanStoreItem( NULL_BAG, NULL_SLOT, playerDst, hisItems[i], false ) == EQUIP_ERR_OK);
185        if(traderCanTrade && playerCanTrade )
186        {
187            // Ok, if trade item exists and can be stored
188            // If we trade in both directions we had to check, if the trade will work before we actually do it
189            // A roll back is not possible after we stored it
190            if(myItems[i])
191            {
192                // logging
193                sLog.outDebug("partner storing: %u",myItems[i]->GetGUIDLow());
194                if( _player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
195                    sLog.outCommand("GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)",
196                        _player->GetName(),_player->GetSession()->GetAccountId(),
197                        myItems[i]->GetProto()->Name1,myItems[i]->GetEntry(),myItems[i]->GetCount(),
198                        _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId());
199
200                // store
201                _player->pTrader->MoveItemToInventory( traderDst, myItems[i], true, true);
202            }
203            if(hisItems[i])
204            {
205                // logging
206                sLog.outDebug("player storing: %u",hisItems[i]->GetGUIDLow());
207                if( _player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
208                    sLog.outCommand("GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)",
209                        _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(),
210                        hisItems[i]->GetProto()->Name1,hisItems[i]->GetEntry(),hisItems[i]->GetCount(),
211                        _player->GetName(),_player->GetSession()->GetAccountId());
212
213                // store
214                _player->MoveItemToInventory( playerDst, hisItems[i], true, true);
215            }
216        }
217        else
218        {
219            // in case of fatal error log error message
220            // return the already removed items to the original owner
221            if(myItems[i])
222            {
223                if(!traderCanTrade)
224                    sLog.outError("trader can't store item: %u",myItems[i]->GetGUIDLow());
225                if(_player->CanStoreItem( NULL_BAG, NULL_SLOT, playerDst, myItems[i], false ) == EQUIP_ERR_OK)
226                    _player->MoveItemToInventory(playerDst, myItems[i], true, true);
227                else
228                    sLog.outError("player can't take item back: %u",myItems[i]->GetGUIDLow());
229            }
230            // return the already removed items to the original owner
231            if(hisItems[i])
232            {
233                if(!playerCanTrade)
234                    sLog.outError("player can't store item: %u",hisItems[i]->GetGUIDLow());
235                if(_player->pTrader->CanStoreItem( NULL_BAG, NULL_SLOT, traderDst, hisItems[i], false ) == EQUIP_ERR_OK)
236                    _player->pTrader->MoveItemToInventory(traderDst, hisItems[i], true, true);
237                else
238                    sLog.outError("trader can't take item back: %u",hisItems[i]->GetGUIDLow());
239            }
240        }
241    }
242}
243
244//==============================================================
245
246void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
247{
248    Item *myItems[TRADE_SLOT_TRADED_COUNT]  = { NULL, NULL, NULL, NULL, NULL, NULL };
249    Item *hisItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL };
250    bool myCanCompleteTrade=true,hisCanCompleteTrade=true;
251
252    if ( !GetPlayer()->pTrader )
253        return;
254
255    // not accept case incorrect money amount
256    if( _player->tradeGold > _player->GetMoney() )
257    {
258        SendNotification( "You do not have enough gold" );
259        _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
260        _player->acceptTrade = false;
261        return;
262    }
263
264    // not accept case incorrect money amount
265    if( _player->pTrader->tradeGold > _player->pTrader->GetMoney() )
266    {
267        _player->pTrader->GetSession( )->SendNotification( "You do not have enough gold" );
268        SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
269        _player->pTrader->acceptTrade = false;
270        return;
271    }
272
273    // not accept if some items now can't be trade (cheating)
274    for(int i=0; i<TRADE_SLOT_TRADED_COUNT; i++)
275    {
276        if(_player->tradeItems[i] != NULL_SLOT )
277        {
278            if(Item* item  =_player->GetItemByPos( _player->tradeItems[i] ))
279            {
280                if(!item->CanBeTraded())
281                {
282                    SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
283                    return;
284                }
285            }
286        }
287        if(_player->pTrader->tradeItems[i] != NULL_SLOT)
288        {
289            if(Item* item  =_player->pTrader->GetItemByPos( _player->pTrader->tradeItems[i]) )
290            {
291                if(!item->CanBeTraded())
292                {
293                    SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
294                    return;
295                }
296            }
297        }
298    }
299
300    _player->acceptTrade = true;
301    if (_player->pTrader->acceptTrade )
302    {
303        // inform partner client
304        _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT);
305
306        // store items in local list and set 'in-trade' flag
307        for(int i=0; i<TRADE_SLOT_TRADED_COUNT; i++)
308        {
309            if(_player->tradeItems[i] != NULL_SLOT )
310            {
311                sLog.outDebug("player trade item bag: %u slot: %u",_player->tradeItems[i] >> 8, _player->tradeItems[i] & 255 );
312                                                            //Can return NULL
313                myItems[i]=_player->GetItemByPos( _player->tradeItems[i] );
314                if (myItems[i])
315                    myItems[i]->SetInTrade();
316            }
317            if(_player->pTrader->tradeItems[i] != NULL_SLOT)
318            {
319                sLog.outDebug("partner trade item bag: %u slot: %u",_player->pTrader->tradeItems[i] >> 8,_player->pTrader->tradeItems[i] & 255);
320                                                            //Can return NULL
321                hisItems[i]=_player->pTrader->GetItemByPos( _player->pTrader->tradeItems[i]);
322                if(hisItems[i])
323                    hisItems[i]->SetInTrade();
324            }
325        }
326
327        // test if item will fit in each inventory
328        hisCanCompleteTrade =  (_player->pTrader->CanStoreItems( myItems,TRADE_SLOT_TRADED_COUNT )== EQUIP_ERR_OK);
329        myCanCompleteTrade = (_player->CanStoreItems( hisItems,TRADE_SLOT_TRADED_COUNT ) == EQUIP_ERR_OK);
330
331        // clear 'in-trade' flag
332        for(int i=0; i<TRADE_SLOT_TRADED_COUNT; i++)
333        {
334            if(myItems[i])  myItems[i]->SetInTrade(false);
335            if(hisItems[i]) hisItems[i]->SetInTrade(false);
336        }
337
338        // in case of missing space report error
339        if(!myCanCompleteTrade)
340        {
341            SendNotification("You do not have enough free slots");
342            GetPlayer( )->pTrader->GetSession( )->SendNotification("Your partner does not have enough free bag slots");
343            SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
344            _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
345            return;
346        }
347        else if (!hisCanCompleteTrade)
348        {
349            SendNotification("Your partner does not have enough free bag slots");
350            GetPlayer()->pTrader->GetSession()->SendNotification("You do not have enough free slots");
351            SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
352            _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
353            return;
354        }
355
356        // execute trade: 1. remove
357        for(int i=0; i<TRADE_SLOT_TRADED_COUNT; i++)
358        {
359            if(myItems[i])
360            {
361                myItems[i]->SetUInt64Value( ITEM_FIELD_GIFTCREATOR,_player->GetGUID());
362                _player->MoveItemFromInventory(_player->tradeItems[i] >> 8, _player->tradeItems[i] & 255, true);
363            }
364            if(hisItems[i])
365            {
366                hisItems[i]->SetUInt64Value( ITEM_FIELD_GIFTCREATOR,_player->pTrader->GetGUID());
367                _player->pTrader->MoveItemFromInventory(_player->pTrader->tradeItems[i] >> 8, _player->pTrader->tradeItems[i] & 255, true);
368            }
369        }
370
371        // execute trade: 2. store
372        moveItems(myItems, hisItems);
373
374        // logging money
375        if(sWorld.getConfig(CONFIG_GM_LOG_TRADE))
376        {
377            if( _player->GetSession()->GetSecurity() > SEC_PLAYER && _player->tradeGold > 0)
378                sLog.outCommand("GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)",
379                    _player->GetName(),_player->GetSession()->GetAccountId(),
380                    _player->tradeGold,
381                    _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId());
382            if( _player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && _player->pTrader->tradeGold > 0)
383                sLog.outCommand("GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)",
384                    _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(),
385                    _player->pTrader->tradeGold,
386                    _player->GetName(),_player->GetSession()->GetAccountId());
387        }
388
389        // update money
390        _player->ModifyMoney( -int32(_player->tradeGold) );
391        _player->ModifyMoney(_player->pTrader->tradeGold );
392        _player->pTrader->ModifyMoney( -int32(_player->pTrader->tradeGold) );
393        _player->pTrader->ModifyMoney(_player->tradeGold );
394
395        _player->ClearTrade();
396        _player->pTrader->ClearTrade();
397
398        // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
399        CharacterDatabase.BeginTransaction();
400        _player->SaveInventoryAndGoldToDB();
401        _player->pTrader->SaveInventoryAndGoldToDB();
402        CharacterDatabase.CommitTransaction();
403
404        _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE);
405        SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE);
406
407        _player->pTrader->pTrader = NULL;
408        _player->pTrader = NULL;
409    }
410    else
411    {
412        _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT);
413    }
414}
415
416void WorldSession::HandleUnacceptTradeOpcode(WorldPacket& /*recvPacket*/)
417{
418    if ( !GetPlayer()->pTrader )
419        return;
420
421    _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
422    _player->acceptTrade = false;
423}
424
425void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/)
426{
427    if(!_player->pTrader)
428        return;
429
430    _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_OPEN_WINDOW);
431    _player->pTrader->ClearTrade();
432
433    SendTradeStatus(TRADE_STATUS_OPEN_WINDOW);
434    _player->ClearTrade();
435}
436
437void WorldSession::SendCancelTrade()
438{
439    SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
440}
441
442void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/)
443{
444    // sended also after LOGOUT COMPLETE
445    if(_player)                                             // needed because STATUS_AUTHED
446        _player->TradeCancel(true);
447}
448
449void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
450{
451    CHECK_PACKET_SIZE(recvPacket,8);
452
453    if( GetPlayer()->pTrader )
454        return;
455
456    uint64 ID;
457
458    if( !GetPlayer()->isAlive() )
459    {
460        SendTradeStatus(TRADE_STATUS_YOU_DEAD);
461        return;
462    }
463
464    if( GetPlayer()->hasUnitState(UNIT_STAT_STUNDED) )
465    {
466        SendTradeStatus(TRADE_STATUS_YOU_STUNNED);
467        return;
468    }
469
470    if( isLogingOut() )
471    {
472        SendTradeStatus(TRADE_STATUS_YOU_LOGOUT);
473        return;
474    }
475
476    if( GetPlayer()->isInFlight() )
477    {
478        SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
479        return;
480    }
481
482    recvPacket >> ID;
483
484    Player* pOther = ObjectAccessor::FindPlayer( ID );
485
486    if( !pOther )
487    {
488        SendTradeStatus(TRADE_STATUS_NO_TARGET);
489        return;
490    }
491
492    if( pOther == GetPlayer() || pOther->pTrader )
493    {
494        SendTradeStatus(TRADE_STATUS_BUSY);
495        return;
496    }
497
498    if( !pOther->isAlive() )
499    {
500        SendTradeStatus(TRADE_STATUS_TARGET_DEAD);
501        return;
502    }
503
504    if( pOther->isInFlight() )
505    {
506        SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
507        return;
508    }
509
510    if( pOther->hasUnitState(UNIT_STAT_STUNDED) )
511    {
512        SendTradeStatus(TRADE_STATUS_TARGET_STUNNED);
513        return;
514    }
515
516    if( pOther->GetSession()->isLogingOut() )
517    {
518        SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT);
519        return;
520    }
521
522    if( pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()) )
523    {
524        SendTradeStatus(TRADE_STATUS_IGNORE_YOU);
525        return;
526    }
527
528    if(pOther->GetTeam() !=_player->GetTeam() )
529    {
530        SendTradeStatus(TRADE_STATUS_WRONG_FACTION);
531        return;
532    }
533
534    if( pOther->GetDistance2d( _player ) > 10.0f )
535    {
536        SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
537        return;
538    }
539
540    // OK start trade
541    _player->pTrader = pOther;
542    pOther->pTrader =_player;
543
544    WorldPacket data(SMSG_TRADE_STATUS, 12);
545    data << (uint32) TRADE_STATUS_BEGIN_TRADE;
546    data << (uint64)_player->GetGUID();
547    _player->pTrader->GetSession()->SendPacket(&data);
548}
549
550void WorldSession::HandleSetTradeGoldOpcode(WorldPacket& recvPacket)
551{
552    CHECK_PACKET_SIZE(recvPacket,4);
553
554    if(!_player->pTrader)
555        return;
556
557    uint32 gold;
558
559    recvPacket >> gold;
560
561    // gold can be incorrect, but this is checked at trade finished.
562    _player->tradeGold = gold;
563
564    _player->pTrader->GetSession()->SendUpdateTrade();
565}
566
567void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket)
568{
569    CHECK_PACKET_SIZE(recvPacket,1+1+1);
570
571    if(!_player->pTrader)
572        return;
573
574    // send update
575    uint8 tradeSlot;
576    uint8 bag;
577    uint8 slot;
578
579    recvPacket >> tradeSlot;
580    recvPacket >> bag;
581    recvPacket >> slot;
582
583    // invalid slot number
584    if(tradeSlot >= TRADE_SLOT_COUNT)
585    {
586        SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
587        return;
588    }
589
590    // check cheating, can't fail with correct client operations
591    Item* item = _player->GetItemByPos(bag,slot);
592    if(!item || tradeSlot!=TRADE_SLOT_NONTRADED && !item->CanBeTraded())
593    {
594        SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
595        return;
596    }
597
598    uint16 pos = (bag << 8) | slot;
599
600    // prevent place single item into many trade slots using cheating and client bugs
601    for(int i = 0; i < TRADE_SLOT_COUNT; ++i)
602    {
603        if(_player->tradeItems[i]==pos)
604        {
605            // cheating attempt
606            SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
607            return;
608        }
609    }
610
611    _player->tradeItems[tradeSlot] = pos;
612
613    _player->pTrader->GetSession()->SendUpdateTrade();
614}
615
616void WorldSession::HandleClearTradeItemOpcode(WorldPacket& recvPacket)
617{
618    CHECK_PACKET_SIZE(recvPacket,1);
619
620    if(!_player->pTrader)
621        return;
622
623    uint8 tradeSlot;
624    recvPacket >> tradeSlot;
625
626    // invalid slot number
627    if(tradeSlot >= TRADE_SLOT_COUNT)
628        return;
629
630    _player->tradeItems[tradeSlot] = NULL_SLOT;
631
632    _player->pTrader->GetSession()->SendUpdateTrade();
633}
Note: See TracBrowser for help on using the browser.