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

Revision 102, 22.2 kB (checked in by yumileroy, 17 years ago)

[svn] Fixed copyright notices to comply with GPL.

Original author: w12x
Date: 2008-10-23 03:29:52-05:00

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