[9290] Some cleanups in realmd, no functional changes
[getmangos.git] / src / game / ItemHandler.cpp
blob800b78a9796084f1f7b82bc0c37ce378654bdeb4
1 /*
2 * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
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.
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.
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
19 #include "Common.h"
20 #include "WorldPacket.h"
21 #include "WorldSession.h"
22 #include "Opcodes.h"
23 #include "Log.h"
24 #include "ObjectMgr.h"
25 #include "Player.h"
26 #include "Item.h"
27 #include "UpdateData.h"
29 void WorldSession::HandleSplitItemOpcode( WorldPacket & recv_data )
31 //sLog.outDebug("WORLD: CMSG_SPLIT_ITEM");
32 uint8 srcbag, srcslot, dstbag, dstslot;
33 uint32 count;
35 recv_data >> srcbag >> srcslot >> dstbag >> dstslot >> count;
36 //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u, count = %u", srcbag, srcslot, dstbag, dstslot, count);
38 uint16 src = ( (srcbag << 8) | srcslot );
39 uint16 dst = ( (dstbag << 8) | dstslot );
41 if(src == dst)
42 return;
44 if (count == 0)
45 return; //check count - if zero it's fake packet
47 if(!_player->IsValidPos(srcbag, srcslot, true))
49 _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
50 return;
53 if(!_player->IsValidPos(dstbag, dstslot, false)) // can be autostore pos
55 _player->SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL );
56 return;
59 _player->SplitItem( src, dst, count );
62 void WorldSession::HandleSwapInvItemOpcode( WorldPacket & recv_data )
64 //sLog.outDebug("WORLD: CMSG_SWAP_INV_ITEM");
65 uint8 srcslot, dstslot;
67 recv_data >> dstslot >> srcslot;
68 //sLog.outDebug("STORAGE: receive srcslot = %u, dstslot = %u", srcslot, dstslot);
70 // prevent attempt swap same item to current position generated by client at special cheating sequence
71 if(srcslot == dstslot)
72 return;
74 if(!_player->IsValidPos(INVENTORY_SLOT_BAG_0, srcslot, true))
76 _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
77 return;
80 if(!_player->IsValidPos(INVENTORY_SLOT_BAG_0, dstslot, true))
82 _player->SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL );
83 return;
86 uint16 src = ( (INVENTORY_SLOT_BAG_0 << 8) | srcslot );
87 uint16 dst = ( (INVENTORY_SLOT_BAG_0 << 8) | dstslot );
89 _player->SwapItem( src, dst );
92 void WorldSession::HandleAutoEquipItemSlotOpcode( WorldPacket & recv_data )
94 uint64 itemguid;
95 uint8 dstslot;
96 recv_data >> itemguid >> dstslot;
98 // cheating attempt, client should never send opcode in that case
99 if(!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, dstslot))
100 return;
102 Item* item = _player->GetItemByGuid(itemguid);
103 uint16 dstpos = dstslot | (INVENTORY_SLOT_BAG_0 << 8);
105 if(!item || item->GetPos() == dstpos)
106 return;
108 _player->SwapItem(item->GetPos(), dstpos);
111 void WorldSession::HandleSwapItem( WorldPacket & recv_data )
113 //sLog.outDebug("WORLD: CMSG_SWAP_ITEM");
114 uint8 dstbag, dstslot, srcbag, srcslot;
116 recv_data >> dstbag >> dstslot >> srcbag >> srcslot ;
117 //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u", srcbag, srcslot, dstbag, dstslot);
119 uint16 src = ( (srcbag << 8) | srcslot );
120 uint16 dst = ( (dstbag << 8) | dstslot );
122 // prevent attempt swap same item to current position generated by client at special cheating sequence
123 if(src == dst)
124 return;
126 if(!_player->IsValidPos(srcbag, srcslot, true))
128 _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
129 return;
132 if(!_player->IsValidPos(dstbag, dstslot, true))
134 _player->SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL );
135 return;
138 _player->SwapItem( src, dst );
141 void WorldSession::HandleAutoEquipItemOpcode( WorldPacket & recv_data )
143 //sLog.outDebug("WORLD: CMSG_AUTOEQUIP_ITEM");
144 uint8 srcbag, srcslot;
146 recv_data >> srcbag >> srcslot;
147 //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot);
149 Item *pSrcItem = _player->GetItemByPos( srcbag, srcslot );
150 if( !pSrcItem )
151 return; // only at cheat
153 uint16 dest;
154 uint8 msg = _player->CanEquipItem( NULL_SLOT, dest, pSrcItem, !pSrcItem->IsBag() );
155 if( msg != EQUIP_ERR_OK )
157 _player->SendEquipError( msg, pSrcItem, NULL );
158 return;
161 uint16 src = pSrcItem->GetPos();
162 if(dest == src) // prevent equip in same slot, only at cheat
163 return;
165 Item *pDstItem = _player->GetItemByPos( dest );
166 if( !pDstItem ) // empty slot, simple case
168 _player->RemoveItem( srcbag, srcslot, true );
169 _player->EquipItem( dest, pSrcItem, true );
170 _player->AutoUnequipOffhandIfNeed();
172 else // have currently equipped item, not simple case
174 uint8 dstbag = pDstItem->GetBagSlot();
175 uint8 dstslot = pDstItem->GetSlot();
177 msg = _player->CanUnequipItem( dest, !pSrcItem->IsBag() );
178 if( msg != EQUIP_ERR_OK )
180 _player->SendEquipError( msg, pDstItem, NULL );
181 return;
184 // check dest->src move possibility
185 ItemPosCountVec sSrc;
186 uint16 eSrc = 0;
187 if( _player->IsInventoryPos( src ) )
189 msg = _player->CanStoreItem( srcbag, srcslot, sSrc, pDstItem, true );
190 if( msg != EQUIP_ERR_OK )
191 msg = _player->CanStoreItem( srcbag, NULL_SLOT, sSrc, pDstItem, true );
192 if( msg != EQUIP_ERR_OK )
193 msg = _player->CanStoreItem( NULL_BAG, NULL_SLOT, sSrc, pDstItem, true );
195 else if( _player->IsBankPos( src ) )
197 msg = _player->CanBankItem( srcbag, srcslot, sSrc, pDstItem, true );
198 if( msg != EQUIP_ERR_OK )
199 msg = _player->CanBankItem( srcbag, NULL_SLOT, sSrc, pDstItem, true );
200 if( msg != EQUIP_ERR_OK )
201 msg = _player->CanBankItem( NULL_BAG, NULL_SLOT, sSrc, pDstItem, true );
203 else if( _player->IsEquipmentPos( src ) )
205 msg = _player->CanEquipItem( srcslot, eSrc, pDstItem, true);
206 if( msg == EQUIP_ERR_OK )
207 msg = _player->CanUnequipItem( eSrc, true);
210 if( msg != EQUIP_ERR_OK )
212 _player->SendEquipError( msg, pDstItem, pSrcItem );
213 return;
216 // now do moves, remove...
217 _player->RemoveItem(dstbag, dstslot, false);
218 _player->RemoveItem(srcbag, srcslot, false);
220 // add to dest
221 _player->EquipItem(dest, pSrcItem, true);
223 // add to src
224 if( _player->IsInventoryPos( src ) )
225 _player->StoreItem(sSrc, pDstItem, true);
226 else if( _player->IsBankPos( src ) )
227 _player->BankItem(sSrc, pDstItem, true);
228 else if( _player->IsEquipmentPos( src ) )
229 _player->EquipItem(eSrc, pDstItem, true);
231 _player->AutoUnequipOffhandIfNeed();
235 void WorldSession::HandleDestroyItemOpcode( WorldPacket & recv_data )
237 //sLog.outDebug("WORLD: CMSG_DESTROYITEM");
238 uint8 bag, slot, count, data1, data2, data3;
240 recv_data >> bag >> slot >> count >> data1 >> data2 >> data3;
241 //sLog.outDebug("STORAGE: receive bag = %u, slot = %u, count = %u", bag, slot, count);
243 uint16 pos = (bag << 8) | slot;
245 // prevent drop unequipable items (in combat, for example) and non-empty bags
246 if(_player->IsEquipmentPos(pos) || _player->IsBagPos(pos))
248 uint8 msg = _player->CanUnequipItem( pos, false );
249 if( msg != EQUIP_ERR_OK )
251 _player->SendEquipError( msg, _player->GetItemByPos(pos), NULL );
252 return;
256 Item *pItem = _player->GetItemByPos( bag, slot );
257 if(!pItem)
259 _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
260 return;
263 if(count)
265 uint32 i_count = count;
266 _player->DestroyItemCount( pItem, i_count, true );
268 else
269 _player->DestroyItem( bag, slot, true );
272 // Only _static_ data send in this packet !!!
273 void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
275 //sLog.outDebug("WORLD: CMSG_ITEM_QUERY_SINGLE");
276 uint32 item;
277 recv_data >> item;
279 sLog.outDetail("STORAGE: Item Query = %u", item);
281 ItemPrototype const *pProto = ObjectMgr::GetItemPrototype( item );
282 if( pProto )
284 std::string Name = pProto->Name1;
285 std::string Description = pProto->Description;
287 int loc_idx = GetSessionDbLocaleIndex();
288 if ( loc_idx >= 0 )
290 ItemLocale const *il = sObjectMgr.GetItemLocale(pProto->ItemId);
291 if (il)
293 if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty())
294 Name = il->Name[loc_idx];
295 if (il->Description.size() > size_t(loc_idx) && !il->Description[loc_idx].empty())
296 Description = il->Description[loc_idx];
299 // guess size
300 WorldPacket data( SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600);
301 data << pProto->ItemId;
302 data << pProto->Class;
303 data << pProto->SubClass;
304 data << int32(pProto->Unk0); // new 2.0.3, not exist in wdb cache?
305 data << Name;
306 data << uint8(0x00); //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name...
307 data << uint8(0x00); //pProto->Name3; // blizz not send name there, just uint8(0x00);
308 data << uint8(0x00); //pProto->Name4; // blizz not send name there, just uint8(0x00);
309 data << pProto->DisplayInfoID;
310 data << pProto->Quality;
311 data << pProto->Flags;
312 data << pProto->Faction; // 3.2 faction?
313 data << pProto->BuyPrice;
314 data << pProto->SellPrice;
315 data << pProto->InventoryType;
316 data << pProto->AllowableClass;
317 data << pProto->AllowableRace;
318 data << pProto->ItemLevel;
319 data << pProto->RequiredLevel;
320 data << pProto->RequiredSkill;
321 data << pProto->RequiredSkillRank;
322 data << pProto->RequiredSpell;
323 data << pProto->RequiredHonorRank;
324 data << pProto->RequiredCityRank;
325 data << pProto->RequiredReputationFaction;
326 data << pProto->RequiredReputationRank;
327 data << int32(pProto->MaxCount);
328 data << int32(pProto->Stackable);
329 data << pProto->ContainerSlots;
330 data << pProto->StatsCount; // item stats count
331 for(uint32 i = 0; i < pProto->StatsCount; ++i)
333 data << pProto->ItemStat[i].ItemStatType;
334 data << pProto->ItemStat[i].ItemStatValue;
336 data << pProto->ScalingStatDistribution; // scaling stats distribution
337 data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column
338 for(int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
340 data << pProto->Damage[i].DamageMin;
341 data << pProto->Damage[i].DamageMax;
342 data << pProto->Damage[i].DamageType;
345 // resistances (7)
346 data << pProto->Armor;
347 data << pProto->HolyRes;
348 data << pProto->FireRes;
349 data << pProto->NatureRes;
350 data << pProto->FrostRes;
351 data << pProto->ShadowRes;
352 data << pProto->ArcaneRes;
354 data << pProto->Delay;
355 data << pProto->AmmoType;
356 data << pProto->RangedModRange;
358 for(int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
360 // send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown
361 // use `item_template` or if not set then only use spell cooldowns
362 SpellEntry const* spell = sSpellStore.LookupEntry(pProto->Spells[s].SpellId);
363 if(spell)
365 bool db_data = pProto->Spells[s].SpellCooldown >= 0 || pProto->Spells[s].SpellCategoryCooldown >= 0;
367 data << pProto->Spells[s].SpellId;
368 data << pProto->Spells[s].SpellTrigger;
369 data << uint32(-abs(pProto->Spells[s].SpellCharges));
371 if(db_data)
373 data << uint32(pProto->Spells[s].SpellCooldown);
374 data << uint32(pProto->Spells[s].SpellCategory);
375 data << uint32(pProto->Spells[s].SpellCategoryCooldown);
377 else
379 data << uint32(spell->RecoveryTime);
380 data << uint32(spell->Category);
381 data << uint32(spell->CategoryRecoveryTime);
384 else
386 data << uint32(0);
387 data << uint32(0);
388 data << uint32(0);
389 data << uint32(-1);
390 data << uint32(0);
391 data << uint32(-1);
394 data << pProto->Bonding;
395 data << Description;
396 data << pProto->PageText;
397 data << pProto->LanguageID;
398 data << pProto->PageMaterial;
399 data << pProto->StartQuest;
400 data << pProto->LockID;
401 data << int32(pProto->Material);
402 data << pProto->Sheath;
403 data << pProto->RandomProperty;
404 data << pProto->RandomSuffix;
405 data << pProto->Block;
406 data << pProto->ItemSet;
407 data << pProto->MaxDurability;
408 data << pProto->Area;
409 data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch
410 data << pProto->BagFamily;
411 data << pProto->TotemCategory;
412 for(int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s)
414 data << pProto->Socket[s].Color;
415 data << pProto->Socket[s].Content;
417 data << pProto->socketBonus;
418 data << pProto->GemProperties;
419 data << pProto->RequiredDisenchantSkill;
420 data << pProto->ArmorDamageModifier;
421 data << abs(pProto->Duration); // added in 2.4.2.8209, duration (seconds)
422 data << pProto->ItemLimitCategory; // WotLK, ItemLimitCategory
423 data << pProto->HolidayId; // Holiday.dbc?
424 SendPacket( &data );
426 else
428 sLog.outDebug( "WORLD: CMSG_ITEM_QUERY_SINGLE - NO item INFO! (ENTRY: %u)", item );
429 WorldPacket data( SMSG_ITEM_QUERY_SINGLE_RESPONSE, 4);
430 data << uint32(item | 0x80000000);
431 SendPacket( &data );
435 void WorldSession::HandleReadItem( WorldPacket & recv_data )
437 //sLog.outDebug( "WORLD: CMSG_READ_ITEM");
439 uint8 bag, slot;
440 recv_data >> bag >> slot;
442 //sLog.outDetail("STORAGE: Read bag = %u, slot = %u", bag, slot);
443 Item *pItem = _player->GetItemByPos( bag, slot );
445 if( pItem && pItem->GetProto()->PageText )
447 WorldPacket data;
449 uint8 msg = _player->CanUseItem( pItem );
450 if( msg == EQUIP_ERR_OK )
452 data.Initialize (SMSG_READ_ITEM_OK, 8);
453 sLog.outDetail("STORAGE: Item page sent");
455 else
457 data.Initialize( SMSG_READ_ITEM_FAILED, 8 );
458 sLog.outDetail("STORAGE: Unable to read item");
459 _player->SendEquipError( msg, pItem, NULL );
461 data << pItem->GetGUID();
462 SendPacket(&data);
464 else
465 _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
468 void WorldSession::HandlePageQuerySkippedOpcode( WorldPacket & recv_data )
470 sLog.outDebug( "WORLD: Received CMSG_PAGE_TEXT_QUERY" );
472 uint32 itemid;
473 uint64 guid;
475 recv_data >> itemid >> guid;
477 sLog.outDetail( "Packet Info: itemid: %u guidlow: %u guidentry: %u guidhigh: %u",
478 itemid, GUID_LOPART(guid), GUID_ENPART(guid), GUID_HIPART(guid));
481 void WorldSession::HandleSellItemOpcode( WorldPacket & recv_data )
483 sLog.outDebug( "WORLD: Received CMSG_SELL_ITEM" );
484 uint64 vendorguid, itemguid;
485 uint32 count;
487 recv_data >> vendorguid >> itemguid >> count;
489 if(!itemguid)
490 return;
492 Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR);
493 if (!pCreature)
495 sLog.outDebug( "WORLD: HandleSellItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) );
496 _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, itemguid, 0);
497 return;
500 // remove fake death
501 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
502 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
504 Item *pItem = _player->GetItemByGuid( itemguid );
505 if( pItem )
507 // prevent sell not owner item
508 if(_player->GetGUID() != pItem->GetOwnerGUID())
510 _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0);
511 return;
514 // prevent sell non empty bag by drag-and-drop at vendor's item list
515 if(pItem->IsBag() && !((Bag*)pItem)->IsEmpty())
517 _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0);
518 return;
521 // prevent sell currently looted item
522 if(_player->GetLootGUID() == pItem->GetGUID())
524 _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0);
525 return;
528 // special case at auto sell (sell all)
529 if(count == 0)
531 count = pItem->GetCount();
533 else
535 // prevent sell more items that exist in stack (possible only not from client)
536 if(count > pItem->GetCount())
538 _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0);
539 return;
543 ItemPrototype const *pProto = pItem->GetProto();
544 if( pProto )
546 if( pProto->SellPrice > 0 )
548 if(count < pItem->GetCount()) // need split items
550 Item *pNewItem = pItem->CloneItem( count, _player );
551 if (!pNewItem)
553 sLog.outError("WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), count );
554 _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0);
555 return;
558 pItem->SetCount( pItem->GetCount() - count );
559 _player->ItemRemovedQuestCheck( pItem->GetEntry(), count );
560 if( _player->IsInWorld() )
561 pItem->SendCreateUpdateToPlayer( _player );
562 pItem->SetState(ITEM_CHANGED, _player);
564 _player->AddItemToBuyBackSlot( pNewItem );
565 if( _player->IsInWorld() )
566 pNewItem->SendCreateUpdateToPlayer( _player );
568 else
570 _player->ItemRemovedQuestCheck( pItem->GetEntry(), pItem->GetCount());
571 _player->RemoveItem( pItem->GetBagSlot(), pItem->GetSlot(), true);
572 pItem->RemoveFromUpdateQueueOf(_player);
573 _player->AddItemToBuyBackSlot( pItem );
576 _player->ModifyMoney( pProto->SellPrice * count );
578 else
579 _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0);
580 return;
583 _player->SendSellError( SELL_ERR_CANT_FIND_ITEM, pCreature, itemguid, 0);
584 return;
587 void WorldSession::HandleBuybackItem(WorldPacket & recv_data)
589 sLog.outDebug( "WORLD: Received CMSG_BUYBACK_ITEM" );
590 uint64 vendorguid;
591 uint32 slot;
593 recv_data >> vendorguid >> slot;
595 Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR);
596 if (!pCreature)
598 sLog.outDebug( "WORLD: HandleBuybackItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) );
599 _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0);
600 return;
603 // remove fake death
604 if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
605 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
607 Item *pItem = _player->GetItemFromBuyBackSlot( slot );
608 if( pItem )
610 uint32 price = _player->GetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + slot - BUYBACK_SLOT_START );
611 if( _player->GetMoney() < price )
613 _player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, pItem->GetEntry(), 0);
614 return;
617 ItemPosCountVec dest;
618 uint8 msg = _player->CanStoreItem( NULL_BAG, NULL_SLOT, dest, pItem, false );
619 if( msg == EQUIP_ERR_OK )
621 _player->ModifyMoney( -(int32)price );
622 _player->RemoveItemFromBuyBackSlot( slot, false );
623 _player->ItemAddedQuestCheck( pItem->GetEntry(), pItem->GetCount());
624 _player->StoreItem( dest, pItem, true );
626 else
627 _player->SendEquipError( msg, pItem, NULL );
628 return;
630 else
631 _player->SendBuyError( BUY_ERR_CANT_FIND_ITEM, pCreature, 0, 0);
634 void WorldSession::HandleBuyItemInSlotOpcode( WorldPacket & recv_data )
636 sLog.outDebug( "WORLD: Received CMSG_BUY_ITEM_IN_SLOT" );
637 uint64 vendorguid, bagguid;
638 uint32 item, slot, count;
639 uint8 bagslot;
641 recv_data >> vendorguid >> item >> slot >> bagguid >> bagslot >> count;
643 uint8 bag = NULL_BAG; // init for case invalid bagGUID
645 // find bag slot by bag guid
646 if (bagguid == _player->GetGUID())
647 bag = INVENTORY_SLOT_BAG_0;
648 else
650 for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END;++i)
652 if (Bag *pBag = (Bag*)_player->GetItemByPos(INVENTORY_SLOT_BAG_0,i))
654 if (bagguid == pBag->GetGUID())
656 bag = i;
657 break;
663 // bag not found, cheating?
664 if (bag == NULL_BAG)
665 return;
667 GetPlayer()->BuyItemFromVendor(vendorguid, item, count, bag, bagslot);
670 void WorldSession::HandleBuyItemOpcode( WorldPacket & recv_data )
672 sLog.outDebug( "WORLD: Received CMSG_BUY_ITEM" );
673 uint64 vendorguid;
674 uint32 item, slot, count;
675 uint8 unk1;
677 recv_data >> vendorguid >> item >> slot >> count >> unk1;
679 GetPlayer()->BuyItemFromVendor(vendorguid, item, count, NULL_BAG, NULL_SLOT);
682 void WorldSession::HandleListInventoryOpcode( WorldPacket & recv_data )
684 uint64 guid;
686 recv_data >> guid;
688 if(!GetPlayer()->isAlive())
689 return;
691 sLog.outDebug( "WORLD: Recvd CMSG_LIST_INVENTORY" );
693 SendListInventory( guid );
696 void WorldSession::SendListInventory(uint64 vendorguid)
698 sLog.outDebug("WORLD: Sent SMSG_LIST_INVENTORY");
700 Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR);
702 if (!pCreature)
704 sLog.outDebug("WORLD: SendListInventory - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)));
705 _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0);
706 return;
709 // remove fake death
710 if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
711 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
713 // Stop the npc if moving
714 if (!pCreature->IsStopped())
715 pCreature->StopMoving();
717 VendorItemData const* vItems = pCreature->GetVendorItems();
719 if (!vItems)
721 _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0);
722 return;
725 uint8 numitems = vItems->GetItemCount();
726 uint8 count = 0;
728 WorldPacket data( SMSG_LIST_INVENTORY, (8+1+numitems*8*4) );
729 data << uint64(vendorguid);
730 data << uint8(numitems);
732 float discountMod = _player->GetReputationPriceDiscount(pCreature);
734 for(int i = 0; i < numitems; ++i )
736 if(VendorItem const* crItem = vItems->GetItem(i))
738 if(ItemPrototype const *pProto = ObjectMgr::GetItemPrototype(crItem->item))
740 if((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP && !_player->isGameMaster())
741 continue;
743 ++count;
745 // reputation discount
746 uint32 price = uint32(floor(pProto->BuyPrice * discountMod));
748 data << uint32(count);
749 data << uint32(crItem->item);
750 data << uint32(pProto->DisplayInfoID);
751 data << uint32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem));
752 data << uint32(price);
753 data << uint32(pProto->MaxDurability);
754 data << uint32(pProto->BuyCount);
755 data << uint32(crItem->ExtendedCost);
760 if ( count == 0 || data.size() != 8 + 1 + size_t(count) * 8 * 4 )
761 return;
763 data.put<uint8>(8, count);
764 SendPacket( &data );
767 void WorldSession::HandleAutoStoreBagItemOpcode( WorldPacket & recv_data )
769 //sLog.outDebug("WORLD: CMSG_AUTOSTORE_BAG_ITEM");
770 uint8 srcbag, srcslot, dstbag;
772 recv_data >> srcbag >> srcslot >> dstbag;
773 //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u", srcbag, srcslot, dstbag);
775 Item *pItem = _player->GetItemByPos( srcbag, srcslot );
776 if( !pItem )
777 return;
779 if(!_player->IsValidPos(dstbag, NULL_SLOT, false)) // can be autostore pos
781 _player->SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL );
782 return;
785 uint16 src = pItem->GetPos();
787 // check unequip potability for equipped items and bank bags
788 if(_player->IsEquipmentPos ( src ) || _player->IsBagPos ( src ))
790 uint8 msg = _player->CanUnequipItem( src, !_player->IsBagPos ( src ));
791 if(msg != EQUIP_ERR_OK)
793 _player->SendEquipError( msg, pItem, NULL );
794 return;
798 ItemPosCountVec dest;
799 uint8 msg = _player->CanStoreItem( dstbag, NULL_SLOT, dest, pItem, false );
800 if( msg != EQUIP_ERR_OK )
802 _player->SendEquipError( msg, pItem, NULL );
803 return;
806 // no-op: placed in same slot
807 if(dest.size() == 1 && dest[0].pos == src)
809 // just remove gray item state
810 _player->SendEquipError( EQUIP_ERR_NONE, pItem, NULL );
811 return;
814 _player->RemoveItem(srcbag, srcslot, true );
815 _player->StoreItem( dest, pItem, true );
818 void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket)
820 sLog.outDebug("WORLD: CMSG_BUY_BANK_SLOT");
822 uint64 guid;
823 recvPacket >> guid;
825 // cheating protection
826 /* not critical if "cheated", and check skip allow by slots in bank windows open by .bank command.
827 Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER);
828 if(!pCreature)
830 sLog.outDebug( "WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
831 return;
835 uint32 slot = _player->GetBankBagSlotCount();
837 // next slot
838 ++slot;
840 sLog.outDetail("PLAYER: Buy bank bag slot, slot number = %u", slot);
842 BankBagSlotPricesEntry const* slotEntry = sBankBagSlotPricesStore.LookupEntry(slot);
844 if(!slotEntry)
845 return;
847 uint32 price = slotEntry->price;
849 if (_player->GetMoney() < price)
850 return;
852 _player->SetBankBagSlotCount(slot);
853 _player->ModifyMoney(-int32(price));
855 _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT);
858 void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket)
860 sLog.outDebug("WORLD: CMSG_AUTOBANK_ITEM");
861 uint8 srcbag, srcslot;
863 recvPacket >> srcbag >> srcslot;
864 sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot);
866 Item *pItem = _player->GetItemByPos( srcbag, srcslot );
867 if( !pItem )
868 return;
870 ItemPosCountVec dest;
871 uint8 msg = _player->CanBankItem( NULL_BAG, NULL_SLOT, dest, pItem, false );
872 if( msg != EQUIP_ERR_OK )
874 _player->SendEquipError( msg, pItem, NULL );
875 return;
878 _player->RemoveItem(srcbag, srcslot, true);
879 _player->BankItem( dest, pItem, true );
882 void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket)
884 sLog.outDebug("WORLD: CMSG_AUTOSTORE_BANK_ITEM");
885 uint8 srcbag, srcslot;
887 recvPacket >> srcbag >> srcslot;
888 sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot);
890 Item *pItem = _player->GetItemByPos( srcbag, srcslot );
891 if( !pItem )
892 return;
894 if(_player->IsBankPos(srcbag, srcslot)) // moving from bank to inventory
896 ItemPosCountVec dest;
897 uint8 msg = _player->CanStoreItem( NULL_BAG, NULL_SLOT, dest, pItem, false );
898 if( msg != EQUIP_ERR_OK )
900 _player->SendEquipError( msg, pItem, NULL );
901 return;
904 _player->RemoveItem(srcbag, srcslot, true);
905 _player->StoreItem( dest, pItem, true );
907 else // moving from inventory to bank
909 ItemPosCountVec dest;
910 uint8 msg = _player->CanBankItem( NULL_BAG, NULL_SLOT, dest, pItem, false );
911 if( msg != EQUIP_ERR_OK )
913 _player->SendEquipError( msg, pItem, NULL );
914 return;
917 _player->RemoveItem(srcbag, srcslot, true);
918 _player->BankItem( dest, pItem, true );
922 void WorldSession::HandleSetAmmoOpcode(WorldPacket & recv_data)
924 if(!GetPlayer()->isAlive())
926 GetPlayer()->SendEquipError( EQUIP_ERR_YOU_ARE_DEAD, NULL, NULL );
927 return;
930 sLog.outDebug("WORLD: CMSG_SET_AMMO");
931 uint32 item;
933 recv_data >> item;
935 if(!item)
936 GetPlayer()->RemoveAmmo();
937 else
938 GetPlayer()->SetAmmo(item);
941 void WorldSession::SendEnchantmentLog(uint64 Target, uint64 Caster,uint32 ItemID,uint32 SpellID)
943 WorldPacket data(SMSG_ENCHANTMENTLOG, (8+8+4+4+1)); // last check 2.0.10
944 data << uint64(Target);
945 data << uint64(Caster);
946 data << uint32(ItemID);
947 data << uint32(SpellID);
948 data << uint8(0);
949 SendPacket(&data);
952 void WorldSession::SendItemEnchantTimeUpdate(uint64 Playerguid, uint64 Itemguid,uint32 slot,uint32 Duration)
954 // last check 2.0.10
955 WorldPacket data(SMSG_ITEM_ENCHANT_TIME_UPDATE, (8+4+4+8));
956 data << uint64(Itemguid);
957 data << uint32(slot);
958 data << uint32(Duration);
959 data << uint64(Playerguid);
960 SendPacket(&data);
963 void WorldSession::HandleItemNameQueryOpcode(WorldPacket & recv_data)
965 uint32 itemid;
966 recv_data >> itemid;
967 recv_data.read_skip<uint64>(); // guid
969 sLog.outDebug("WORLD: CMSG_ITEM_NAME_QUERY %u", itemid);
970 ItemPrototype const *pProto = ObjectMgr::GetItemPrototype( itemid );
971 if( pProto )
973 std::string Name;
974 Name = pProto->Name1;
976 int loc_idx = GetSessionDbLocaleIndex();
977 if (loc_idx >= 0)
979 ItemLocale const *il = sObjectMgr.GetItemLocale(pProto->ItemId);
980 if (il)
982 if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty())
983 Name = il->Name[loc_idx];
986 // guess size
987 WorldPacket data(SMSG_ITEM_NAME_QUERY_RESPONSE, (4+10));
988 data << uint32(pProto->ItemId);
989 data << Name;
990 data << uint32(pProto->InventoryType);
991 SendPacket(&data);
992 return;
994 else
996 // listed in dbc or not expected to exist unknown item
997 if(sItemStore.LookupEntry(itemid))
998 sLog.outErrorDb("WORLD: CMSG_ITEM_NAME_QUERY for item %u failed (item listed in Item.dbc but not exist in DB)", itemid);
999 else
1000 sLog.outError("WORLD: CMSG_ITEM_NAME_QUERY for item %u failed (unknown item, not listed in Item.dbc)", itemid);
1004 void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data)
1006 sLog.outDebug("Received opcode CMSG_WRAP_ITEM");
1008 uint8 gift_bag, gift_slot, item_bag, item_slot;
1009 //recv_data.hexlike();
1011 recv_data >> gift_bag >> gift_slot; // paper
1012 recv_data >> item_bag >> item_slot; // item
1014 sLog.outDebug("WRAP: receive gift_bag = %u, gift_slot = %u, item_bag = %u, item_slot = %u", gift_bag, gift_slot, item_bag, item_slot);
1016 Item *gift = _player->GetItemByPos( gift_bag, gift_slot );
1017 if(!gift)
1019 _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL );
1020 return;
1023 if(!gift->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPER))// cheating: non-wrapper wrapper
1025 _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL );
1026 return;
1029 Item *item = _player->GetItemByPos( item_bag, item_slot );
1031 if( !item )
1033 _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, item, NULL );
1034 return;
1037 if(item == gift) // not possible with packet from real client
1039 _player->SendEquipError( EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL );
1040 return;
1043 if(item->IsEquipped())
1045 _player->SendEquipError( EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED, item, NULL );
1046 return;
1049 if(item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED);
1051 _player->SendEquipError( EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL );
1052 return;
1055 if(item->IsBag())
1057 _player->SendEquipError( EQUIP_ERR_BAGS_CANT_BE_WRAPPED, item, NULL );
1058 return;
1061 if(item->IsSoulBound())
1063 _player->SendEquipError( EQUIP_ERR_BOUND_CANT_BE_WRAPPED, item, NULL );
1064 return;
1067 if(item->GetMaxStackCount() != 1)
1069 _player->SendEquipError( EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED, item, NULL );
1070 return;
1073 // maybe not correct check (it is better than nothing)
1074 if(item->GetProto()->MaxCount > 0)
1076 _player->SendEquipError( EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED, item, NULL );
1077 return;
1080 CharacterDatabase.BeginTransaction();
1081 CharacterDatabase.PExecute("INSERT INTO character_gifts VALUES ('%u', '%u', '%u', '%u')", GUID_LOPART(item->GetOwnerGUID()), item->GetGUIDLow(), item->GetEntry(), item->GetUInt32Value(ITEM_FIELD_FLAGS));
1082 item->SetEntry(gift->GetEntry());
1084 switch (item->GetEntry())
1086 case 5042: item->SetEntry( 5043); break;
1087 case 5048: item->SetEntry( 5044); break;
1088 case 17303: item->SetEntry(17302); break;
1089 case 17304: item->SetEntry(17305); break;
1090 case 17307: item->SetEntry(17308); break;
1091 case 21830: item->SetEntry(21831); break;
1093 item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID());
1094 item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED);
1095 item->SetState(ITEM_CHANGED, _player);
1097 if(item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance`
1099 // after save it will be impossible to remove the item from the queue
1100 item->RemoveFromUpdateQueueOf(_player);
1101 item->SaveToDB(); // item gave inventory record unchanged and can be save standalone
1103 CharacterDatabase.CommitTransaction();
1105 uint32 count = 1;
1106 _player->DestroyItemCount(gift, count, true);
1109 void WorldSession::HandleSocketOpcode(WorldPacket& recv_data)
1111 sLog.outDebug("WORLD: CMSG_SOCKET_GEMS");
1113 uint64 item_guid;
1114 uint64 gem_guids[MAX_GEM_SOCKETS];
1116 recv_data >> item_guid;
1117 if(!item_guid)
1118 return;
1120 for(int i = 0; i < MAX_GEM_SOCKETS; ++i)
1121 recv_data >> gem_guids[i];
1123 //cheat -> tried to socket same gem multiple times
1124 if ((gem_guids[0] && (gem_guids[0] == gem_guids[1] || gem_guids[0] == gem_guids[2])) ||
1125 (gem_guids[1] && (gem_guids[1] == gem_guids[2])))
1126 return;
1128 Item *itemTarget = _player->GetItemByGuid(item_guid);
1129 if(!itemTarget) //missing item to socket
1130 return;
1132 ItemPrototype const* itemProto = itemTarget->GetProto();
1133 if(!itemProto)
1134 return;
1136 //this slot is excepted when applying / removing meta gem bonus
1137 uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT);
1139 Item *Gems[MAX_GEM_SOCKETS];
1140 for(int i = 0; i < MAX_GEM_SOCKETS; ++i)
1141 Gems[i] = gem_guids[i] ? _player->GetItemByGuid(gem_guids[i]) : NULL;
1143 GemPropertiesEntry const *GemProps[MAX_GEM_SOCKETS];
1144 for(int i = 0; i < MAX_GEM_SOCKETS; ++i) //get geminfo from dbc storage
1145 GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetProto()->GemProperties) : NULL;
1147 for(int i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe
1149 if (!GemProps[i])
1150 continue;
1152 // tried to put gem in socket where no socket exists (take care about prismatic sockets)
1153 if (!itemProto->Socket[i].Color)
1155 // no prismatic socket
1156 if(!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
1157 return;
1159 // not first not-colored (not normally used) socket
1160 if(i != 0 && !itemProto->Socket[i - 1].Color && (i + 1 >= MAX_GEM_SOCKETS || itemProto->Socket[i + 1].Color))
1161 return;
1163 // ok, this is first not colored socket for item with prismatic socket
1166 // tried to put normal gem in meta socket
1167 if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META)
1168 return;
1170 // tried to put meta gem in normal socket
1171 if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META)
1172 return;
1175 uint32 GemEnchants[MAX_GEM_SOCKETS];
1176 uint32 OldEnchants[MAX_GEM_SOCKETS];
1177 for(int i = 0; i < MAX_GEM_SOCKETS; ++i) //get new and old enchantments
1179 GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0;
1180 OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + i));
1183 // check unique-equipped conditions
1184 for(int i = 0; i < MAX_GEM_SOCKETS; ++i)
1186 if(!Gems[i])
1187 continue;
1189 // continue check for case when attempt add 2 similar unique equipped gems in one item.
1190 ItemPrototype const* iGemProto = Gems[i]->GetProto();
1192 // unique item (for new and already placed bit removed enchantments
1193 if (iGemProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)
1195 for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
1197 if(i == j) // skip self
1198 continue;
1200 if (Gems[j])
1202 if (iGemProto->ItemId == Gems[j]->GetEntry())
1204 _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
1205 return;
1208 else if(OldEnchants[j])
1210 if(SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
1212 if (iGemProto->ItemId == enchantEntry->GemID)
1214 _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
1215 return;
1223 // unique limit type item
1224 int32 limit_newcount = 0;
1225 if (iGemProto->ItemLimitCategory)
1227 if(ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->ItemLimitCategory))
1229 for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
1231 if (Gems[j])
1233 // destroyed gem
1234 if (OldEnchants[j])
1236 if(SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
1237 if(ItemPrototype const* jProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID))
1238 if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory)
1239 --limit_newcount;
1242 // new gem
1243 if (iGemProto->ItemLimitCategory == Gems[j]->GetProto()->ItemLimitCategory)
1244 ++limit_newcount;
1246 // existed gem
1247 else if(OldEnchants[j])
1249 if(SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
1250 if(ItemPrototype const* jProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID))
1251 if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory)
1252 ++limit_newcount;
1256 if(limit_newcount > 0 && uint32(limit_newcount) > limitEntry->maxCount)
1258 _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
1259 return;
1264 // for equipped item check all equipment for duplicate equipped gems
1265 if(itemTarget->IsEquipped())
1267 if(uint8 res = _player->CanEquipUniqueItem(Gems[i], slot, limit_newcount >= 0 ? limit_newcount : 0))
1269 _player->SendEquipError( res, itemTarget, NULL );
1270 return;
1275 bool SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus
1276 _player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item)
1278 //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
1280 //remove ALL enchants
1281 for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot)
1282 _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), false);
1284 for(int i = 0; i < MAX_GEM_SOCKETS; ++i)
1286 if(GemEnchants[i])
1288 itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + i), GemEnchants[i], 0, 0);
1289 if(Item* guidItem = _player->GetItemByGuid(gem_guids[i]))
1290 _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true );
1294 for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot)
1295 _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), true);
1297 bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();// current socketbonus state
1298 if(SocketBonusActivated != SocketBonusToBeActivated) // if there was a change...
1300 _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT, false);
1301 itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetProto()->socketBonus : 0), 0, 0);
1302 _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, true);
1303 //it is not displayed, client has an inbuilt system to determine if the bonus is activated
1306 _player->ToggleMetaGemsActive(slot, true); // turn on all metagems (except for target item)
1309 void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPacket& recv_data)
1311 sLog.outDebug("WORLD: CMSG_CANCEL_TEMP_ENCHANTMENT");
1313 uint32 eslot;
1315 recv_data >> eslot;
1317 // apply only to equipped item
1318 if(!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, eslot))
1319 return;
1321 Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, eslot);
1323 if(!item)
1324 return;
1326 if(!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
1327 return;
1329 GetPlayer()->ApplyEnchantment(item, TEMP_ENCHANTMENT_SLOT, false);
1330 item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT);
1333 void WorldSession::HandleItemRefundInfoRequest(WorldPacket& recv_data)
1335 sLog.outDebug("WORLD: CMSG_ITEM_REFUND_INFO_REQUEST");
1337 uint64 guid;
1338 recv_data >> guid; // item guid
1340 Item *item = _player->GetItemByGuid(guid);
1342 if(!item)
1344 sLog.outDebug("Item refund: item not found!");
1345 return;
1348 if(!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE))
1350 sLog.outDebug("Item refund: item not refundable!");
1351 return;
1354 // item refund system not implemented yet