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

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

[svn] * svn:eol-style native set on all files that need it

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