TrinityCore
Loading...
Searching...
No Matches
ItemHandler.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "WorldSession.h"
19#include "BattlePetMgr.h"
20#include "Common.h"
21#include "Creature.h"
22#include "DatabaseEnv.h"
23#include "DB2Stores.h"
24#include "GossipDef.h"
25#include "Item.h"
26#include "ItemPackets.h"
27#include "Log.h"
28#include "NPCPackets.h"
29#include "ObjectMgr.h"
30#include "Player.h"
31#include "World.h"
32
34{
35 if (!splitItem.Inv.Items.empty())
36 {
37 TC_LOG_ERROR("network", "HandleSplitItemOpcode - Invalid ItemCount ({})", splitItem.Inv.Items.size());
38 return;
39 }
40
41 TC_LOG_DEBUG("network", "HandleSplitItemOpcode: receive FromPackSlot: {}, FromSlot: {}, ToPackSlot: {}, ToSlot: {}, Quantity: {}",
42 splitItem.FromPackSlot, splitItem.FromSlot, splitItem.ToPackSlot, splitItem.ToSlot, splitItem.Quantity);
43
44 uint16 src = ((splitItem.FromPackSlot << 8) | splitItem.FromSlot);
45 uint16 dst = ((splitItem.ToPackSlot << 8) | splitItem.ToSlot);
46
47 if (src == dst)
48 return;
49
50 // check count - if zero it's fake packet
51 if (!splitItem.Quantity)
52 return;
53
54 if (!_player->IsValidPos(splitItem.FromPackSlot, splitItem.FromSlot, true))
55 {
57 return;
58 }
59
60 if (!_player->IsValidPos(splitItem.ToPackSlot, splitItem.ToSlot, false)) // can be autostore pos
61 {
63 return;
64 }
65
66 _player->SplitItem(src, dst, splitItem.Quantity);
67}
68
70{
71 if (swapInvItem.Inv.Items.size() != 2)
72 {
73 TC_LOG_ERROR("network", "HandleSwapInvItemOpcode - Invalid itemCount ({})", swapInvItem.Inv.Items.size());
74 return;
75 }
76
77 TC_LOG_DEBUG("network", "HandleSwapInvItemOpcode: receive Slot1: {}, Slot2: {}",
78 swapInvItem.Slot1, swapInvItem.Slot2);
79
80 // prevent attempt swap same item to current position generated by client at special checting sequence
81 if (swapInvItem.Slot1 == swapInvItem.Slot2)
82 return;
83
84 if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, swapInvItem.Slot1, true))
85 {
87 return;
88 }
89
90 if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, swapInvItem.Slot2, true))
91 {
93 return;
94 }
95
96 if (_player->IsBankPos(INVENTORY_SLOT_BAG_0, swapInvItem.Slot1) && !CanUseBank())
97 {
98 TC_LOG_DEBUG("network", "HandleSwapInvItemOpcode - Unit ({}) not found or you can't interact with him.", _player->PlayerTalkClass->GetInteractionData().SourceGuid.ToString());
99 return;
100 }
101
102 if (_player->IsBankPos(INVENTORY_SLOT_BAG_0, swapInvItem.Slot2) && !CanUseBank())
103 {
104 TC_LOG_DEBUG("network", "HandleSwapInvItemOpcode - Unit ({}) not found or you can't interact with him.", _player->PlayerTalkClass->GetInteractionData().SourceGuid.ToString());
105 return;
106 }
107
108 uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | swapInvItem.Slot1);
109 uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | swapInvItem.Slot2);
110
111 _player->SwapItem(src, dst);
112}
113
115{
116 // cheating attempt, client should never send opcode in that case
117 if (autoEquipItemSlot.Inv.Items.size() != 1 || !Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, autoEquipItemSlot.ItemDstSlot))
118 return;
119
120 Item* item = _player->GetItemByGuid(autoEquipItemSlot.Item);
121 uint16 dstPos = autoEquipItemSlot.ItemDstSlot | (INVENTORY_SLOT_BAG_0 << 8);
122 uint16 srcPos = autoEquipItemSlot.Inv.Items[0].Slot | (uint32(autoEquipItemSlot.Inv.Items[0].ContainerSlot) << 8);
123
124 if (!item || item->GetPos() != srcPos || srcPos == dstPos)
125 return;
126
127 _player->SwapItem(srcPos, dstPos);
128}
129
131{
132 if (swapItem.Inv.Items.size() != 2)
133 {
134 TC_LOG_ERROR("network", "HandleSwapItem - Invalid itemCount ({})", swapItem.Inv.Items.size());
135 return;
136 }
137
138 TC_LOG_DEBUG("network", "HandleSwapItem: receive ContainerSlotA: {}, SlotA: {}, ContainerSlotB: {}, SlotB: {}",
139 swapItem.ContainerSlotA, swapItem.SlotA, swapItem.ContainerSlotB, swapItem.SlotB);
140
141 uint16 src = ((swapItem.ContainerSlotA << 8) | swapItem.SlotA);
142 uint16 dst = ((swapItem.ContainerSlotB << 8) | swapItem.SlotB);
143
144 // prevent attempt swap same item to current position generated by client at special checting sequence
145 if (src == dst)
146 return;
147
148 if (!_player->IsValidPos(swapItem.ContainerSlotA, swapItem.SlotA, true))
149 {
151 return;
152 }
153
154 if (!_player->IsValidPos(swapItem.ContainerSlotB, swapItem.SlotB, true))
155 {
157 return;
158 }
159
160 if (_player->IsBankPos(swapItem.ContainerSlotA, swapItem.SlotA) && !CanUseBank())
161 {
162 TC_LOG_DEBUG("network", "HandleSwapItem - Unit ({}) not found or you can't interact with him.", _player->PlayerTalkClass->GetInteractionData().SourceGuid.ToString());
163 return;
164 }
165
166 if (_player->IsBankPos(swapItem.ContainerSlotB, swapItem.SlotB) && !CanUseBank())
167 {
168 TC_LOG_DEBUG("network", "HandleSwapItem - Unit ({}) not found or you can't interact with him.", _player->PlayerTalkClass->GetInteractionData().SourceGuid.ToString());
169 return;
170 }
171
172 _player->SwapItem(src, dst);
173}
174
176{
177 if (autoEquipItem.Inv.Items.size() != 1)
178 {
179 TC_LOG_ERROR("network", "HandleAutoEquipItemOpcode - Invalid itemCount ({})", autoEquipItem.Inv.Items.size());
180 return;
181 }
182
183 TC_LOG_DEBUG("network", "HandleAutoEquipItemOpcode: receive PackSlot: {}, Slot: {}",
184 autoEquipItem.PackSlot, autoEquipItem.Slot);
185
186 Item* srcItem = _player->GetItemByPos(autoEquipItem.PackSlot, autoEquipItem.Slot);
187 if (!srcItem)
188 return; // only at cheat
189
190 uint16 dest;
191 InventoryResult msg = _player->CanEquipItem(NULL_SLOT, dest, srcItem, !srcItem->IsBag());
192 if (msg != EQUIP_ERR_OK)
193 {
194 _player->SendEquipError(msg, srcItem);
195 return;
196 }
197
198 uint16 src = srcItem->GetPos();
199 if (dest == src) // prevent equip in same slot, only at cheat
200 return;
201
202 Item* dstItem = _player->GetItemByPos(dest);
203 if (!dstItem) // empty slot, simple case
204 {
205 if (!srcItem->GetChildItem().IsEmpty())
206 {
207 InventoryResult childEquipResult = _player->CanEquipChildItem(srcItem);
208 if (childEquipResult != EQUIP_ERR_OK)
209 {
210 _player->SendEquipError(msg, srcItem);
211 return;
212 }
213 }
214
215 _player->RemoveItem(autoEquipItem.PackSlot, autoEquipItem.Slot, true);
216 _player->EquipItem(dest, srcItem, true);
217 if (!srcItem->GetChildItem().IsEmpty())
218 _player->EquipChildItem(autoEquipItem.PackSlot, autoEquipItem.Slot, srcItem);
219
221 }
222 else // have currently equipped item, not simple case
223 {
224 uint8 dstbag = dstItem->GetBagSlot();
225 uint8 dstslot = dstItem->GetSlot();
226
227 msg = _player->CanUnequipItem(dest, !srcItem->IsBag());
228 if (msg != EQUIP_ERR_OK)
229 {
230 _player->SendEquipError(msg, dstItem);
231 return;
232 }
233
234 if (!dstItem->HasItemFlag(ITEM_FIELD_FLAG_CHILD))
235 {
236 // check dest->src move possibility
237 ItemPosCountVec sSrc;
238 uint16 eSrc = 0;
239 if (_player->IsInventoryPos(src))
240 {
241 msg = _player->CanStoreItem(autoEquipItem.PackSlot, autoEquipItem.Slot, sSrc, dstItem, true);
242 if (msg != EQUIP_ERR_OK)
243 msg = _player->CanStoreItem(autoEquipItem.PackSlot, NULL_SLOT, sSrc, dstItem, true);
244 if (msg != EQUIP_ERR_OK)
245 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true);
246 }
247 else if (_player->IsBankPos(src))
248 {
249 msg = _player->CanBankItem(autoEquipItem.PackSlot, autoEquipItem.Slot, sSrc, dstItem, true);
250 if (msg != EQUIP_ERR_OK)
251 msg = _player->CanBankItem(autoEquipItem.PackSlot, NULL_SLOT, sSrc, dstItem, true);
252 if (msg != EQUIP_ERR_OK)
253 msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true);
254 }
255 else if (_player->IsEquipmentPos(src))
256 {
257 msg = _player->CanEquipItem(autoEquipItem.Slot, eSrc, dstItem, true);
258 if (msg == EQUIP_ERR_OK)
259 msg = _player->CanUnequipItem(eSrc, true);
260 }
261
262 if (msg == EQUIP_ERR_OK && Player::IsEquipmentPos(dest) && !srcItem->GetChildItem().IsEmpty())
263 msg = _player->CanEquipChildItem(srcItem);
264
265 if (msg != EQUIP_ERR_OK)
266 {
267 _player->SendEquipError(msg, dstItem, srcItem);
268 return;
269 }
270
271 // now do moves, remove...
272 _player->RemoveItem(dstbag, dstslot, false);
273 _player->RemoveItem(autoEquipItem.PackSlot, autoEquipItem.Slot, false);
274
275 // add to dest
276 _player->EquipItem(dest, srcItem, true);
277
278 // add to src
279 if (_player->IsInventoryPos(src))
280 _player->StoreItem(sSrc, dstItem, true);
281 else if (_player->IsBankPos(src))
282 _player->BankItem(sSrc, dstItem, true);
283 else if (_player->IsEquipmentPos(src))
284 _player->EquipItem(eSrc, dstItem, true);
285
286 if (Player::IsEquipmentPos(dest) && !srcItem->GetChildItem().IsEmpty())
287 _player->EquipChildItem(autoEquipItem.PackSlot, autoEquipItem.Slot, srcItem);
288 }
289 else
290 {
291 if (Item* parentItem = _player->GetItemByGuid(dstItem->GetCreator()))
292 {
293 if (Player::IsEquipmentPos(dest))
294 {
295 _player->AutoUnequipChildItem(parentItem);
296 // dest is now empty
297 _player->SwapItem(src, dest);
298 // src is now empty
299 _player->SwapItem(parentItem->GetPos(), src);
300 }
301 }
302 }
303
305
306 // if inventory item was moved, check if we can remove dependent auras, because they were not removed in Player::RemoveItem (update was set to false)
307 // do this after swaps are done, we pass nullptr because both weapons could be swapped and none of them should be ignored
308 if ((autoEquipItem.PackSlot == INVENTORY_SLOT_BAG_0 && autoEquipItem.Slot < REAGENT_BAG_SLOT_END) || (dstbag == INVENTORY_SLOT_BAG_0 && dstslot < REAGENT_BAG_SLOT_END))
309 _player->ApplyItemDependentAuras((Item*)nullptr, false);
310 }
311}
312
314{
315 TC_LOG_DEBUG("network", "HandleDestroyItemOpcode: receive ContainerId: {}, SlotNum: {}, Count: {}",
316 destroyItem.ContainerId, destroyItem.SlotNum, destroyItem.Count);
317
318 uint16 pos = (destroyItem.ContainerId << 8) | destroyItem.SlotNum;
319
320 // prevent drop unequipable items (in combat, for example) and non-empty bags
321 if (_player->IsEquipmentPos(pos) || _player->IsBagPos(pos))
322 {
323 InventoryResult msg = _player->CanUnequipItem(pos, false);
324 if (msg != EQUIP_ERR_OK)
325 {
327 return;
328 }
329 }
330
331 Item* item = _player->GetItemByPos(destroyItem.ContainerId, destroyItem.SlotNum);
332 if (!item)
333 {
335 return;
336 }
337
339 {
341 return;
342 }
343
344 if (destroyItem.Count)
345 _player->DestroyItemCount(item, destroyItem.Count, true);
346 else
347 _player->DestroyItem(destroyItem.ContainerId, destroyItem.SlotNum, true);
348}
349
351{
352 Item* item = _player->GetItemByPos(readItem.PackSlot, readItem.Slot);
353 if (item && item->GetTemplate()->GetPageText())
354 {
356 if (msg == EQUIP_ERR_OK)
357 {
359 packet.Item = item->GetGUID();
360 SendPacket(packet.Write());
361
362 TC_LOG_INFO("network", "STORAGE: Item page sent");
363 }
364 else
365 {
367 /*WorldPackets::Item::ReadItemResultFailed packet;
368 packet.Item = item->GetGUID();
369 packet.Subcode = ??;
370 packet.Delay = ??;
371 SendPacket(packet.Write());*/
372
373 TC_LOG_INFO("network", "STORAGE: Unable to read item");
374 _player->SendEquipError(msg, item, nullptr);
375 }
376 }
377 else
379}
380
382{
383 TC_LOG_DEBUG("network", "WORLD: Received CMSG_SELL_ITEM: Vendor {}, Item {}, Amount: {}",
384 sellItem.VendorGUID, sellItem.ItemGUID, sellItem.Amount);
385
387 if (!creature)
388 {
389 TC_LOG_DEBUG("network", "WORLD: HandleSellItemOpcode - {} not found or you can not interact with him.", sellItem.VendorGUID);
391 return;
392 }
393
395 {
397 return;
398 }
399
400 Item* pItem = _player->GetItemByGuid(sellItem.ItemGUID);
401 if (!pItem)
402 {
404 return;
405 }
406
407 // prevent selling item for sellprice when the item is still refundable
408 // this probably happens when right clicking a refundable item, the client sends both
409 // CMSG_SELL_ITEM and CMSG_REFUND_ITEM (unverified)
410 if (pItem->IsRefundable())
411 return;
412
413 // remove fake death
414 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
416
417 uint32 amount = sellItem.Amount ? sellItem.Amount : pItem->GetCount();
418
419 Optional<SellResult> sellResult = _player->CanSellItemToVendor(pItem, amount);
420 if (!sellResult)
421 sellResult = _player->SellItemToVendor(pItem, amount);
422
423 if (sellResult)
424 _player->SendSellError(*sellResult, creature, sellItem.ItemGUID);
425}
426
428{
430 if (!creature)
431 {
433 return;
434 }
435
437 {
439 return;
440 }
441
442 // remove fake death
443 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
445
446 // collect junk items first
447 std::vector<Item*> junkItems;
448 _player->ForEachItem(ItemSearchLocation::Inventory, [this, &junkItems](Item* item)
449 {
450 if (item->GetQuality() != ITEM_QUALITY_POOR)
452
453 if (item->IsRefundable())
455
456 // check per-bag junk sell exclusion
457 if (item->GetBagSlot() == INVENTORY_SLOT_BAG_0)
458 {
461 }
462 else
463 {
464 uint32 bagIndex = item->GetBagSlot() - INVENTORY_SLOT_BAG_START;
465 if (bagIndex < _player->m_activePlayerData->BagSlotFlags.size()
468 }
469
470 Optional<SellResult> sellError = _player->CanSellItemToVendor(item, item->GetCount());
471 if (!sellError)
472 junkItems.push_back(item);
473
475 });
476
477 auto itr = junkItems.begin();
478 auto end = junkItems.end();
479 Optional<SellResult> sellError;
480
481 // stop on first sell failure (gold cap reached)
482 for (; itr != end && !sellError; ++itr)
483 sellError = _player->SellItemToVendor(*itr, (*itr)->GetCount());
484}
485
487{
488 TC_LOG_DEBUG("network", "WORLD: Received CMSG_BUYBACK_ITEM: Vendor {}, Slot: {}", packet.VendorGUID.ToString(), packet.Slot);
489
491 if (!creature)
492 {
493 TC_LOG_DEBUG("network", "WORLD: HandleBuybackItem - Unit ({}) not found or you can not interact with him.", packet.VendorGUID.ToString());
495 return;
496 }
497
498 // remove fake death
499 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
501
502 Item* pItem = _player->GetItemFromBuyBackSlot(packet.Slot);
503 if (pItem)
504 {
505 uint32 price = _player->m_activePlayerData->BuybackPrice[packet.Slot - BUYBACK_SLOT_START];
506 if (!_player->HasEnoughMoney(uint64(price)))
507 {
509 return;
510 }
511
512 ItemPosCountVec dest;
513 InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false);
514 if (msg == EQUIP_ERR_OK)
515 {
516 _player->ModifyMoney(-(int32)price);
517 _player->RemoveItemFromBuyBackSlot(packet.Slot, false);
518 _player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount());
519 _player->StoreItem(dest, pItem, true);
520 }
521 else
522 _player->SendEquipError(msg, pItem, nullptr);
523 return;
524 }
525 else
527}
528
530{
531 // client expects count starting at 1, and we send vendorslot+1 to client already
532 if (packet.Muid > 0)
533 --packet.Muid;
534 else
535 return; // cheating
536
537 switch (packet.ItemType)
538 {
540 {
541 uint8 bag = NULL_BAG;
542 if (packet.ContainerGUID == GetPlayer()->GetGUID()) // The client sends the player guid when trying to store an item in the default backpack
544 else if (Item* bagItem = _player->GetItemByGuid(packet.ContainerGUID))
545 bag = bagItem->GetSlot();
546
547 GetPlayer()->BuyItemFromVendorSlot(packet.VendorGUID, packet.Muid, packet.Item.ItemID,
548 packet.Quantity, bag, packet.Slot);
549 break;
550 }
552 {
553 GetPlayer()->BuyCurrencyFromVendorSlot(packet.VendorGUID, packet.Muid, packet.Item.ItemID, packet.Quantity);
554 break;
555 }
556 default:
557 {
558 TC_LOG_DEBUG("network", "WORLD: received wrong itemType ({}) in HandleBuyItemOpcode", packet.ItemType);
559 break;
560 }
561 }
562}
563
565{
566 if (!GetPlayer()->IsAlive())
567 return;
568
569 SendListInventory(packet.Unit);
570}
571
573{
575 if (!vendor)
576 {
577 TC_LOG_DEBUG("network", "WORLD: SendListInventory - {} not found or you can not interact with him.", vendorGuid.ToString());
579 return;
580 }
581
582 // remove fake death
583 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
585
586 GetPlayer()->PlayerTalkClass->GetInteractionData().StartInteraction(vendorGuid, PlayerInteractionType::Vendor);
587
588 // Stop the npc if moving
590 vendor->PauseMovement(pause);
591 vendor->SetHomePosition(vendor->GetPosition());
592
593 VendorItemData const* vendorItems = vendor->GetVendorItems();
594 uint32 rawItemCount = vendorItems ? vendorItems->GetItemCount() : 0;
595
597 packet.Vendor = vendor->GetGUID();
598
599 packet.Items.resize(rawItemCount);
600
601 const float discountMod = _player->GetReputationPriceDiscount(vendor);
602 uint8 count = 0;
603 for (uint32 slot = 0; slot < rawItemCount; ++slot)
604 {
605 VendorItem const* vendorItem = vendorItems->GetItem(slot);
606 if (!vendorItem)
607 continue;
608
609 WorldPackets::NPC::VendorItem& item = packet.Items[count];
610
612 item.PlayerConditionFailed = vendorItem->PlayerConditionId;
613
614 if (vendorItem->Type == ITEM_VENDOR_TYPE_ITEM)
615 {
616 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(vendorItem->item);
617 if (!itemTemplate)
618 continue;
619
620 int32 leftInStock = !vendorItem->maxcount ? -1 : int32(vendor->GetVendorItemCurrentCount(vendorItem));
621 if (!_player->IsGameMaster()) // ignore conditions if GM on
622 {
623 // Respect allowed class
624 if (!(itemTemplate->GetAllowableClass() & _player->GetClassMask()) && itemTemplate->GetBonding() == BIND_ON_ACQUIRE)
625 continue;
626
627 // Only display items in vendor lists for the team the player is on
628 if ((itemTemplate->HasFlag(ITEM_FLAG2_FACTION_HORDE) && _player->GetTeam() == ALLIANCE) ||
629 (itemTemplate->HasFlag(ITEM_FLAG2_FACTION_ALLIANCE) && _player->GetTeam() == HORDE))
630 continue;
631
632 // Items sold out are not displayed in list
633 if (leftInStock == 0)
634 continue;
635 }
636
637 if (!sConditionMgr->IsObjectMeetingVendorItemConditions(vendor->GetEntry(), vendorItem->item, _player, vendor))
638 {
639 TC_LOG_DEBUG("condition", "SendListInventory: conditions not met for creature entry {} item {}", vendor->GetEntry(), vendorItem->item);
640 continue;
641 }
642
643 uint64 basePrice = itemTemplate->GetBuyPrice();
644 if (ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(vendorItem->ExtendedCost))
645 basePrice = iece->Money;
646
647 uint64 price = uint64(floor(basePrice * discountMod));
648
650 price -= CalculatePct(price, priceMod);
651
652 if (basePrice > 0)
653 price = std::max(uint64(1), price);
654
655 item.MuID = slot + 1; // client expects counting to start at 1
656 item.Type = vendorItem->Type;
657 item.Item.ItemID = vendorItem->item;
658 if (!vendorItem->BonusListIDs.empty())
659 {
660 item.Item.ItemBonus.emplace();
661 item.Item.ItemBonus->BonusListIDs = vendorItem->BonusListIDs;
662 }
663 item.Quantity = leftInStock;
664 item.Price = price;
665 item.StackCount = itemTemplate->GetBuyCount();
666 item.ExtendedCostID = vendorItem->ExtendedCost;
667 item.DoNotFilterOnVendor = vendorItem->IgnoreFiltering;
668 item.Refundable = itemTemplate->HasFlag(ITEM_FLAG_ITEM_PURCHASE_RECORD) && vendorItem->ExtendedCost && itemTemplate->GetMaxStackSize() == 1;
669
670 }
671 else if (vendorItem->Type == ITEM_VENDOR_TYPE_CURRENCY)
672 {
673 CurrencyTypesEntry const* currencyTemplate = sCurrencyTypesStore.LookupEntry(vendorItem->item);
674 if (!currencyTemplate)
675 continue;
676
677 if (!vendorItem->ExtendedCost)
678 continue; // there's no price defined for currencies, only extendedcost is used
679
680 item.MuID = slot + 1; // client expects counting to start at 1
681 item.Type = vendorItem->Type;
682 item.Item.ItemID = vendorItem->item;
683 item.StackCount = vendorItem->maxcount;
684 item.ExtendedCostID = vendorItem->ExtendedCost;
685 item.DoNotFilterOnVendor = vendorItem->IgnoreFiltering;
686 }
687 else
688 continue;
689
690 if (++count >= MAX_VENDOR_ITEMS)
691 break;
692 }
693
694 // Resize vector to real size (some items can be skipped due to checks)
695 packet.Items.resize(count);
696
698
699 SendPacket(packet.Write());
700}
701
703{
704 if (!packet.Inv.Items.empty())
705 {
706 TC_LOG_ERROR("network", "HandleAutoStoreBagItemOpcode - Invalid itemCount ({})", packet.Inv.Items.size());
707 return;
708 }
709
710 TC_LOG_DEBUG("network", "HandleAutoStoreBagItemOpcode: receive ContainerSlotA: {}, SlotA: {}, ContainerSlotB: {}",
711 packet.ContainerSlotA, packet.SlotA, packet.ContainerSlotB);
712
713 Item* item = _player->GetItemByPos(packet.ContainerSlotA, packet.SlotA);
714 if (!item)
715 return;
716
717 if (!_player->IsValidPos(packet.ContainerSlotB, NULL_SLOT, false)) // can be autostore pos
718 {
720 return;
721 }
722
723 uint16 src = item->GetPos();
724
725 // check unequip potability for equipped items and bank bags
726 if (_player->IsEquipmentPos(src) || _player->IsBagPos(src))
727 {
729 if (msg != EQUIP_ERR_OK)
730 {
731 _player->SendEquipError(msg, item);
732 return;
733 }
734 }
735
736 ItemPosCountVec dest;
737 InventoryResult msg = _player->CanStoreItem(packet.ContainerSlotB, NULL_SLOT, dest, item, false);
738 if (msg != EQUIP_ERR_OK)
739 {
740 _player->SendEquipError(msg, item);
741 return;
742 }
743
744 // no-op: placed in same slot
745 if (dest.size() == 1 && dest[0].pos == src)
746 {
747 // just remove grey item state
749 return;
750 }
751
752 _player->RemoveItem(packet.ContainerSlotA, packet.SlotA, true);
753 _player->StoreItem(dest, item, true);
754}
755
756void WorldSession::SendEnchantmentLog(ObjectGuid owner, ObjectGuid caster, ObjectGuid itemGuid, uint32 itemId, uint32 enchantId, uint32 enchantSlot)
757{
759 enchantmentLog.Owner = owner;
760 enchantmentLog.Caster = caster;
761 enchantmentLog.ItemGUID = itemGuid;
762 enchantmentLog.ItemID = itemId;
763 enchantmentLog.Enchantment = enchantId;
764 enchantmentLog.EnchantSlot = enchantSlot;
765 GetPlayer()->SendMessageToSet(enchantmentLog.Write(), true);
766}
767
769{
771 data.ItemGuid = Itemguid;
772 data.DurationLeft = Duration;
773 data.Slot = slot;
774 data.OwnerGuid = Playerguid;
775 SendPacket(data.Write());
776}
777
779{
780 if (packet.Inv.Items.size() != 2)
781 {
782 TC_LOG_ERROR("network", "HandleWrapItem - Invalid itemCount ({})", packet.Inv.Items.size());
783 return;
784 }
785
787 // Gift
788 uint8 giftContainerSlot = packet.Inv.Items[0].ContainerSlot;
789 uint8 giftSlot = packet.Inv.Items[0].Slot;
790 // Item
791 uint8 itemContainerSlot = packet.Inv.Items[1].ContainerSlot;
792 uint8 itemSlot = packet.Inv.Items[1].Slot;
793
794 TC_LOG_DEBUG("network", "HandleWrapItem - Receive giftContainerSlot = {}, giftSlot = {}, itemContainerSlot = {}, itemSlot = {}", giftContainerSlot, giftSlot, itemContainerSlot, itemSlot);
795
796 Item* gift = _player->GetItemByPos(giftContainerSlot, giftSlot);
797 if (!gift)
798 {
800 return;
801 }
802
803 if (!gift->GetTemplate()->HasFlag(ITEM_FLAG_IS_WRAPPER)) // cheating: non-wrapper wrapper
804 {
806 return;
807 }
808
809 Item* item = _player->GetItemByPos(itemContainerSlot, itemSlot);
810 if (!item)
811 {
813 return;
814 }
815
816 if (item == gift) // not possable with pacjket from real client
817 {
819 return;
820 }
821
822 if (item->IsEquipped())
823 {
825 return;
826 }
827
828 if (!item->GetGiftCreator().IsEmpty()) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED);
829 {
831 return;
832 }
833
834 if (item->IsBag())
835 {
837 return;
838 }
839
840 if (item->IsSoulBound())
841 {
843 return;
844 }
845
846 if (item->GetMaxStackCount() != 1)
847 {
849 return;
850 }
851
852 // maybe not correct check (it is better than nothing)
853 if (item->GetTemplate()->GetMaxCount() > 0)
854 {
856 return;
857 }
858
859 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
860
862 stmt->setUInt64(0, item->GetOwnerGUID().GetCounter());
863 stmt->setUInt64(1, item->GetGUID().GetCounter());
864 stmt->setUInt32(2, item->GetEntry());
865 stmt->setUInt32(3, item->m_itemData->DynamicFlags);
866 trans->Append(stmt);
867
868 item->SetEntry(gift->GetEntry());
869
870 switch (item->GetEntry())
871 {
874 break;
877 break;
880 break;
883 break;
886 break;
889 break;
890 default:
891 break;
892 }
893
897
898 if (item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance`
899 {
900 // after save it will be impossible to remove the item from the queue
902 item->SaveToDB(trans); // item gave inventory record unchanged and can be save standalone
903 }
904 CharacterDatabase.CommitTransaction(trans);
905
906 uint32 count = 1;
907 _player->DestroyItemCount(gift, count, true);
908}
909
911{
912 if (!socketGems.ItemGuid)
913 return;
914
915 //cheat -> tried to socket same gem multiple times
916 if ((!socketGems.GemItem[0].IsEmpty() && (socketGems.GemItem[0] == socketGems.GemItem[1] || socketGems.GemItem[0] == socketGems.GemItem[2])) ||
917 (!socketGems.GemItem[1].IsEmpty() && (socketGems.GemItem[1] == socketGems.GemItem[2])))
918 return;
919
920 Item* itemTarget = _player->GetItemByGuid(socketGems.ItemGuid);
921 if (!itemTarget) //missing item to socket
922 return;
923
924 ItemTemplate const* itemProto = itemTarget->GetTemplate();
925 if (!itemProto)
926 return;
927
928 //this slot is excepted when applying / removing meta gem bonus
929 uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT);
930
931 Item* gems[MAX_GEM_SOCKETS];
932 memset(gems, 0, sizeof(gems));
934 memset(gemData, 0, sizeof(gemData));
935 GemPropertiesEntry const* gemProperties[MAX_GEM_SOCKETS];
936 memset(gemProperties, 0, sizeof(gemProperties));
937 UF::SocketedGem const* oldGemData[MAX_GEM_SOCKETS];
938 memset(oldGemData, 0, sizeof(oldGemData));
939 for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i)
940 {
941 if (Item* gem = _player->GetItemByGuid(socketGems.GemItem[i]))
942 {
943 gems[i] = gem;
944 gemData[i].ItemId = gem->GetEntry();
945 gemData[i].Context = gem->m_itemData->Context;
946 for (std::size_t b = 0; b < gem->GetBonusListIDs().size() && b < 16; ++b)
947 gemData[i].BonusListIDs[b] = gem->GetBonusListIDs()[b];
948
949 gemProperties[i] = sGemPropertiesStore.LookupEntry(gem->GetTemplate()->GetGemProperties());
950 }
951
952 oldGemData[i] = itemTarget->GetGem(i);
953 }
954
955 // Find first prismatic socket
956 uint32 firstPrismatic = 0;
957 while (firstPrismatic < MAX_GEM_SOCKETS && itemTarget->GetSocketColor(firstPrismatic))
958 ++firstPrismatic;
959
960 for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe
961 {
962 if (!gemProperties[i])
963 continue;
964
965 uint32 acceptableGemTypeMask = SocketColorToGemTypeMask[itemTarget->GetSocketColor(i)];
966 // tried to put gem in socket where no socket exists (take care about prismatic sockets)
967 switch (itemTarget->GetSocketColor(i))
968 {
969 case 0:
970 {
971 // no prismatic socket
973 return;
974
975 if (i != firstPrismatic)
976 return;
977
978 acceptableGemTypeMask = SOCKET_COLOR_RED | SOCKET_COLOR_YELLOW | SOCKET_COLOR_BLUE;
979 break;
980 }
981 case 2:
982 case 3:
983 case 4:
984 // red, blue and yellow sockets accept any red/blue/yellow gem
985 acceptableGemTypeMask = SOCKET_COLOR_RED | SOCKET_COLOR_YELLOW | SOCKET_COLOR_BLUE;
986 break;
987 default:
988 break;
989 }
990
991 // Gem must match socket color
992 if (!(acceptableGemTypeMask & gemProperties[i]->Type))
993 return;
994 }
995
996 // check unique-equipped conditions
997 for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i)
998 {
999 if (!gems[i])
1000 continue;
1001
1002 // continue check for case when attempt add 2 similar unique equipped gems in one item.
1003 ItemTemplate const* iGemProto = gems[i]->GetTemplate();
1004
1005 // unique item (for new and already placed bit removed enchantments
1006 if (iGemProto->HasFlag(ITEM_FLAG_UNIQUE_EQUIPPABLE))
1007 {
1008 for (uint32 j = 0; j < MAX_GEM_SOCKETS; ++j)
1009 {
1010 if (i == j) // skip self
1011 continue;
1012
1013 if (gems[j])
1014 {
1015 if (iGemProto->GetId() == gems[j]->GetEntry())
1016 {
1018 return;
1019 }
1020 }
1021 else if (oldGemData[j])
1022 {
1023 if (int32(iGemProto->GetId()) == oldGemData[j]->ItemID)
1024 {
1026 return;
1027 }
1028 }
1029 }
1030 }
1031
1032 // unique limit type item
1033 int32 limit_newcount = 0;
1034 if (gems[i]->GetItemLimitCategory())
1035 {
1036 if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(gems[i]->GetItemLimitCategory()))
1037 {
1038 // NOTE: limitEntry->Flags is not checked because if item has limit then it is applied in equip case
1039 for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
1040 {
1041 if (gems[j])
1042 {
1043 // new gem
1044 if (gems[i]->GetItemLimitCategory() == gems[j]->GetItemLimitCategory())
1045 ++limit_newcount;
1046 }
1047 else if (oldGemData[j])
1048 {
1049 // existing gem
1050 if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(oldGemData[j]->ItemID))
1051 {
1052 BonusData oldGemBonus;
1053 oldGemBonus.Initialize(jProto);
1054
1055 for (uint16 bonusListID : oldGemData[j]->BonusListIDs)
1056 oldGemBonus.AddBonusList(bonusListID);
1057
1058 if (gems[i]->GetItemLimitCategory() == oldGemBonus.LimitCategory)
1059 ++limit_newcount;
1060 }
1061 }
1062 }
1063
1064 if (limit_newcount > 0 && uint32(limit_newcount) > _player->GetItemLimitCategoryQuantity(limitEntry))
1065 {
1067 return;
1068 }
1069 }
1070 }
1071
1072 // for equipped item check all equipment for duplicate equipped gems
1073 if (itemTarget->IsEquipped())
1074 {
1075 if (InventoryResult res = _player->CanEquipUniqueItem(gems[i], slot, std::max(limit_newcount, 0)))
1076 {
1077 _player->SendEquipError(res, itemTarget, nullptr);
1078 return;
1079 }
1080 }
1081 }
1082
1083 bool SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus
1084 _player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item)
1085
1086 //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
1087
1088 //remove ALL mods - gem can change item level
1089 if (itemTarget->IsEquipped())
1090 _player->_ApplyItemMods(itemTarget, itemTarget->GetSlot(), false);
1091
1092 for (uint16 i = 0; i < MAX_GEM_SOCKETS; ++i)
1093 {
1094 if (gems[i])
1095 {
1096 uint32 gemScalingLevel = _player->GetLevel();
1097 if (uint32 fixedLevel = gems[i]->GetModifier(ITEM_MODIFIER_TIMEWALKER_LEVEL))
1098 gemScalingLevel = fixedLevel;
1099
1100 itemTarget->SetGem(i, &gemData[i], gemScalingLevel);
1101
1102 if (gemProperties[i] && gemProperties[i]->EnchantId)
1103 itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + i), gemProperties[i]->EnchantId, 0, 0, _player->GetGUID());
1104
1105 uint32 gemCount = 1;
1106 _player->DestroyItemCount(gems[i], gemCount, true);
1107 }
1108 }
1109
1110 if (itemTarget->IsEquipped())
1111 _player->_ApplyItemMods(itemTarget, itemTarget->GetSlot(), true);
1112
1113 if (Item* childItem = _player->GetChildItemByGuid(itemTarget->GetChildItem()))
1114 {
1115 if (childItem->IsEquipped())
1116 _player->_ApplyItemMods(childItem, childItem->GetSlot(), false);
1117 childItem->CopyArtifactDataFromParent(itemTarget);
1118 if (childItem->IsEquipped())
1119 _player->_ApplyItemMods(childItem, childItem->GetSlot(), true);
1120 }
1121
1122 bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state
1123 if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change...
1124 {
1125 _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, false);
1126 itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetTemplate()->GetSocketBonus() : 0), 0, 0, _player->GetGUID());
1128 //it is not displayed, client has an inbuilt system to determine if the bonus is activated
1129 }
1130
1131 _player->ToggleMetaGemsActive(slot, true); //turn on all metagems (except for target item)
1132
1133 _player->RemoveTradeableItem(itemTarget);
1134 itemTarget->ClearSoulboundTradeable(_player); // clear tradeable flag
1135
1136 itemTarget->SendUpdateSockets();
1137}
1138
1140{
1141 // apply only to equipped item
1142 if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, cancelTempEnchantment.Slot))
1143 return;
1144
1145 Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, cancelTempEnchantment.Slot);
1146
1147 if (!item)
1148 return;
1149
1151 return;
1152
1155}
1156
1158{
1159 Item* item = _player->GetItemByGuid(packet.ItemGUID);
1160 if (!item)
1161 {
1162 TC_LOG_DEBUG("network", "HandleGetItemPurchaseData: Item {} not found!", packet.ItemGUID.ToString());
1163 return;
1164 }
1165
1166 TC_LOG_DEBUG("network", "HandleGetItemPurchaseData: Item {}", packet.ItemGUID.ToString());
1167
1168 GetPlayer()->SendRefundInfo(item);
1169}
1170
1172{
1173 Item* item = _player->GetItemByGuid(packet.ItemGUID);
1174 if (!item)
1175 {
1176 TC_LOG_DEBUG("network", "WorldSession::HandleItemRefund: Item ({}) not found!", packet.ItemGUID.ToString());
1177 return;
1178 }
1179
1180 // Don't try to refund item currently being disenchanted
1181 if (_player->GetLootGUID() == packet.ItemGUID)
1182 return;
1183
1184 GetPlayer()->RefundItem(item);
1185}
1186
1188{
1189 // bankerGUID parameter is optional, set to 0 by default.
1190 if (!bankerGUID)
1191 bankerGUID = _player->PlayerTalkClass->GetInteractionData().SourceGuid;
1192
1193 bool isUsingBankCommand = (bankerGUID == GetPlayer()->GetGUID() && bankerGUID == _player->PlayerTalkClass->GetInteractionData().SourceGuid);
1194
1195 if (!isUsingBankCommand)
1196 {
1198 if (!creature)
1199 return false;
1200 }
1201
1202 return true;
1203}
1204
1206{
1207 Item* item = _player->GetItemByGuid(useCritterItem.ItemGuid);
1208 if (!item)
1209 return;
1210
1211 for (ItemEffectEntry const* itemEffect : item->GetEffects())
1212 {
1213 if (itemEffect->TriggerType != ITEM_SPELLTRIGGER_ON_LEARN)
1214 continue;
1215
1216 if (BattlePetSpeciesEntry const* speciesEntry = BattlePets::BattlePetMgr::GetBattlePetSpeciesBySpell(uint32(itemEffect->SpellID)))
1217 GetBattlePetMgr()->AddPet(speciesEntry->ID, BattlePets::BattlePetMgr::SelectPetDisplay(speciesEntry),
1219 }
1220
1221 _player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true);
1222}
1223
1225{
1226 // TODO: Implement sorting
1227 // Placeholder to prevent completely locking out bags clientside
1229}
1230
1232{
1233 // TODO: Implement sorting
1234 // Placeholder to prevent completely locking out bags clientside
1236}
1237
1239{
1240 // TODO: Implement sorting
1241 // Placeholder to prevent completely locking out bags clientside
1243}
1244
1246{
1247 Item* item = _player->GetItemByGuid(removeNewItem.ItemGuid);
1248 if (!item)
1249 {
1250 TC_LOG_DEBUG("network", "WorldSession::HandleRemoveNewItem: Item ({}) not found for {}!", removeNewItem.ItemGuid.ToString(), GetPlayerInfo());
1251 return;
1252 }
1253
1255 {
1258 }
1259}
1260
1262{
1263 if (changeBagSlotFlag.BagIndex >= _player->m_activePlayerData->BagSlotFlags.size())
1264 return;
1265
1266 if (changeBagSlotFlag.On)
1267 _player->SetBagSlotFlag(changeBagSlotFlag.BagIndex, changeBagSlotFlag.FlagToChange);
1268 else
1269 _player->RemoveBagSlotFlag(changeBagSlotFlag.BagIndex, changeBagSlotFlag.FlagToChange);
1270}
1271
1273{
1274 _player->SetBackpackAutoSortDisabled(setBackpackAutosortDisabled.Disable);
1275}
1276
1278{
1279 _player->SetBackpackSellJunkDisabled(setBackpackSellJunkDisabled.Disable);
1280}
1281
1283{
1284 _player->SetBankAutoSortDisabled(setBankAutosortDisabled.Disable);
1285}
@ CHAR_INS_CHAR_GIFT
#define sConditionMgr
@ CREATURE_FLAG_EXTRA_NO_SELL_VENDOR
#define MAX_VENDOR_ITEMS
Definition Creature.h:54
DB2Storage< ItemLimitCategoryEntry > sItemLimitCategoryStore("ItemLimitCategory.db2", &ItemLimitCategoryLoadInfo::Instance)
DB2Storage< ItemExtendedCostEntry > sItemExtendedCostStore("ItemExtendedCost.db2", &ItemExtendedCostLoadInfo::Instance)
DB2Storage< CurrencyTypesEntry > sCurrencyTypesStore("CurrencyTypes.db2", &CurrencyTypesLoadInfo::Instance)
DB2Storage< GemPropertiesEntry > sGemPropertiesStore("GemProperties.db2", &GemPropertiesLoadInfo::Instance)
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
EnchantmentSlot
@ TEMP_ENCHANTMENT_SLOT
@ PRISMATIC_ENCHANTMENT_SLOT
@ SOCK_ENCHANTMENT_SLOT
@ BONUS_ENCHANTMENT_SLOT
InventoryResult
Definition ItemDefines.h:25
@ EQUIP_ERR_CANT_WRAP_BAGS
Definition ItemDefines.h:75
@ EQUIP_ERR_WRONG_SLOT
Definition ItemDefines.h:29
@ EQUIP_ERR_DROP_BOUND_ITEM
Definition ItemDefines.h:50
@ EQUIP_ERR_ITEM_NOT_FOUND
Definition ItemDefines.h:49
@ EQUIP_ERR_CANT_WRAP_BOUND
Definition ItemDefines.h:73
@ EQUIP_ERR_OK
Definition ItemDefines.h:26
@ EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED
@ EQUIP_ERR_INTERNAL_BAG_ERROR
Definition ItemDefines.h:67
@ EQUIP_ERR_CANT_WRAP_EQUIPPED
Definition ItemDefines.h:71
@ EQUIP_ERR_CANT_WRAP_STACKABLE
Definition ItemDefines.h:70
@ EQUIP_ERR_CANT_WRAP_WRAPPED
Definition ItemDefines.h:72
@ EQUIP_ERR_CANT_WRAP_UNIQUE
Definition ItemDefines.h:74
@ BUY_ERR_CANT_FIND_ITEM
@ BUY_ERR_NOT_ENOUGHT_MONEY
@ ITEM_MODIFIER_TIMEWALKER_LEVEL
@ SELL_ERR_CANT_FIND_VENDOR
@ SELL_ERR_CANT_SELL_TO_THIS_MERCHANT
@ SELL_ERR_CANT_FIND_ITEM
@ ITEM_VENDOR_TYPE_ITEM
@ ITEM_VENDOR_TYPE_CURRENCY
int32 const SocketColorToGemTypeMask[31]
@ ITEM_FLAG2_FACTION_HORDE
@ ITEM_FLAG2_FACTION_ALLIANCE
@ ITEM_FIELD_FLAG_NEW_ITEM
@ ITEM_FIELD_FLAG_CHILD
@ ITEM_FIELD_FLAG_WRAPPED
@ ITEM_SPELLTRIGGER_ON_LEARN
@ ITEM_FLAG_IS_WRAPPER
@ ITEM_FLAG_NO_USER_DESTROY
@ ITEM_FLAG_UNIQUE_EQUIPPABLE
@ ITEM_FLAG_ITEM_PURCHASE_RECORD
@ SOCKET_COLOR_YELLOW
@ SOCKET_COLOR_RED
@ SOCKET_COLOR_BLUE
@ BIND_ON_ACQUIRE
@ ITEM_PURPLE_RIBBONED_WRAPPING_PAPER
@ ITEM_BLUE_RIBBONED_WRAPPING_PAPER
@ ITEM_PURPLE_RIBBONED_HOLIDAY_GIFT
@ ITEM_BLUE_RIBBONED_GIFT
@ ITEM_EMPTY_WRAPPER
@ ITEM_GREEN_RIBBONED_HOLIDAY_GIFT
@ ITEM_GREEN_RIBBONED_WRAPPING_PAPER
@ ITEM_BLUE_RIBBONED_HOLIDAY_GIFT
@ ITEM_RED_RIBBONED_WRAPPING_PAPER
@ ITEM_WRAPPED_GIFT
@ ITEM_BLUE_RIBBONED_HOLIDAY_WRAPPING_PAPER
@ ITEM_RED_RIBBONED_GIFT
void RemoveItemFromUpdateQueueOf(Item *item, Player *player)
Definition Item.cpp:1310
#define MAX_GEM_SOCKETS
Definition Item.h:40
@ ITEM_CHANGED
Definition Item.h:47
@ ITEM_NEW
Definition Item.h:48
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:173
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:176
#define sObjectMgr
Definition ObjectMgr.h:1873
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
std::vector< ItemPosCount > ItemPosCountVec
Definition Player.h:827
@ INVENTORY_SLOT_BAG_START
Definition Player.h:759
constexpr uint8 INVENTORY_SLOT_BAG_0
Definition Player.h:706
@ BUYBACK_SLOT_START
Definition Player.h:784
@ REAGENT_BAG_SLOT_END
Definition Player.h:766
@ ITEM_QUALITY_POOR
@ ALLIANCE
@ HORDE
@ SPELL_AURA_MOD_VENDOR_ITEMS_PRICES
@ SPELL_AURA_FEIGN_DEATH
@ UNIT_NPC_FLAG_BANKER
@ UNIT_NPC_FLAG_VENDOR
@ UNIT_NPC_FLAG_2_NONE
@ UNIT_STATE_DIED
Definition Unit.h:275
@ NULL_BAG
Definition Unit.h:63
@ NULL_SLOT
Definition Unit.h:64
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
T CalculatePct(T base, U pct)
Definition Util.h:72
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
static uint16 RollPetBreed(uint32 species)
static uint32 SelectPetDisplay(BattlePetSpeciesEntry const *speciesEntry)
static BattlePetSpeciesEntry const * GetBattlePetSpeciesBySpell(uint32 spellId)
void AddPet(uint32 species, uint32 display, uint16 breed, BattlePetBreedQuality quality, uint16 level=1)
static BattlePetBreedQuality GetDefaultPetQuality(uint32 species)
static bool IsPlayerMeetingCondition(Player const *player, uint32 conditionId)
void SetHomePosition(float x, float y, float z, float o)
Definition Creature.h:394
VendorItemData const * GetVendorItems() const
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:274
uint32 GetVendorItemCurrentCount(VendorItem const *vItem)
CreatureMovementData const & GetMovementTemplate() const
Definition Item.h:185
void SetState(ItemUpdateState state, Player *forplayer=nullptr)
Definition Item.cpp:1258
uint8 GetSlot() const
Definition Item.h:296
std::span< ItemEffectEntry const *const > GetEffects() const
Definition Item.h:370
uint32 GetSocketColor(uint32 index) const
Definition Item.h:359
virtual void SaveToDB(CharacterDatabaseTransaction trans)
Definition Item.cpp:639
void ReplaceAllItemFlags(ItemFieldFlags flags)
Definition Item.h:226
void RemoveItemFlag(ItemFieldFlags flags)
Definition Item.h:225
uint32 GetEnchantmentId(EnchantmentSlot slot) const
Definition Item.h:314
uint32 GetQuality() const
Definition Item.h:352
UF::SocketedGem const * GetGem(uint16 slot) const
Definition Item.cpp:1571
ObjectGuid GetCreator() const
Definition Item.h:207
ItemTemplate const * GetTemplate() const
Definition Item.cpp:1233
UF::UpdateField< UF::ItemData, uint32(WowCS::EntityFragment::CGObject), TYPEID_ITEM > m_itemData
Definition Item.h:464
void SetGem(uint16 slot, ItemDynamicFieldGems const *gem, uint32 gemScalingLevel)
Definition Item.cpp:1577
bool IsSoulBound() const
Definition Item.h:233
ItemUpdateState GetState() const
Definition Item.h:339
bool HasItemFlag(ItemFieldFlags flag) const
Definition Item.h:223
bool IsEquipped() const
Definition Item.cpp:1336
uint32 GetItemLimitCategory() const
Definition Item.h:371
ObjectGuid GetOwnerGUID() const
Definition Item.h:203
bool IsRefundable() const
Definition Item.h:264
uint16 GetPos() const
Definition Item.h:300
bool GemsFitSockets() const
Definition Item.cpp:1634
ObjectGuid GetGiftCreator() const
Definition Item.h:209
bool IsBag() const
Definition Item.h:268
void ClearEnchantment(EnchantmentSlot slot)
Definition Item.cpp:1558
void SendUpdateSockets()
Definition Item.cpp:1699
void ClearSoulboundTradeable(Player *currentOwner)
Definition Item.cpp:1969
uint32 GetCount() const
Definition Item.h:289
uint8 GetBagSlot() const
Definition Item.cpp:1331
ObjectGuid GetChildItem() const
Definition Item.h:438
uint32 GetMaxStackCount() const
Definition Item.h:291
void SetGiftCreator(ObjectGuid guid)
Definition Item.h:210
void SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint32 charges, ObjectGuid caster=ObjectGuid::Empty)
Definition Item.cpp:1511
LowType GetCounter() const
Definition ObjectGuid.h:336
static ObjectGuid const Empty
Definition ObjectGuid.h:314
bool IsEmpty() const
Definition ObjectGuid.h:362
std::string ToString() const
uint32 GetEntry() const
Definition Object.h:89
void SetEntry(uint32 entry)
Definition Object.h:90
bool IsValidPos(uint16 pos, bool explicit_pos) const
Definition Player.h:1481
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition Player.cpp:13048
static bool IsEquipmentPos(uint16 pos)
Definition Player.h:1472
InventoryResult CanUnequipItem(uint16 src, bool swap) const
Definition Player.cpp:10931
void ToggleMetaGemsActive(uint8 exceptslot, bool apply)
Definition Player.cpp:24195
bool ModifyMoney(int64 amount, bool sendError=true)
Definition Player.cpp:24800
void AutoUnequipChildItem(Item *parentItem)
Definition Player.cpp:11701
InventoryResult CanEquipItem(uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading=true) const
Definition Player.cpp:10709
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition Player.cpp:1814
bool ForEachItem(ItemSearchLocation location, T callback) const
Iterate over each item in the player storage.
Definition Player.h:1388
void RemoveBagSlotFlag(uint32 bagIndex, EnumFlag< BagSlotFlags > flags)
Definition Player.h:1517
Item * BankItem(ItemPosCountVec const &dest, Item *pItem, bool update)
Definition Player.cpp:11902
UF::UpdateField< UF::ActivePlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition Player.h:3048
void SplitItem(uint16 src, uint16 dst, uint32 count)
Definition Player.cpp:12451
InventoryResult CanEquipUniqueItem(Item *pItem, uint8 except_slot=NULL_SLOT, uint32 limit_count=1) const
Definition Player.cpp:27372
InventoryResult CanEquipChildItem(Item *parentItem) const
Definition Player.cpp:10891
Item * GetChildItemByGuid(ObjectGuid guid) const
Definition Player.cpp:9629
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap=false) const
Definition Player.cpp:9975
bool IsBackpackSellJunkDisabled() const
Definition Player.h:1511
void SetBackpackSellJunkDisabled(bool disabled)
Definition Player.h:1512
void _ApplyItemMods(Item *item, uint8 slot, bool apply, bool updateItemAuras=true)
Definition Player.cpp:7807
uint8 GetItemLimitCategoryQuantity(ItemLimitCategoryEntry const *limitEntry) const
Definition Player.cpp:30787
void RemoveItemFromBuyBackSlot(uint32 slot, bool del)
Definition Player.cpp:13015
float GetReputationPriceDiscount(Creature const *creature) const
Definition Player.cpp:25808
ObjectGuid const & GetLootGUID() const
Definition Player.h:2246
void SetBackpackAutoSortDisabled(bool disabled)
Definition Player.h:1510
void ApplyEnchantment(Item *item, EnchantmentSlot slot, bool apply, bool apply_dur=true, bool ignore_condition=false)
Definition Player.cpp:13412
InventoryResult CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap, bool not_loading=true, bool reagentBankOnly=false) const
Definition Player.cpp:10975
void SendSellError(SellResult msg, Creature *creature, ObjectGuid guid) const
Definition Player.cpp:13105
EnumFlag< BagSlotFlags > GetBagSlotFlags(uint32 bagIndex) const
Definition Player.h:1515
void SwapItem(uint16 src, uint16 dst)
Definition Player.cpp:12567
void ApplyItemDependentAuras(Item *item, bool apply)
Definition Player.cpp:8275
void RemoveTradeableItem(Item *item)
Definition Player.cpp:13249
Item * StoreItem(ItemPosCountVec const &pos, Item *pItem, bool update)
Definition Player.cpp:11365
void EquipChildItem(uint8 parentBag, uint8 parentSlot, Item *parentItem)
Definition Player.cpp:11623
Item * GetItemByPos(uint16 pos) const
Definition Player.cpp:9538
void DestroyItem(uint8 bag, uint8 slot, bool update)
Definition Player.cpp:12039
static bool IsInventoryPos(uint16 pos)
Definition Player.h:1470
Optional< SellResult > SellItemToVendor(Item *item, uint32 amount)
Definition Player.cpp:23920
uint32 DestroyItemCount(uint32 item, uint32 count, bool update, bool unequip_check=false)
Definition Player.cpp:12140
void SendBuyError(BuyResult msg, Creature *creature, uint32 item, uint32 param) const
Definition Player.cpp:13096
void SetBankAutoSortDisabled(bool disabled)
Definition Player.h:1514
void SendRefundInfo(Item *item)
Definition Player.cpp:29510
void AutoUnequipOffhandIfNeed(bool force=false)
Definition Player.cpp:26101
Optional< SellResult > CanSellItemToVendor(Item const *item, uint32 amount) const
Definition Player.cpp:23889
void ItemAddedQuestCheck(uint32 entry, uint32 count, Optional< bool > boundItemFlagRequirement={}, bool *hadBoundItemObjective=nullptr)
Definition Player.cpp:16566
bool IsGameMaster() const
Definition Player.h:1293
Item * EquipItem(uint16 pos, Item *pItem, bool update)
Definition Player.cpp:11507
static bool IsBagPos(uint16 pos)
Definition Player.cpp:9691
Item * GetItemFromBuyBackSlot(uint32 slot)
Definition Player.cpp:13006
bool BuyCurrencyFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorSlot, uint32 currency, uint32 count)
Definition Player.cpp:23486
static bool IsBankPos(uint16 pos)
Definition Player.h:1475
void RemoveItem(uint8 bag, uint8 slot, bool update)
Definition Player.cpp:11907
void RefundItem(Item *item)
Definition Player.cpp:29837
void SendMessageToSet(WorldPacket const *data, bool self) const override
Definition Player.h:2310
Item * GetItemByGuid(ObjectGuid guid) const
Definition Player.cpp:9522
bool BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uint32 item, uint32 count, uint8 bag, uint8 slot)
Definition Player.cpp:23662
std::unique_ptr< PlayerMenu > PlayerTalkClass
Definition Player.h:2556
void SetBagSlotFlag(uint32 bagIndex, EnumFlag< BagSlotFlags > flags)
Definition Player.h:1516
Team GetTeam() const
Definition Player.h:2406
bool HasEnoughMoney(uint64 amount) const
Definition Player.h:1892
InventoryResult CanUseItem(Item *pItem, bool not_loading=true) const
Definition Player.cpp:11124
void setUInt32(uint8 index, uint32 value)
void setUInt64(uint8 index, uint64 value)
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3973
uint32 GetClassMask() const
Definition Unit.h:778
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition Unit.cpp:10768
float GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:5087
uint8 GetLevel() const
Definition Unit.h:769
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
std::array< ObjectGuid, MAX_ITEM_PROTO_SOCKETS > GemItem
WorldPacket const * Write() override
std::vector< VendorItem > Items
Definition NPCPackets.h:187
void HandleReadItem(WorldPackets::Item::ReadItem &readItem)
void HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem &autoEquipItem)
void HandleSellItemOpcode(WorldPackets::Item::SellItem const &sellItem)
void HandleSplitItemOpcode(WorldPackets::Item::SplitItem &splitItem)
void HandleCancelTempEnchantmentOpcode(WorldPackets::Item::CancelTempEnchantment &cancelTempEnchantment)
void HandleSetBackpackAutosortDisabled(WorldPackets::Item::SetBackpackAutosortDisabled const &setBackpackAutosortDisabled)
void HandleBuybackItem(WorldPackets::Item::BuyBackItem &packet)
void HandleGetItemPurchaseData(WorldPackets::Item::GetItemPurchaseData &packet)
void HandleSellAllJunkItems(WorldPackets::Item::SellAllJunkItems const &sellAllJunkItems)
void HandleSortBags(WorldPackets::Item::SortBags &sortBags)
std::string GetPlayerInfo() const
void HandleAutoStoreBagItemOpcode(WorldPackets::Item::AutoStoreBagItem &packet)
Player * GetPlayer() const
void HandleSortBankBags(WorldPackets::Item::SortBankBags &sortBankBags)
void HandleUseCritterItem(WorldPackets::Item::UseCritterItem &packet)
void SendItemEnchantTimeUpdate(ObjectGuid Playerguid, ObjectGuid Itemguid, uint32 slot, uint32 Duration)
void HandleSwapInvItemOpcode(WorldPackets::Item::SwapInvItem &swapInvItem)
void HandleRemoveNewItem(WorldPackets::Item::RemoveNewItem &removeNewItem)
void HandleSocketGems(WorldPackets::Item::SocketGems &socketGems)
void HandleChangeBagSlotFlag(WorldPackets::Item::ChangeBagSlotFlag const &changeBagSlotFlag)
void HandleDestroyItemOpcode(WorldPackets::Item::DestroyItem &destroyItem)
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
void HandleSortAccountBankBags(WorldPackets::Item::SortAccountBankBags &sortBankBags)
Player * _player
void SendListInventory(ObjectGuid guid)
void HandleSwapItem(WorldPackets::Item::SwapItem &swapItem)
void HandleWrapItem(WorldPackets::Item::WrapItem &packet)
void HandleSetBackpackSellJunkDisabled(WorldPackets::Item::SetBackpackSellJunkDisabled const &setBackpackSellJunkDisabled)
bool CanUseBank(ObjectGuid bankerGUID=ObjectGuid::Empty) const
void HandleSetBankAutosortDisabled(WorldPackets::Item::SetBankAutosortDisabled const &setBankAutosortDisabled)
void HandleAutoEquipItemSlotOpcode(WorldPackets::Item::AutoEquipItemSlot &autoEquipItemSlot)
void HandleListInventoryOpcode(WorldPackets::NPC::Hello &packet)
void HandleBuyItemOpcode(WorldPackets::Item::BuyItem &packet)
void HandleItemRefund(WorldPackets::Item::ItemPurchaseRefund &packet)
BattlePets::BattlePetMgr * GetBattlePetMgr() const
void SendEnchantmentLog(ObjectGuid owner, ObjectGuid caster, ObjectGuid itemGuid, uint32 itemId, uint32 enchantId, uint32 enchantSlot)
void AddBonusList(uint32 bonusListId)
Definition Item.cpp:3012
uint32 LimitCategory
Definition Item.h:94
void Initialize(ItemTemplate const *proto)
Definition Item.cpp:2918
uint32 GetInteractionPauseTimer() const
uint32 GetBuyCount() const
int32 GetAllowableClass() const
uint32 GetPageText() const
uint32 GetId() const
uint32 GetMaxStackSize() const
uint32 GetBuyPrice() const
ItemBondingType GetBonding() const
bool HasFlag(ItemFlags flag) const
uint32 GetSocketBonus() const
uint32 GetMaxCount() const
constexpr void GetPosition(float &x, float &y) const
Definition Position.h:92
UpdateFieldArray< uint16, 16, 3, 4 > BonusListIDs
UpdateField< int32, 0, 1 > ItemID
uint32 GetItemCount() const
VendorItem const * GetItem(uint32 slot) const
uint32 ExtendedCost
bool IgnoreFiltering
uint32 PlayerConditionId
uint32 maxcount
std::vector< int32 > BonusListIDs
Optional< ItemBonuses > ItemBonus
WorldPackets::Item::ItemInstance Item
Definition NPCPackets.h:168