root/trunk/src/game/ItemHandler.cpp @ 143

Revision 102, 40.3 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 "Opcodes.h"
26#include "Log.h"
27#include "ObjectMgr.h"
28#include "Player.h"
29#include "Item.h"
30#include "UpdateData.h"
31#include "ObjectAccessor.h"
32
33void WorldSession::HandleSplitItemOpcode( WorldPacket & recv_data )
34{
35    CHECK_PACKET_SIZE(recv_data,1+1+1+1+1);
36
37    //sLog.outDebug("WORLD: CMSG_SPLIT_ITEM");
38    uint8 srcbag, srcslot, dstbag, dstslot, count;
39
40    recv_data >> srcbag >> srcslot >> dstbag >> dstslot >> count;
41    //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u, count = %u", srcbag, srcslot, dstbag, dstslot, count);
42
43    uint16 src = ( (srcbag << 8) | srcslot );
44    uint16 dst = ( (dstbag << 8) | dstslot );
45
46    if(src==dst)
47        return;
48
49    if (count==0)
50        return;                                             //check count - if zero it's fake packet
51
52    _player->SplitItem( src, dst, count );
53}
54
55void WorldSession::HandleSwapInvItemOpcode( WorldPacket & recv_data )
56{
57    CHECK_PACKET_SIZE(recv_data,1+1);
58
59    //sLog.outDebug("WORLD: CMSG_SWAP_INV_ITEM");
60    uint8 srcslot, dstslot;
61
62    recv_data >> srcslot >> dstslot;
63    //sLog.outDebug("STORAGE: receive srcslot = %u, dstslot = %u", srcslot, dstslot);
64
65    // prevent attempt swap same item to current position generated by client at special checting sequence
66    if(srcslot==dstslot)
67        return;
68
69    uint16 src = ( (INVENTORY_SLOT_BAG_0 << 8) | srcslot );
70    uint16 dst = ( (INVENTORY_SLOT_BAG_0 << 8) | dstslot );
71
72    _player->SwapItem( src, dst );
73}
74
75void WorldSession::HandleAutoEquipItemSlotOpcode( WorldPacket & recv_data )
76{
77    CHECK_PACKET_SIZE(recv_data,8+1);
78    uint64 itemguid;
79    uint8 dstslot;
80    recv_data >> itemguid >> dstslot;
81
82    // cheating attempt, client should never send opcode in that case
83    if(!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, dstslot))
84        return;
85
86    Item* item = _player->GetItemByGuid(itemguid);
87    uint16 dstpos = dstslot | (INVENTORY_SLOT_BAG_0 << 8);
88
89    if(!item || item->GetPos() == dstpos)
90        return;
91
92    _player->SwapItem(item->GetPos(), dstpos);
93}
94
95void WorldSession::HandleSwapItem( WorldPacket & recv_data )
96{
97    CHECK_PACKET_SIZE(recv_data,1+1+1+1);
98
99    //sLog.outDebug("WORLD: CMSG_SWAP_ITEM");
100    uint8 dstbag, dstslot, srcbag, srcslot;
101
102    recv_data >> dstbag >> dstslot >> srcbag >> srcslot ;
103    //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u", srcbag, srcslot, dstbag, dstslot);
104
105    uint16 src = ( (srcbag << 8) | srcslot );
106    uint16 dst = ( (dstbag << 8) | dstslot );
107
108    // prevent attempt swap same item to current position generated by client at special checting sequence
109    if(src==dst)
110        return;
111
112    _player->SwapItem( src, dst );
113}
114
115void WorldSession::HandleAutoEquipItemOpcode( WorldPacket & recv_data )
116{
117    CHECK_PACKET_SIZE(recv_data,1+1);
118
119    //sLog.outDebug("WORLD: CMSG_AUTOEQUIP_ITEM");
120    uint8 srcbag, srcslot;
121
122    recv_data >> srcbag >> srcslot;
123    //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot);
124
125    Item *pSrcItem  = _player->GetItemByPos( srcbag, srcslot );
126    if( !pSrcItem )
127        return;                                             // only at cheat
128
129    if(pSrcItem->m_lootGenerated)                           // prevent swap looting item
130    {
131        //best error message found for attempting to swap while looting
132        _player->SendEquipError( EQUIP_ERR_CANT_DO_RIGHT_NOW, pSrcItem, NULL );
133        return;
134    }
135
136    uint16 dest;
137    uint8 msg = _player->CanEquipItem( NULL_SLOT, dest, pSrcItem, !pSrcItem->IsBag() );
138    if( msg != EQUIP_ERR_OK )
139    {
140        _player->SendEquipError( msg, pSrcItem, NULL );
141        return;
142    }
143
144    uint16 src = pSrcItem->GetPos();
145    if(dest==src)                                           // prevent equip in same slot, only at cheat
146        return;
147
148    Item *pDstItem = _player->GetItemByPos( dest );
149    if( !pDstItem )                                         // empty slot, simple case
150    {
151        _player->RemoveItem( srcbag, srcslot, true );
152        _player->EquipItem( dest, pSrcItem, true );
153        _player->AutoUnequipOffhandIfNeed();
154    }
155    else                                                    // have currently equipped item, not simple case
156    {
157        uint8 dstbag = pDstItem->GetBagSlot();
158        uint8 dstslot = pDstItem->GetSlot();
159
160        msg = _player->CanUnequipItem( dest, !pSrcItem->IsBag() );
161        if( msg != EQUIP_ERR_OK )
162        {
163            _player->SendEquipError( msg, pDstItem, NULL );
164            return;
165        }
166
167        // check dest->src move possibility
168        ItemPosCountVec sSrc;
169        uint16 eSrc;
170        if( _player->IsInventoryPos( src ) )
171        {
172            msg = _player->CanStoreItem( srcbag, srcslot, sSrc, pDstItem, true );
173            if( msg != EQUIP_ERR_OK )
174                msg = _player->CanStoreItem( srcbag, NULL_SLOT, sSrc, pDstItem, true );
175            if( msg != EQUIP_ERR_OK )
176                msg = _player->CanStoreItem( NULL_BAG, NULL_SLOT, sSrc, pDstItem, true );
177        }
178        else if( _player->IsBankPos( src ) )
179        {
180            msg = _player->CanBankItem( srcbag, srcslot, sSrc, pDstItem, true );
181            if( msg != EQUIP_ERR_OK )
182                msg = _player->CanBankItem( srcbag, NULL_SLOT, sSrc, pDstItem, true );
183            if( msg != EQUIP_ERR_OK )
184                msg = _player->CanBankItem( NULL_BAG, NULL_SLOT, sSrc, pDstItem, true );
185        }
186        else if( _player->IsEquipmentPos( src ) )
187        {
188            msg = _player->CanEquipItem( srcslot, eSrc, pDstItem, true);
189            if( msg == EQUIP_ERR_OK )
190                msg = _player->CanUnequipItem( eSrc, true);
191        }
192
193        if( msg != EQUIP_ERR_OK )
194        {
195            _player->SendEquipError( msg, pDstItem, pSrcItem );
196            return;
197        }
198
199        // now do moves, remove...
200        _player->RemoveItem(dstbag, dstslot, false);
201        _player->RemoveItem(srcbag, srcslot, false);
202
203        // add to dest
204        _player->EquipItem(dest, pSrcItem, true);
205
206        // add to src
207        if( _player->IsInventoryPos( src ) )
208            _player->StoreItem(sSrc, pDstItem, true);
209        else if( _player->IsBankPos( src ) )
210            _player->BankItem(sSrc, pDstItem, true);
211        else if( _player->IsEquipmentPos( src ) )
212            _player->EquipItem(eSrc, pDstItem, true);
213
214        _player->AutoUnequipOffhandIfNeed();
215    }
216}
217
218void WorldSession::HandleDestroyItemOpcode( WorldPacket & recv_data )
219{
220    CHECK_PACKET_SIZE(recv_data,1+1+1+1+1+1);
221
222    //sLog.outDebug("WORLD: CMSG_DESTROYITEM");
223    uint8 bag, slot, count, data1, data2, data3;
224
225    recv_data >> bag >> slot >> count >> data1 >> data2 >> data3;
226    //sLog.outDebug("STORAGE: receive bag = %u, slot = %u, count = %u", bag, slot, count);
227
228    uint16 pos = (bag << 8) | slot;
229
230    // prevent drop unequipable items (in combat, for example) and non-empty bags
231    if(_player->IsEquipmentPos(pos) || _player->IsBagPos(pos))
232    {
233        uint8 msg = _player->CanUnequipItem( pos, false );
234        if( msg != EQUIP_ERR_OK )
235        {
236            _player->SendEquipError( msg, _player->GetItemByPos(pos), NULL );
237            return;
238        }
239    }
240
241    Item *pItem  = _player->GetItemByPos( bag, slot );
242    if(!pItem)
243    {
244        _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
245        return;
246    }
247
248    if(count)
249    {
250        uint32 i_count = count;
251        _player->DestroyItemCount( pItem, i_count, true );
252    }
253    else
254        _player->DestroyItem( bag, slot, true );
255}
256
257// Only _static_ data send in this packet !!!
258void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
259{
260    CHECK_PACKET_SIZE(recv_data, 4);
261
262    //sLog.outDebug("WORLD: CMSG_ITEM_QUERY_SINGLE");
263    uint32 item;
264    recv_data >> item;
265
266    sLog.outDetail("STORAGE: Item Query = %u", item);
267
268    ItemPrototype const *pProto = objmgr.GetItemPrototype( item );
269    if( pProto )
270    {
271        std::string Name        = pProto->Name1;
272        std::string Description = pProto->Description;
273
274        int loc_idx = GetSessionDbLocaleIndex();
275        if ( loc_idx >= 0 )
276        {
277            ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId);
278            if (il)
279            {
280                if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty())
281                    Name = il->Name[loc_idx];
282                if (il->Description.size() > loc_idx && !il->Description[loc_idx].empty())
283                    Description = il->Description[loc_idx];
284            }
285        }
286                                                            // guess size
287        WorldPacket data( SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600);
288        data << pProto->ItemId;
289        data << pProto->Class;
290        data << pProto->SubClass;
291        data << uint32(-1);                                 // new 2.0.3, not exist in wdb cache?
292        data << Name;
293        data << uint8(0x00);                                //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name...
294        data << uint8(0x00);                                //pProto->Name3; // blizz not send name there, just uint8(0x00);
295        data << uint8(0x00);                                //pProto->Name4; // blizz not send name there, just uint8(0x00);
296        data << pProto->DisplayInfoID;
297        data << pProto->Quality;
298        data << pProto->Flags;
299        data << pProto->BuyPrice;
300        data << pProto->SellPrice;
301        data << pProto->InventoryType;
302        data << pProto->AllowableClass;
303        data << pProto->AllowableRace;
304        data << pProto->ItemLevel;
305        data << pProto->RequiredLevel;
306        data << pProto->RequiredSkill;
307        data << pProto->RequiredSkillRank;
308        data << pProto->RequiredSpell;
309        data << pProto->RequiredHonorRank;
310        data << pProto->RequiredCityRank;
311        data << pProto->RequiredReputationFaction;
312        data << pProto->RequiredReputationRank;
313        data << pProto->MaxCount;
314        data << pProto->Stackable;
315        data << pProto->ContainerSlots;
316        for(int i = 0; i < 10; i++)
317        {
318            data << pProto->ItemStat[i].ItemStatType;
319            data << pProto->ItemStat[i].ItemStatValue;
320        }
321        for(int i = 0; i < 5; i++)
322        {
323            data << pProto->Damage[i].DamageMin;
324            data << pProto->Damage[i].DamageMax;
325            data << pProto->Damage[i].DamageType;
326        }
327        data << pProto->Armor;
328        data << pProto->HolyRes;
329        data << pProto->FireRes;
330        data << pProto->NatureRes;
331        data << pProto->FrostRes;
332        data << pProto->ShadowRes;
333        data << pProto->ArcaneRes;
334        data << pProto->Delay;
335        data << pProto->Ammo_type;
336
337        data << (float)pProto->RangedModRange;
338        for(int s = 0; s < 5; s++)
339        {
340            // send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown
341            // use `item_template` or if not set then only use spell cooldowns
342            SpellEntry const* spell = sSpellStore.LookupEntry(pProto->Spells[s].SpellId);
343            if(spell)
344            {
345                bool db_data = pProto->Spells[s].SpellCooldown >= 0 || pProto->Spells[s].SpellCategoryCooldown >= 0;
346
347                data << pProto->Spells[s].SpellId;
348                data << pProto->Spells[s].SpellTrigger;
349                data << uint32(-abs(pProto->Spells[s].SpellCharges));
350
351                if(db_data)
352                {
353                    data << uint32(pProto->Spells[s].SpellCooldown);
354                    data << uint32(pProto->Spells[s].SpellCategory);
355                    data << uint32(pProto->Spells[s].SpellCategoryCooldown);
356                }
357                else
358                {
359                    data << uint32(spell->RecoveryTime);
360                    data << uint32(spell->Category);
361                    data << uint32(spell->CategoryRecoveryTime);
362                }
363            }
364            else
365            {
366                data << uint32(0);
367                data << uint32(0);
368                data << uint32(0);
369                data << uint32(-1);
370                data << uint32(0);
371                data << uint32(-1);
372            }
373        }
374        data << pProto->Bonding;
375        data << Description;
376        data << pProto->PageText;
377        data << pProto->LanguageID;
378        data << pProto->PageMaterial;
379        data << pProto->StartQuest;
380        data << pProto->LockID;
381        data << pProto->Material;
382        data << pProto->Sheath;
383        data << pProto->RandomProperty;
384        data << pProto->RandomSuffix;
385        data << pProto->Block;
386        data << pProto->ItemSet;
387        data << pProto->MaxDurability;
388        data << pProto->Area;
389        data << pProto->Map;                                // Added in 1.12.x & 2.0.1 client branch
390        data << pProto->BagFamily;
391        data << pProto->TotemCategory;
392        for(int s = 0; s < 3; s++)
393        {
394            data << pProto->Socket[s].Color;
395            data << pProto->Socket[s].Content;
396        }
397        data << pProto->socketBonus;
398        data << pProto->GemProperties;
399        data << pProto->RequiredDisenchantSkill;
400        data << pProto->ArmorDamageModifier;
401        data << uint32(0);                                  // added in 2.4.2.8209, duration (seconds)
402        SendPacket( &data );
403    }
404    else
405    {
406        sLog.outDebug(  "WORLD: CMSG_ITEM_QUERY_SINGLE - NO item INFO! (ENTRY: %u)", item );
407        WorldPacket data( SMSG_ITEM_QUERY_SINGLE_RESPONSE, 4);
408        data << uint32(item | 0x80000000);
409        SendPacket( &data );
410    }
411}
412
413void WorldSession::HandleReadItem( WorldPacket & recv_data )
414{
415    CHECK_PACKET_SIZE(recv_data,1+1);
416
417    //sLog.outDebug( "WORLD: CMSG_READ_ITEM");
418
419    uint8 bag, slot;
420    recv_data >> bag >> slot;
421
422    //sLog.outDetail("STORAGE: Read bag = %u, slot = %u", bag, slot);
423    Item *pItem = _player->GetItemByPos( bag, slot );
424
425    if( pItem && pItem->GetProto()->PageText )
426    {
427        WorldPacket data;
428
429        uint8 msg = _player->CanUseItem( pItem );
430        if( msg == EQUIP_ERR_OK )
431        {
432            data.Initialize (SMSG_READ_ITEM_OK, 8);
433            sLog.outDetail("STORAGE: Item page sent");
434        }
435        else
436        {
437            data.Initialize( SMSG_READ_ITEM_FAILED, 8 );
438            sLog.outDetail("STORAGE: Unable to read item");
439            _player->SendEquipError( msg, pItem, NULL );
440        }
441        data << pItem->GetGUID();
442        SendPacket(&data);
443    }
444    else
445        _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
446}
447
448void WorldSession::HandlePageQuerySkippedOpcode( WorldPacket & recv_data )
449{
450    CHECK_PACKET_SIZE(recv_data,4+8);
451
452    sLog.outDebug(  "WORLD: Received CMSG_PAGE_TEXT_QUERY" );
453
454    uint32 itemid;
455    uint64 guid;
456
457    recv_data >> itemid >> guid;
458
459    sLog.outDetail( "Packet Info: itemid: %u guidlow: %u guidentry: %u guidhigh: %u",
460        itemid, GUID_LOPART(guid), GUID_ENPART(guid), GUID_HIPART(guid));
461}
462
463void WorldSession::HandleSellItemOpcode( WorldPacket & recv_data )
464{
465    CHECK_PACKET_SIZE(recv_data,8+8+1);
466
467    sLog.outDebug(  "WORLD: Received CMSG_SELL_ITEM" );
468    uint64 vendorguid, itemguid;
469    uint8 _count;
470
471    recv_data >> vendorguid >> itemguid >> _count;
472
473    // prevent possible overflow, as Trinity uses uint32 for item count
474    uint32 count = _count;
475
476    if(!itemguid)
477        return;
478
479    Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, vendorguid,UNIT_NPC_FLAG_VENDOR);
480    if (!pCreature)
481    {
482        sLog.outDebug( "WORLD: HandleSellItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) );
483        _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, itemguid, 0);
484        return;
485    }
486
487    // remove fake death
488    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
489        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
490
491    Item *pItem = _player->GetItemByGuid( itemguid );
492    if( pItem )
493    {
494        // prevent sell not owner item
495        if(_player->GetGUID()!=pItem->GetOwnerGUID())
496        {
497            _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0);
498            return;
499        }
500
501        // prevent sell non empty bag by drag-and-drop at vendor's item list
502        if(pItem->IsBag() && !((Bag*)pItem)->IsEmpty())
503        {
504            _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0);
505            return;
506        }
507
508        // prevent sell currently looted item
509        if(_player->GetLootGUID()==pItem->GetGUID())
510        {
511            _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0);
512            return;
513        }
514
515        // special case at auto sell (sell all)
516        if(count==0)
517        {
518            count = pItem->GetCount();
519        }
520        else
521        {
522            // prevent sell more items that exist in stack (possable only not from client)
523            if(count > pItem->GetCount())
524            {
525                _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0);
526                return;
527            }
528        }
529
530        ItemPrototype const *pProto = pItem->GetProto();
531        if( pProto )
532        {
533            if( pProto->SellPrice > 0 )
534            {
535                if(count < pItem->GetCount())               // need split items
536                {
537                    Item *pNewItem = pItem->CloneItem( count, _player );
538                    if (!pNewItem)
539                    {
540                        sLog.outError("WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), count );
541                        _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0);
542                        return;
543                    }
544
545                    pItem->SetCount( pItem->GetCount() - count );
546                    _player->ItemRemovedQuestCheck( pItem->GetEntry(), count );
547                    if( _player->IsInWorld() )
548                        pItem->SendUpdateToPlayer( _player );
549                    pItem->SetState(ITEM_CHANGED, _player);
550
551                    _player->AddItemToBuyBackSlot( pNewItem );
552                    if( _player->IsInWorld() )
553                        pNewItem->SendUpdateToPlayer( _player );
554                }
555                else
556                {
557                    _player->ItemRemovedQuestCheck( pItem->GetEntry(), pItem->GetCount());
558                    _player->RemoveItem( pItem->GetBagSlot(), pItem->GetSlot(), true);
559                    pItem->RemoveFromUpdateQueueOf(_player);
560                    _player->AddItemToBuyBackSlot( pItem );
561                }
562
563                _player->ModifyMoney( pProto->SellPrice * count );
564            }
565            else
566                _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0);
567            return;
568        }
569    }
570    _player->SendSellError( SELL_ERR_CANT_FIND_ITEM, pCreature, itemguid, 0);
571    return;
572}
573
574void WorldSession::HandleBuybackItem(WorldPacket & recv_data)
575{
576    CHECK_PACKET_SIZE(recv_data,8+4);
577
578    sLog.outDebug(  "WORLD: Received CMSG_BUYBACK_ITEM" );
579    uint64 vendorguid;
580    uint32 slot;
581
582    recv_data >> vendorguid >> slot;
583
584    Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, vendorguid,UNIT_NPC_FLAG_VENDOR);
585    if (!pCreature)
586    {
587        sLog.outDebug( "WORLD: HandleBuybackItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) );
588        _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0);
589        return;
590    }
591
592    // remove fake death
593    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
594        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
595
596    Item *pItem = _player->GetItemFromBuyBackSlot( slot );
597    if( pItem )
598    {
599        uint32 price = _player->GetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + slot - BUYBACK_SLOT_START );
600        if( _player->GetMoney() < price )
601        {
602            _player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, pItem->GetEntry(), 0);
603            return;
604        }
605
606        ItemPosCountVec dest;
607        uint8 msg = _player->CanStoreItem( NULL_BAG, NULL_SLOT, dest, pItem, false );
608        if( msg == EQUIP_ERR_OK )
609        {
610            _player->ModifyMoney( -(int32)price );
611            _player->RemoveItemFromBuyBackSlot( slot, false );
612            _player->ItemAddedQuestCheck( pItem->GetEntry(), pItem->GetCount());
613            _player->StoreItem( dest, pItem, true );
614        }
615        else
616            _player->SendEquipError( msg, pItem, NULL );
617        return;
618    }
619    else
620        _player->SendBuyError( BUY_ERR_CANT_FIND_ITEM, pCreature, 0, 0);
621}
622
623void WorldSession::HandleBuyItemInSlotOpcode( WorldPacket & recv_data )
624{
625    CHECK_PACKET_SIZE(recv_data,8+4+8+1+1);
626
627    sLog.outDebug(  "WORLD: Received CMSG_BUY_ITEM_IN_SLOT" );
628    uint64 vendorguid, bagguid;
629    uint32 item;
630    uint8 slot, count;
631
632    recv_data >> vendorguid >> item >> bagguid >> slot >> count;
633
634    GetPlayer()->BuyItemFromVendor(vendorguid,item,count,bagguid,slot);
635}
636
637void WorldSession::HandleBuyItemOpcode( WorldPacket & recv_data )
638{
639    CHECK_PACKET_SIZE(recv_data,8+4+1+1);
640
641    sLog.outDebug(  "WORLD: Received CMSG_BUY_ITEM" );
642    uint64 vendorguid;
643    uint32 item;
644    uint8 count, unk1;
645
646    recv_data >> vendorguid >> item >> count >> unk1;
647
648    GetPlayer()->BuyItemFromVendor(vendorguid,item,count,NULL_BAG,NULL_SLOT);
649}
650
651void WorldSession::HandleListInventoryOpcode( WorldPacket & recv_data )
652{
653    CHECK_PACKET_SIZE(recv_data,8);
654
655    uint64 guid;
656
657    recv_data >> guid;
658
659    if(!GetPlayer()->isAlive())
660        return;
661
662    sLog.outDebug(  "WORLD: Recvd CMSG_LIST_INVENTORY" );
663
664    SendListInventory( guid );
665}
666
667void WorldSession::SendListInventory( uint64 vendorguid )
668{
669    sLog.outDebug(  "WORLD: Sent SMSG_LIST_INVENTORY" );
670
671    Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, vendorguid,UNIT_NPC_FLAG_VENDOR);
672    if (!pCreature)
673    {
674        sLog.outDebug( "WORLD: SendListInventory - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) );
675        _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0);
676        return;
677    }
678
679    // remove fake death
680    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
681        GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
682
683    // Stop the npc if moving
684    pCreature->StopMoving();
685
686    VendorItemData const* vItems = pCreature->GetVendorItems();
687    if(!vItems)
688    {
689        _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0);
690        return;
691    }
692
693    uint8 numitems = vItems->GetItemCount();
694    uint8 count = 0;
695
696    WorldPacket data( SMSG_LIST_INVENTORY, (8+1+numitems*8*4) );
697    data << uint64(vendorguid);
698    data << uint8(numitems);
699
700    float discountMod = _player->GetReputationPriceDiscount(pCreature);
701
702    for(int i = 0; i < numitems; i++ )
703    {
704        if(VendorItem const* crItem = vItems->GetItem(i))
705        {
706            if(ItemPrototype const *pProto = objmgr.GetItemPrototype(crItem->item))
707            {
708                if((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP && !_player->isGameMaster())
709                    continue;
710
711                ++count;
712
713                // reputation discount
714                uint32 price = uint32(floor(pProto->BuyPrice * discountMod));
715
716                data << uint32(count);
717                data << uint32(crItem->item);
718                data << uint32(pProto->DisplayInfoID);
719                data << uint32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem));
720                data << uint32(price);
721                data << uint32(pProto->MaxDurability);
722                data << uint32(pProto->BuyCount);
723                data << uint32(crItem->ExtendedCost);
724            }
725        }
726    }
727
728    if ( count == 0 || data.size() != 8 + 1 + size_t(count) * 8 * 4 )
729        return;
730
731    data.put<uint8>(8, count);
732    SendPacket( &data );
733}
734
735void WorldSession::HandleAutoStoreBagItemOpcode( WorldPacket & recv_data )
736{
737    CHECK_PACKET_SIZE(recv_data,1+1+1);
738
739    //sLog.outDebug("WORLD: CMSG_AUTOSTORE_BAG_ITEM");
740    uint8 srcbag, srcslot, dstbag;
741
742    recv_data >> srcbag >> srcslot >> dstbag;
743    //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u", srcbag, srcslot, dstbag);
744
745    Item *pItem = _player->GetItemByPos( srcbag, srcslot );
746    if( !pItem )
747        return;
748
749    uint16 src = pItem->GetPos();
750
751    // check unequip potability for equipped items and bank bags
752    if(_player->IsEquipmentPos ( src ) || _player->IsBagPos ( src ))
753    {
754        uint8 msg = _player->CanUnequipItem( src, !_player->IsBagPos ( src ));
755        if(msg != EQUIP_ERR_OK)
756        {
757            _player->SendEquipError( msg, pItem, NULL );
758            return;
759        }
760    }
761
762    ItemPosCountVec dest;
763    uint8 msg = _player->CanStoreItem( dstbag, NULL_SLOT, dest, pItem, false );
764    if( msg != EQUIP_ERR_OK )
765    {
766        _player->SendEquipError( msg, pItem, NULL );
767        return;
768    }
769
770    // no-op: placed in same slot
771    if(dest.size()==1 && dest[0].pos==src)
772    {
773        // just remove grey item state
774        _player->SendEquipError( EQUIP_ERR_NONE, pItem, NULL );
775        return;
776    }
777
778    _player->RemoveItem(srcbag, srcslot, true );
779    _player->StoreItem( dest, pItem, true );
780}
781
782void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& /*recvPacket*/)
783{
784    sLog.outDebug("WORLD: CMSG_BUY_BANK_SLOT");
785
786    uint32 slot = _player->GetByteValue(PLAYER_BYTES_2, 2);
787
788    // next slot
789    ++slot;
790
791    sLog.outDetail("PLAYER: Buy bank bag slot, slot number = %u", slot);
792
793    BankBagSlotPricesEntry const* slotEntry = sBankBagSlotPricesStore.LookupEntry(slot);
794
795    if(!slotEntry)
796        return;
797
798    uint32 price = slotEntry->price;
799
800    if (_player->GetMoney() < price)
801        return;
802
803    _player->SetByteValue(PLAYER_BYTES_2, 2, slot);
804    _player->ModifyMoney(-int32(price));
805}
806
807void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket)
808{
809    CHECK_PACKET_SIZE(recvPacket,1+1);
810
811    sLog.outDebug("WORLD: CMSG_AUTOBANK_ITEM");
812    uint8 srcbag, srcslot;
813
814    recvPacket >> srcbag >> srcslot;
815    sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot);
816
817    Item *pItem = _player->GetItemByPos( srcbag, srcslot );
818    if( !pItem )
819        return;
820
821    ItemPosCountVec dest;
822    uint8 msg = _player->CanBankItem( NULL_BAG, NULL_SLOT, dest, pItem, false );
823    if( msg != EQUIP_ERR_OK )
824    {
825        _player->SendEquipError( msg, pItem, NULL );
826        return;
827    }
828
829    _player->RemoveItem(srcbag, srcslot, true);
830    _player->BankItem( dest, pItem, true );
831}
832
833void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket)
834{
835    CHECK_PACKET_SIZE(recvPacket,1+1);
836
837    sLog.outDebug("WORLD: CMSG_AUTOSTORE_BANK_ITEM");
838    uint8 srcbag, srcslot;
839
840    recvPacket >> srcbag >> srcslot;
841    sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot);
842
843    Item *pItem = _player->GetItemByPos( srcbag, srcslot );
844    if( !pItem )
845        return;
846
847    if(_player->IsBankPos(srcbag, srcslot))                 // moving from bank to inventory
848    {
849        ItemPosCountVec dest;
850        uint8 msg = _player->CanStoreItem( NULL_BAG, NULL_SLOT, dest, pItem, false );
851        if( msg != EQUIP_ERR_OK )
852        {
853            _player->SendEquipError( msg, pItem, NULL );
854            return;
855        }
856
857        _player->RemoveItem(srcbag, srcslot, true);
858        _player->StoreItem( dest, pItem, true );
859    }
860    else                                                    // moving from inventory to bank
861    {
862        ItemPosCountVec dest;
863        uint8 msg = _player->CanBankItem( NULL_BAG, NULL_SLOT, dest, pItem, false );
864        if( msg != EQUIP_ERR_OK )
865        {
866            _player->SendEquipError( msg, pItem, NULL );
867            return;
868        }
869
870        _player->RemoveItem(srcbag, srcslot, true);
871        _player->BankItem( dest, pItem, true );
872    }
873}
874
875void WorldSession::HandleSetAmmoOpcode(WorldPacket & recv_data)
876{
877    CHECK_PACKET_SIZE(recv_data,4);
878
879    if(!GetPlayer()->isAlive())
880    {
881        GetPlayer()->SendEquipError( EQUIP_ERR_YOU_ARE_DEAD, NULL, NULL );
882        return;
883    }
884
885    sLog.outDebug("WORLD: CMSG_SET_AMMO");
886    uint32 item;
887
888    recv_data >> item;
889
890    if(!item)
891        GetPlayer()->RemoveAmmo();
892    else
893        GetPlayer()->SetAmmo(item);
894}
895
896void WorldSession::SendEnchantmentLog(uint64 Target, uint64 Caster,uint32 ItemID,uint32 SpellID)
897{
898    WorldPacket data(SMSG_ENCHANTMENTLOG, (8+8+4+4+1));     // last check 2.0.10
899    data << Target;
900    data << Caster;
901    data << ItemID;
902    data << SpellID;
903    data << uint8(0);
904    SendPacket(&data);
905}
906
907void WorldSession::SendItemEnchantTimeUpdate(uint64 Playerguid, uint64 Itemguid,uint32 slot,uint32 Duration)
908{
909                                                            // last check 2.0.10
910    WorldPacket data(SMSG_ITEM_ENCHANT_TIME_UPDATE, (8+4+4+8));
911    data << uint64(Itemguid);
912    data << uint32(slot);
913    data << uint32(Duration);
914    data << uint64(Playerguid);
915    SendPacket(&data);
916}
917
918void WorldSession::HandleItemNameQueryOpcode(WorldPacket & recv_data)
919{
920    CHECK_PACKET_SIZE(recv_data,4);
921
922    uint32 itemid;
923    recv_data >> itemid;
924    sLog.outDebug("WORLD: CMSG_ITEM_NAME_QUERY %u", itemid);
925    ItemPrototype const *pProto = objmgr.GetItemPrototype( itemid );
926    if( pProto )
927    {
928        std::string Name;
929        Name = pProto->Name1;
930
931        int loc_idx = GetSessionDbLocaleIndex();
932        if (loc_idx >= 0)
933        {
934            ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId);
935            if (il)
936            {
937                if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty())
938                    Name = il->Name[loc_idx];
939            }
940        }
941                                                            // guess size
942        WorldPacket data(SMSG_ITEM_NAME_QUERY_RESPONSE, (4+10));
943        data << uint32(pProto->ItemId);
944        data << Name;
945        data << uint32(pProto->InventoryType);
946        SendPacket(&data);
947        return;
948    }
949    else
950        sLog.outDebug("WORLD: CMSG_ITEM_NAME_QUERY for item %u failed (unknown item)", itemid);
951}
952
953void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data)
954{
955    CHECK_PACKET_SIZE(recv_data,1+1+1+1);
956
957    sLog.outDebug("Received opcode CMSG_WRAP_ITEM");
958
959    uint8 gift_bag, gift_slot, item_bag, item_slot;
960    //recv_data.hexlike();
961
962    recv_data >> gift_bag >> gift_slot;                     // paper
963    recv_data >> item_bag >> item_slot;                     // item
964
965    sLog.outDebug("WRAP: receive gift_bag = %u, gift_slot = %u, item_bag = %u, item_slot = %u", gift_bag, gift_slot, item_bag, item_slot);
966
967    Item *gift = _player->GetItemByPos( gift_bag, gift_slot );
968    if(!gift)
969    {
970        _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL );
971        return;
972    }
973
974    if(!gift->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPER))// cheating: non-wrapper wrapper
975    {
976        _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL );
977        return;
978    }
979
980    Item *item = _player->GetItemByPos( item_bag, item_slot );
981
982    if( !item )
983    {
984        _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, item, NULL );
985        return;
986    }
987
988    if(item==gift)                                          // not possable with pacjket from real client
989    {
990        _player->SendEquipError( EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL );
991        return;
992    }
993
994    if(item->IsEquipped())
995    {
996        _player->SendEquipError( EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED, item, NULL );
997        return;
998    }
999
1000    if(item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR))        // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED);
1001    {
1002        _player->SendEquipError( EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL );
1003        return;
1004    }
1005
1006    if(item->IsBag())
1007    {
1008        _player->SendEquipError( EQUIP_ERR_BAGS_CANT_BE_WRAPPED, item, NULL );
1009        return;
1010    }
1011
1012    if(item->IsSoulBound())
1013    {
1014        _player->SendEquipError( EQUIP_ERR_BOUND_CANT_BE_WRAPPED, item, NULL );
1015        return;
1016    }
1017
1018    if(item->GetMaxStackCount() != 1)
1019    {
1020        _player->SendEquipError( EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED, item, NULL );
1021        return;
1022    }
1023
1024    // maybe not correct check  (it is better than nothing)
1025    if(item->GetProto()->MaxCount>0)
1026    {
1027        _player->SendEquipError( EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED, item, NULL );
1028        return;
1029    }
1030
1031    CharacterDatabase.BeginTransaction();
1032    CharacterDatabase.PExecute("INSERT INTO character_gifts VALUES ('%u', '%u', '%u', '%u')", GUID_LOPART(item->GetOwnerGUID()), item->GetGUIDLow(), item->GetEntry(), item->GetUInt32Value(ITEM_FIELD_FLAGS));
1033    item->SetUInt32Value(OBJECT_FIELD_ENTRY, gift->GetUInt32Value(OBJECT_FIELD_ENTRY));
1034
1035    switch (item->GetEntry())
1036    {
1037        case 5042:  item->SetUInt32Value(OBJECT_FIELD_ENTRY,  5043); break;
1038        case 5048:  item->SetUInt32Value(OBJECT_FIELD_ENTRY,  5044); break;
1039        case 17303: item->SetUInt32Value(OBJECT_FIELD_ENTRY, 17302); break;
1040        case 17304: item->SetUInt32Value(OBJECT_FIELD_ENTRY, 17305); break;
1041        case 17307: item->SetUInt32Value(OBJECT_FIELD_ENTRY, 17308); break;
1042        case 21830: item->SetUInt32Value(OBJECT_FIELD_ENTRY, 21831); break;
1043    }
1044    item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID());
1045    item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED);
1046    item->SetState(ITEM_CHANGED, _player);
1047
1048    if(item->GetState()==ITEM_NEW)                          // save new item, to have alway for `character_gifts` record in `item_instance`
1049    {
1050        // after save it will be impossible to remove the item from the queue
1051        item->RemoveFromUpdateQueueOf(_player);
1052        item->SaveToDB();                                   // item gave inventory record unchanged and can be save standalone
1053    }
1054    CharacterDatabase.CommitTransaction();
1055
1056    uint32 count = 1;
1057    _player->DestroyItemCount(gift, count, true);
1058}
1059
1060void WorldSession::HandleSocketOpcode(WorldPacket& recv_data)
1061{
1062    sLog.outDebug("WORLD: CMSG_SOCKET_GEMS");
1063
1064    CHECK_PACKET_SIZE(recv_data,8*4);
1065
1066    uint64 guids[4];
1067    uint32 GemEnchants[3], OldEnchants[3];
1068    Item *Gems[3];
1069    bool SocketBonusActivated, SocketBonusToBeActivated;
1070
1071    for(int i = 0; i < 4; i++)
1072        recv_data >> guids[i];
1073
1074    if(!guids[0])
1075        return;
1076
1077    //cheat -> tried to socket same gem multiple times
1078    if((guids[1] && (guids[1] == guids[2] || guids[1] == guids[3])) || (guids[2] && (guids[2] == guids[3])))
1079        return;
1080
1081    Item *itemTarget = _player->GetItemByGuid(guids[0]);
1082    if(!itemTarget)                                         //missing item to socket
1083        return;
1084
1085    //this slot is excepted when applying / removing meta gem bonus
1086    uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : NULL_SLOT;
1087
1088    for(int i = 0; i < 3; i++)
1089        Gems[i] = guids[i + 1] ? _player->GetItemByGuid(guids[i + 1]) : NULL;
1090
1091    GemPropertiesEntry const *GemProps[3];
1092    for(int i = 0; i < 3; ++i)                              //get geminfo from dbc storage
1093    {
1094        GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetProto()->GemProperties) : NULL;
1095    }
1096
1097    for(int i = 0; i < 3; ++i)                              //check for hack maybe
1098    {
1099        // tried to put gem in socket where no socket exists / tried to put normal gem in meta socket
1100        // tried to put meta gem in normal socket
1101        if( GemProps[i] && ( !itemTarget->GetProto()->Socket[i].Color ||
1102            itemTarget->GetProto()->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META ||
1103            itemTarget->GetProto()->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META ) )
1104            return;
1105    }
1106
1107    for(int i = 0; i < 3; ++i)                              //get new and old enchantments
1108    {
1109        GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0;
1110        OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i));
1111    }
1112
1113    // check unique-equipped conditions
1114    for(int i = 0; i < 3; ++i)
1115    {
1116        if (Gems[i] && (Gems[i]->GetProto()->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED))
1117        {
1118            // for equipped item check all equipment for duplicate equipped gems
1119            if(itemTarget->IsEquipped())
1120            {
1121                if(GetPlayer()->GetItemOrItemWithGemEquipped(Gems[i]->GetEntry()))
1122                {
1123                    _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE, itemTarget, NULL );
1124                    return;
1125                }
1126            }
1127
1128            // continue check for case when attempt add 2 similar unique equipped gems in one item.
1129            for (int j = 0; j < 3; ++j)
1130            {
1131                if ((i != j) && (Gems[j]) && (Gems[i]->GetProto()->ItemId == Gems[j]->GetProto()->ItemId))
1132                {
1133                    _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
1134                    return;
1135                }
1136            }
1137            for (int j = 0; j < 3; ++j)
1138            {
1139                if (OldEnchants[j])
1140                {
1141                    SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]);
1142                    if(!enchantEntry)
1143                        continue;
1144
1145                    if ((enchantEntry->GemID == Gems[i]->GetProto()->ItemId) && (i != j))
1146                    {
1147                        _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
1148                        return;
1149                    }
1150                }
1151            }
1152        }
1153    }
1154
1155    SocketBonusActivated = itemTarget->GemsFitSockets();    //save state of socketbonus
1156    _player->ToggleMetaGemsActive(slot, false);             //turn off all metagems (except for the target item)
1157
1158    //if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met
1159
1160    //remove ALL enchants
1161    for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
1162        _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),false);
1163
1164    for(int i = 0; i < 3; ++i)
1165    {
1166        if(GemEnchants[i])
1167        {
1168            itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i],0,0);
1169            if(Item* guidItem = _player->GetItemByGuid(guids[i + 1]))
1170                _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true );
1171        }
1172    }
1173
1174    for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
1175        _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),true);
1176
1177    SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state
1178    if(SocketBonusActivated ^ SocketBonusToBeActivated)     //if there was a change...
1179    {
1180        _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,false);
1181        itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetProto()->socketBonus : 0), 0, 0);
1182        _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,true);
1183        //it is not displayed, client has an inbuilt system to determine if the bonus is activated
1184    }
1185
1186    _player->ToggleMetaGemsActive(slot, true);              //turn on all metagems (except for target item)
1187}
1188
1189void WorldSession::HandleCancelTempItemEnchantmentOpcode(WorldPacket& recv_data)
1190{
1191    sLog.outDebug("WORLD: CMSG_CANCEL_TEMP_ENCHANTMENT");
1192
1193    CHECK_PACKET_SIZE(recv_data,4);
1194
1195    uint32 eslot;
1196
1197    recv_data >> eslot;
1198
1199    // apply only to equipped item
1200    if(!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0,eslot))
1201        return;
1202
1203    Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, eslot);
1204
1205    if(!item)
1206        return;
1207
1208    if(!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
1209        return;
1210
1211    GetPlayer()->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,false);
1212    item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT);
1213}
Note: See TracBrowser for help on using the browser.