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 {
346 uint32 i_count = destroyItem.Count;
347 _player->DestroyItemCount(item, i_count, true);
348 }
349 else
350 _player->DestroyItem(destroyItem.ContainerId, destroyItem.SlotNum, true);
351}
352
354{
355 Item* item = _player->GetItemByPos(readItem.PackSlot, readItem.Slot);
356 if (item && item->GetTemplate()->GetPageText())
357 {
359 if (msg == EQUIP_ERR_OK)
360 {
362 packet.Item = item->GetGUID();
363 SendPacket(packet.Write());
364
365 TC_LOG_INFO("network", "STORAGE: Item page sent");
366 }
367 else
368 {
370 /*WorldPackets::Item::ReadItemResultFailed packet;
371 packet.Item = item->GetGUID();
372 packet.Subcode = ??;
373 packet.Delay = ??;
374 SendPacket(packet.Write());*/
375
376 TC_LOG_INFO("network", "STORAGE: Unable to read item");
377 _player->SendEquipError(msg, item, nullptr);
378 }
379 }
380 else
382}
383
385{
386 TC_LOG_DEBUG("network", "WORLD: Received CMSG_SELL_ITEM: Vendor {}, Item {}, Amount: {}",
387 sellItem.VendorGUID, sellItem.ItemGUID, sellItem.Amount);
388
390 if (!creature)
391 {
392 TC_LOG_DEBUG("network", "WORLD: HandleSellItemOpcode - {} not found or you can not interact with him.", sellItem.VendorGUID);
394 return;
395 }
396
398 {
400 return;
401 }
402
403 Item* pItem = _player->GetItemByGuid(sellItem.ItemGUID);
404 if (!pItem)
405 {
407 return;
408 }
409
410 // prevent selling item for sellprice when the item is still refundable
411 // this probably happens when right clicking a refundable item, the client sends both
412 // CMSG_SELL_ITEM and CMSG_REFUND_ITEM (unverified)
413 if (pItem->IsRefundable())
414 return;
415
416 // remove fake death
417 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
419
420 uint32 amount = sellItem.Amount ? sellItem.Amount : pItem->GetCount();
421
422 Optional<SellResult> sellResult = _player->CanSellItemToVendor(pItem, amount);
423 if (!sellResult)
424 sellResult = _player->SellItemToVendor(pItem, amount);
425
426 if (sellResult)
427 _player->SendSellError(*sellResult, creature, sellItem.ItemGUID);
428}
429
431{
433 if (!creature)
434 {
436 return;
437 }
438
440 {
442 return;
443 }
444
445 // remove fake death
446 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
448
449 // collect junk items first
450 std::vector<Item*> junkItems;
451 _player->ForEachItem(ItemSearchLocation::Inventory, [this, &junkItems](Item* item)
452 {
453 if (item->GetQuality() != ITEM_QUALITY_POOR)
455
456 if (item->IsRefundable())
458
459 // check per-bag junk sell exclusion
460 if (item->GetBagSlot() == INVENTORY_SLOT_BAG_0)
461 {
464 }
465 else
466 {
467 uint32 bagIndex = item->GetBagSlot() - INVENTORY_SLOT_BAG_START;
468 if (bagIndex < _player->m_activePlayerData->BagSlotFlags.size()
471 }
472
473 Optional<SellResult> sellError = _player->CanSellItemToVendor(item, item->GetCount());
474 if (!sellError)
475 junkItems.push_back(item);
476
478 });
479
480 auto itr = junkItems.begin();
481 auto end = junkItems.end();
482 Optional<SellResult> sellError;
483
484 // stop on first sell failure (gold cap reached)
485 for (; itr != end && !sellError; ++itr)
486 sellError = _player->SellItemToVendor(*itr, (*itr)->GetCount());
487}
488
490{
491 TC_LOG_DEBUG("network", "WORLD: Received CMSG_BUYBACK_ITEM: Vendor {}, Slot: {}", packet.VendorGUID.ToString(), packet.Slot);
492
494 if (!creature)
495 {
496 TC_LOG_DEBUG("network", "WORLD: HandleBuybackItem - Unit ({}) not found or you can not interact with him.", packet.VendorGUID.ToString());
498 return;
499 }
500
501 // remove fake death
502 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
504
505 Item* pItem = _player->GetItemFromBuyBackSlot(packet.Slot);
506 if (pItem)
507 {
508 uint32 price = _player->m_activePlayerData->BuybackPrice[packet.Slot - BUYBACK_SLOT_START];
509 if (!_player->HasEnoughMoney(uint64(price)))
510 {
512 return;
513 }
514
515 ItemPosCountVec dest;
516 InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false);
517 if (msg == EQUIP_ERR_OK)
518 {
519 _player->ModifyMoney(-(int32)price);
520 _player->RemoveItemFromBuyBackSlot(packet.Slot, false);
521 _player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount());
522 _player->StoreItem(dest, pItem, true);
523 }
524 else
525 _player->SendEquipError(msg, pItem, nullptr);
526 return;
527 }
528 else
530}
531
533{
534 // client expects count starting at 1, and we send vendorslot+1 to client already
535 if (packet.Muid > 0)
536 --packet.Muid;
537 else
538 return; // cheating
539
540 switch (packet.ItemType)
541 {
543 {
544 uint8 bag = NULL_BAG;
545 if (packet.ContainerGUID == GetPlayer()->GetGUID()) // The client sends the player guid when trying to store an item in the default backpack
547 else if (Item* bagItem = _player->GetItemByGuid(packet.ContainerGUID))
548 bag = bagItem->GetSlot();
549
550 GetPlayer()->BuyItemFromVendorSlot(packet.VendorGUID, packet.Muid, packet.Item.ItemID,
551 packet.Quantity, bag, packet.Slot);
552 break;
553 }
555 {
556 GetPlayer()->BuyCurrencyFromVendorSlot(packet.VendorGUID, packet.Muid, packet.Item.ItemID, packet.Quantity);
557 break;
558 }
559 default:
560 {
561 TC_LOG_DEBUG("network", "WORLD: received wrong itemType ({}) in HandleBuyItemOpcode", packet.ItemType);
562 break;
563 }
564 }
565}
566
568{
569 if (!GetPlayer()->IsAlive())
570 return;
571
572 SendListInventory(packet.Unit);
573}
574
576{
578 if (!vendor)
579 {
580 TC_LOG_DEBUG("network", "WORLD: SendListInventory - {} not found or you can not interact with him.", vendorGuid.ToString());
582 return;
583 }
584
585 // remove fake death
586 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
588
589 GetPlayer()->PlayerTalkClass->GetInteractionData().StartInteraction(vendorGuid, PlayerInteractionType::Vendor);
590
591 // Stop the npc if moving
593 vendor->PauseMovement(pause);
594 vendor->SetHomePosition(vendor->GetPosition());
595
596 VendorItemData const* vendorItems = vendor->GetVendorItems();
597 uint32 rawItemCount = vendorItems ? vendorItems->GetItemCount() : 0;
598
600 packet.Vendor = vendor->GetGUID();
601
602 packet.Items.resize(rawItemCount);
603
604 const float discountMod = _player->GetReputationPriceDiscount(vendor);
605 uint8 count = 0;
606 for (uint32 slot = 0; slot < rawItemCount; ++slot)
607 {
608 VendorItem const* vendorItem = vendorItems->GetItem(slot);
609 if (!vendorItem)
610 continue;
611
612 WorldPackets::NPC::VendorItem& item = packet.Items[count];
613
615 item.PlayerConditionFailed = vendorItem->PlayerConditionId;
616
617 if (vendorItem->Type == ITEM_VENDOR_TYPE_ITEM)
618 {
619 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(vendorItem->item);
620 if (!itemTemplate)
621 continue;
622
623 int32 leftInStock = !vendorItem->maxcount ? -1 : vendor->GetVendorItemCurrentCount(vendorItem);
624 if (!_player->IsGameMaster()) // ignore conditions if GM on
625 {
626 // Respect allowed class
627 if (!(itemTemplate->GetAllowableClass() & _player->GetClassMask()) && itemTemplate->GetBonding() == BIND_ON_ACQUIRE)
628 continue;
629
630 // Only display items in vendor lists for the team the player is on
631 if ((itemTemplate->HasFlag(ITEM_FLAG2_FACTION_HORDE) && _player->GetTeam() == ALLIANCE) ||
632 (itemTemplate->HasFlag(ITEM_FLAG2_FACTION_ALLIANCE) && _player->GetTeam() == HORDE))
633 continue;
634
635 // Items sold out are not displayed in list
636 if (leftInStock == 0)
637 continue;
638 }
639
640 if (!sConditionMgr->IsObjectMeetingVendorItemConditions(vendor->GetEntry(), vendorItem->item, _player, vendor))
641 {
642 TC_LOG_DEBUG("condition", "SendListInventory: conditions not met for creature entry {} item {}", vendor->GetEntry(), vendorItem->item);
643 continue;
644 }
645
646 uint64 basePrice = itemTemplate->GetBuyPrice();
647 if (ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(vendorItem->ExtendedCost))
648 basePrice = iece->Money;
649
650 uint64 price = uint64(floor(basePrice * discountMod));
651
653 price -= CalculatePct(price, priceMod);
654
655 if (basePrice > 0)
656 price = std::max(uint64(1), price);
657
658 item.MuID = slot + 1; // client expects counting to start at 1
659 item.ExtendedCostID = vendorItem->ExtendedCost;
660 item.Type = vendorItem->Type;
661 item.Quantity = leftInStock;
662 item.StackCount = itemTemplate->GetBuyCount();
663 item.Price = price;
664 item.DoNotFilterOnVendor = vendorItem->IgnoreFiltering;
665 item.Refundable = itemTemplate->HasFlag(ITEM_FLAG_ITEM_PURCHASE_RECORD) && vendorItem->ExtendedCost && itemTemplate->GetMaxStackSize() == 1;
666
667 item.Item.ItemID = vendorItem->item;
668 if (!vendorItem->BonusListIDs.empty())
669 {
670 item.Item.ItemBonus.emplace();
671 item.Item.ItemBonus->BonusListIDs = vendorItem->BonusListIDs;
672 }
673 }
674 else if (vendorItem->Type == ITEM_VENDOR_TYPE_CURRENCY)
675 {
676 CurrencyTypesEntry const* currencyTemplate = sCurrencyTypesStore.LookupEntry(vendorItem->item);
677 if (!currencyTemplate)
678 continue;
679
680 if (!vendorItem->ExtendedCost)
681 continue; // there's no price defined for currencies, only extendedcost is used
682
683 item.MuID = slot + 1; // client expects counting to start at 1
684 item.ExtendedCostID = vendorItem->ExtendedCost;
685 item.Item.ItemID = vendorItem->item;
686 item.Type = vendorItem->Type;
687 item.StackCount = vendorItem->maxcount;
688 item.DoNotFilterOnVendor = vendorItem->IgnoreFiltering;
689 }
690 else
691 continue;
692
693 if (++count >= MAX_VENDOR_ITEMS)
694 break;
695 }
696
697 // Resize vector to real size (some items can be skipped due to checks)
698 packet.Items.resize(count);
699
701
702 SendPacket(packet.Write());
703}
704
706{
707 if (!packet.Inv.Items.empty())
708 {
709 TC_LOG_ERROR("network", "HandleAutoStoreBagItemOpcode - Invalid itemCount ({})", packet.Inv.Items.size());
710 return;
711 }
712
713 TC_LOG_DEBUG("network", "HandleAutoStoreBagItemOpcode: receive ContainerSlotA: {}, SlotA: {}, ContainerSlotB: {}",
714 packet.ContainerSlotA, packet.SlotA, packet.ContainerSlotB);
715
716 Item* item = _player->GetItemByPos(packet.ContainerSlotA, packet.SlotA);
717 if (!item)
718 return;
719
720 if (!_player->IsValidPos(packet.ContainerSlotB, NULL_SLOT, false)) // can be autostore pos
721 {
723 return;
724 }
725
726 uint16 src = item->GetPos();
727
728 // check unequip potability for equipped items and bank bags
729 if (_player->IsEquipmentPos(src) || _player->IsBagPos(src))
730 {
732 if (msg != EQUIP_ERR_OK)
733 {
734 _player->SendEquipError(msg, item);
735 return;
736 }
737 }
738
739 ItemPosCountVec dest;
740 InventoryResult msg = _player->CanStoreItem(packet.ContainerSlotB, NULL_SLOT, dest, item, false);
741 if (msg != EQUIP_ERR_OK)
742 {
743 _player->SendEquipError(msg, item);
744 return;
745 }
746
747 // no-op: placed in same slot
748 if (dest.size() == 1 && dest[0].pos == src)
749 {
750 // just remove grey item state
752 return;
753 }
754
755 _player->RemoveItem(packet.ContainerSlotA, packet.SlotA, true);
756 _player->StoreItem(dest, item, true);
757}
758
759void WorldSession::SendEnchantmentLog(ObjectGuid owner, ObjectGuid caster, ObjectGuid itemGuid, uint32 itemId, uint32 enchantId, uint32 enchantSlot)
760{
762 enchantmentLog.Owner = owner;
763 enchantmentLog.Caster = caster;
764 enchantmentLog.ItemGUID = itemGuid;
765 enchantmentLog.ItemID = itemId;
766 enchantmentLog.Enchantment = enchantId;
767 enchantmentLog.EnchantSlot = enchantSlot;
768 GetPlayer()->SendMessageToSet(enchantmentLog.Write(), true);
769}
770
772{
774 data.ItemGuid = Itemguid;
775 data.DurationLeft = Duration;
776 data.Slot = slot;
777 data.OwnerGuid = Playerguid;
778 SendPacket(data.Write());
779}
780
782{
783 if (packet.Inv.Items.size() != 2)
784 {
785 TC_LOG_ERROR("network", "HandleWrapItem - Invalid itemCount ({})", packet.Inv.Items.size());
786 return;
787 }
788
790 // Gift
791 uint8 giftContainerSlot = packet.Inv.Items[0].ContainerSlot;
792 uint8 giftSlot = packet.Inv.Items[0].Slot;
793 // Item
794 uint8 itemContainerSlot = packet.Inv.Items[1].ContainerSlot;
795 uint8 itemSlot = packet.Inv.Items[1].Slot;
796
797 TC_LOG_DEBUG("network", "HandleWrapItem - Receive giftContainerSlot = {}, giftSlot = {}, itemContainerSlot = {}, itemSlot = {}", giftContainerSlot, giftSlot, itemContainerSlot, itemSlot);
798
799 Item* gift = _player->GetItemByPos(giftContainerSlot, giftSlot);
800 if (!gift)
801 {
803 return;
804 }
805
806 if (!gift->GetTemplate()->HasFlag(ITEM_FLAG_IS_WRAPPER)) // cheating: non-wrapper wrapper
807 {
809 return;
810 }
811
812 Item* item = _player->GetItemByPos(itemContainerSlot, itemSlot);
813 if (!item)
814 {
816 return;
817 }
818
819 if (item == gift) // not possable with pacjket from real client
820 {
822 return;
823 }
824
825 if (item->IsEquipped())
826 {
828 return;
829 }
830
831 if (!item->GetGiftCreator().IsEmpty()) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED);
832 {
834 return;
835 }
836
837 if (item->IsBag())
838 {
840 return;
841 }
842
843 if (item->IsSoulBound())
844 {
846 return;
847 }
848
849 if (item->GetMaxStackCount() != 1)
850 {
852 return;
853 }
854
855 // maybe not correct check (it is better than nothing)
856 if (item->GetTemplate()->GetMaxCount() > 0)
857 {
859 return;
860 }
861
862 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
863
865 stmt->setUInt64(0, item->GetOwnerGUID().GetCounter());
866 stmt->setUInt64(1, item->GetGUID().GetCounter());
867 stmt->setUInt32(2, item->GetEntry());
868 stmt->setUInt32(3, item->m_itemData->DynamicFlags);
869 trans->Append(stmt);
870
871 item->SetEntry(gift->GetEntry());
872
873 switch (item->GetEntry())
874 {
877 break;
880 break;
883 break;
886 break;
889 break;
892 break;
893 default:
894 break;
895 }
896
900
901 if (item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance`
902 {
903 // after save it will be impossible to remove the item from the queue
905 item->SaveToDB(trans); // item gave inventory record unchanged and can be save standalone
906 }
907 CharacterDatabase.CommitTransaction(trans);
908
909 uint32 count = 1;
910 _player->DestroyItemCount(gift, count, true);
911}
912
914{
915 if (!socketGems.ItemGuid)
916 return;
917
918 //cheat -> tried to socket same gem multiple times
919 if ((!socketGems.GemItem[0].IsEmpty() && (socketGems.GemItem[0] == socketGems.GemItem[1] || socketGems.GemItem[0] == socketGems.GemItem[2])) ||
920 (!socketGems.GemItem[1].IsEmpty() && (socketGems.GemItem[1] == socketGems.GemItem[2])))
921 return;
922
923 Item* itemTarget = _player->GetItemByGuid(socketGems.ItemGuid);
924 if (!itemTarget) //missing item to socket
925 return;
926
927 ItemTemplate const* itemProto = itemTarget->GetTemplate();
928 if (!itemProto)
929 return;
930
931 //this slot is excepted when applying / removing meta gem bonus
932 uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT);
933
934 Item* gems[MAX_GEM_SOCKETS];
935 memset(gems, 0, sizeof(gems));
937 memset(gemData, 0, sizeof(gemData));
938 GemPropertiesEntry const* gemProperties[MAX_GEM_SOCKETS];
939 memset(gemProperties, 0, sizeof(gemProperties));
940 UF::SocketedGem const* oldGemData[MAX_GEM_SOCKETS];
941 memset(oldGemData, 0, sizeof(oldGemData));
942 for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i)
943 {
944 if (Item* gem = _player->GetItemByGuid(socketGems.GemItem[i]))
945 {
946 gems[i] = gem;
947 gemData[i].ItemId = gem->GetEntry();
948 gemData[i].Context = gem->m_itemData->Context;
949 for (std::size_t b = 0; b < gem->GetBonusListIDs().size() && b < 16; ++b)
950 gemData[i].BonusListIDs[b] = gem->GetBonusListIDs()[b];
951
952 gemProperties[i] = sGemPropertiesStore.LookupEntry(gem->GetTemplate()->GetGemProperties());
953 }
954
955 oldGemData[i] = itemTarget->GetGem(i);
956 }
957
958 // Find first prismatic socket
959 uint32 firstPrismatic = 0;
960 while (firstPrismatic < MAX_GEM_SOCKETS && itemTarget->GetSocketColor(firstPrismatic))
961 ++firstPrismatic;
962
963 for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe
964 {
965 if (!gemProperties[i])
966 continue;
967
968 uint32 acceptableGemTypeMask = SocketColorToGemTypeMask[itemTarget->GetSocketColor(i)];
969 // tried to put gem in socket where no socket exists (take care about prismatic sockets)
970 switch (itemTarget->GetSocketColor(i))
971 {
972 case 0:
973 {
974 // no prismatic socket
976 return;
977
978 if (i != firstPrismatic)
979 return;
980
981 acceptableGemTypeMask = SOCKET_COLOR_RED | SOCKET_COLOR_YELLOW | SOCKET_COLOR_BLUE;
982 break;
983 }
984 case 2:
985 case 3:
986 case 4:
987 // red, blue and yellow sockets accept any red/blue/yellow gem
988 acceptableGemTypeMask = SOCKET_COLOR_RED | SOCKET_COLOR_YELLOW | SOCKET_COLOR_BLUE;
989 break;
990 default:
991 break;
992 }
993
994 // Gem must match socket color
995 if (!(acceptableGemTypeMask & gemProperties[i]->Type))
996 return;
997 }
998
999 // check unique-equipped conditions
1000 for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i)
1001 {
1002 if (!gems[i])
1003 continue;
1004
1005 // continue check for case when attempt add 2 similar unique equipped gems in one item.
1006 ItemTemplate const* iGemProto = gems[i]->GetTemplate();
1007
1008 // unique item (for new and already placed bit removed enchantments
1009 if (iGemProto->HasFlag(ITEM_FLAG_UNIQUE_EQUIPPABLE))
1010 {
1011 for (uint32 j = 0; j < MAX_GEM_SOCKETS; ++j)
1012 {
1013 if (i == j) // skip self
1014 continue;
1015
1016 if (gems[j])
1017 {
1018 if (iGemProto->GetId() == gems[j]->GetEntry())
1019 {
1021 return;
1022 }
1023 }
1024 else if (oldGemData[j])
1025 {
1026 if (int32(iGemProto->GetId()) == oldGemData[j]->ItemID)
1027 {
1029 return;
1030 }
1031 }
1032 }
1033 }
1034
1035 // unique limit type item
1036 int32 limit_newcount = 0;
1037 if (gems[i]->GetItemLimitCategory())
1038 {
1039 if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(gems[i]->GetItemLimitCategory()))
1040 {
1041 // NOTE: limitEntry->Flags is not checked because if item has limit then it is applied in equip case
1042 for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
1043 {
1044 if (gems[j])
1045 {
1046 // new gem
1047 if (gems[i]->GetItemLimitCategory() == gems[j]->GetItemLimitCategory())
1048 ++limit_newcount;
1049 }
1050 else if (oldGemData[j])
1051 {
1052 // existing gem
1053 if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(oldGemData[j]->ItemID))
1054 {
1055 BonusData oldGemBonus;
1056 oldGemBonus.Initialize(jProto);
1057
1058 for (uint16 bonusListID : oldGemData[j]->BonusListIDs)
1059 oldGemBonus.AddBonusList(bonusListID);
1060
1061 if (gems[i]->GetItemLimitCategory() == oldGemBonus.LimitCategory)
1062 ++limit_newcount;
1063 }
1064 }
1065 }
1066
1067 if (limit_newcount > 0 && uint32(limit_newcount) > _player->GetItemLimitCategoryQuantity(limitEntry))
1068 {
1070 return;
1071 }
1072 }
1073 }
1074
1075 // for equipped item check all equipment for duplicate equipped gems
1076 if (itemTarget->IsEquipped())
1077 {
1078 if (InventoryResult res = _player->CanEquipUniqueItem(gems[i], slot, std::max(limit_newcount, 0)))
1079 {
1080 _player->SendEquipError(res, itemTarget, nullptr);
1081 return;
1082 }
1083 }
1084 }
1085
1086 bool SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus
1087 _player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item)
1088
1089 //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
1090
1091 //remove ALL mods - gem can change item level
1092 if (itemTarget->IsEquipped())
1093 _player->_ApplyItemMods(itemTarget, itemTarget->GetSlot(), false);
1094
1095 for (uint16 i = 0; i < MAX_GEM_SOCKETS; ++i)
1096 {
1097 if (gems[i])
1098 {
1099 uint32 gemScalingLevel = _player->GetLevel();
1100 if (uint32 fixedLevel = gems[i]->GetModifier(ITEM_MODIFIER_TIMEWALKER_LEVEL))
1101 gemScalingLevel = fixedLevel;
1102
1103 itemTarget->SetGem(i, &gemData[i], gemScalingLevel);
1104
1105 if (gemProperties[i] && gemProperties[i]->EnchantId)
1106 itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + i), gemProperties[i]->EnchantId, 0, 0, _player->GetGUID());
1107
1108 uint32 gemCount = 1;
1109 _player->DestroyItemCount(gems[i], gemCount, true);
1110 }
1111 }
1112
1113 if (itemTarget->IsEquipped())
1114 _player->_ApplyItemMods(itemTarget, itemTarget->GetSlot(), true);
1115
1116 if (Item* childItem = _player->GetChildItemByGuid(itemTarget->GetChildItem()))
1117 {
1118 if (childItem->IsEquipped())
1119 _player->_ApplyItemMods(childItem, childItem->GetSlot(), false);
1120 childItem->CopyArtifactDataFromParent(itemTarget);
1121 if (childItem->IsEquipped())
1122 _player->_ApplyItemMods(childItem, childItem->GetSlot(), true);
1123 }
1124
1125 bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state
1126 if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change...
1127 {
1128 _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, false);
1129 itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetTemplate()->GetSocketBonus() : 0), 0, 0, _player->GetGUID());
1131 //it is not displayed, client has an inbuilt system to determine if the bonus is activated
1132 }
1133
1134 _player->ToggleMetaGemsActive(slot, true); //turn on all metagems (except for target item)
1135
1136 _player->RemoveTradeableItem(itemTarget);
1137 itemTarget->ClearSoulboundTradeable(_player); // clear tradeable flag
1138
1139 itemTarget->SendUpdateSockets();
1140}
1141
1143{
1144 // apply only to equipped item
1145 if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, cancelTempEnchantment.Slot))
1146 return;
1147
1148 Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, cancelTempEnchantment.Slot);
1149
1150 if (!item)
1151 return;
1152
1154 return;
1155
1158}
1159
1161{
1162 Item* item = _player->GetItemByGuid(packet.ItemGUID);
1163 if (!item)
1164 {
1165 TC_LOG_DEBUG("network", "HandleGetItemPurchaseData: Item {} not found!", packet.ItemGUID.ToString());
1166 return;
1167 }
1168
1169 TC_LOG_DEBUG("network", "HandleGetItemPurchaseData: Item {}", packet.ItemGUID.ToString());
1170
1171 GetPlayer()->SendRefundInfo(item);
1172}
1173
1175{
1176 Item* item = _player->GetItemByGuid(packet.ItemGUID);
1177 if (!item)
1178 {
1179 TC_LOG_DEBUG("network", "WorldSession::HandleItemRefund: Item ({}) not found!", packet.ItemGUID.ToString());
1180 return;
1181 }
1182
1183 // Don't try to refund item currently being disenchanted
1184 if (_player->GetLootGUID() == packet.ItemGUID)
1185 return;
1186
1187 GetPlayer()->RefundItem(item);
1188}
1189
1191{
1192 // bankerGUID parameter is optional, set to 0 by default.
1193 if (!bankerGUID)
1194 bankerGUID = _player->PlayerTalkClass->GetInteractionData().SourceGuid;
1195
1196 bool isUsingBankCommand = (bankerGUID == GetPlayer()->GetGUID() && bankerGUID == _player->PlayerTalkClass->GetInteractionData().SourceGuid);
1197
1198 if (!isUsingBankCommand)
1199 {
1201 if (!creature)
1202 return false;
1203 }
1204
1205 return true;
1206}
1207
1209{
1210 Item* item = _player->GetItemByGuid(useCritterItem.ItemGuid);
1211 if (!item)
1212 return;
1213
1214 for (ItemEffectEntry const* itemEffect : item->GetEffects())
1215 {
1216 if (itemEffect->TriggerType != ITEM_SPELLTRIGGER_ON_LEARN)
1217 continue;
1218
1219 if (BattlePetSpeciesEntry const* speciesEntry = BattlePets::BattlePetMgr::GetBattlePetSpeciesBySpell(uint32(itemEffect->SpellID)))
1220 GetBattlePetMgr()->AddPet(speciesEntry->ID, BattlePets::BattlePetMgr::SelectPetDisplay(speciesEntry),
1222 }
1223
1224 _player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true);
1225}
1226
1228{
1229 // TODO: Implement sorting
1230 // Placeholder to prevent completely locking out bags clientside
1232}
1233
1235{
1236 // TODO: Implement sorting
1237 // Placeholder to prevent completely locking out bags clientside
1239}
1240
1242{
1243 // TODO: Implement sorting
1244 // Placeholder to prevent completely locking out bags clientside
1246}
1247
1249{
1250 Item* item = _player->GetItemByGuid(removeNewItem.ItemGuid);
1251 if (!item)
1252 {
1253 TC_LOG_DEBUG("network", "WorldSession::HandleRemoveNewItem: Item ({}) not found for {}!", removeNewItem.ItemGuid.ToString(), GetPlayerInfo());
1254 return;
1255 }
1256
1258 {
1261 }
1262}
1263
1265{
1266 if (changeBagSlotFlag.BagIndex >= _player->m_activePlayerData->BagSlotFlags.size())
1267 return;
1268
1269 if (changeBagSlotFlag.On)
1270 _player->SetBagSlotFlag(changeBagSlotFlag.BagIndex, changeBagSlotFlag.FlagToChange);
1271 else
1272 _player->RemoveBagSlotFlag(changeBagSlotFlag.BagIndex, changeBagSlotFlag.FlagToChange);
1273}
1274
1276{
1277 _player->SetBackpackAutoSortDisabled(setBackpackAutosortDisabled.Disable);
1278}
1279
1281{
1282 _player->SetBackpackSellJunkDisabled(setBackpackSellJunkDisabled.Disable);
1283}
1284
1286{
1287 _player->SetBankAutoSortDisabled(setBankAutosortDisabled.Disable);
1288}
@ 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:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
#define sObjectMgr
Definition ObjectMgr.h:1885
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
std::vector< ItemPosCount > ItemPosCountVec
Definition Player.h:841
@ INVENTORY_SLOT_BAG_START
Definition Player.h:773
@ BUYBACK_SLOT_START
Definition Player.h:798
#define INVENTORY_SLOT_BAG_0
Definition Player.h:723
@ REAGENT_BAG_SLOT_END
Definition Player.h:780
@ 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:261
@ 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:386
VendorItemData const * GetVendorItems() const
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:266
uint32 GetVendorItemCurrentCount(VendorItem const *vItem)
CreatureMovementData const & GetMovementTemplate() const
Definition Item.h:179
void SetState(ItemUpdateState state, Player *forplayer=nullptr)
Definition Item.cpp:1258
uint8 GetSlot() const
Definition Item.h:290
std::span< ItemEffectEntry const *const > GetEffects() const
Definition Item.h:365
uint32 GetSocketColor(uint32 index) const
Definition Item.h:354
virtual void SaveToDB(CharacterDatabaseTransaction trans)
Definition Item.cpp:639
void ReplaceAllItemFlags(ItemFieldFlags flags)
Definition Item.h:220
void RemoveItemFlag(ItemFieldFlags flags)
Definition Item.h:219
uint32 GetEnchantmentId(EnchantmentSlot slot) const
Definition Item.h:308
uint32 GetQuality() const
Definition Item.h:347
UF::SocketedGem const * GetGem(uint16 slot) const
Definition Item.cpp:1571
ObjectGuid GetCreator() const
Definition Item.h:201
ItemTemplate const * GetTemplate() const
Definition Item.cpp:1233
UF::UpdateField< UF::ItemData, uint32(WowCS::EntityFragment::CGObject), TYPEID_ITEM > m_itemData
Definition Item.h:459
void SetGem(uint16 slot, ItemDynamicFieldGems const *gem, uint32 gemScalingLevel)
Definition Item.cpp:1577
bool IsSoulBound() const
Definition Item.h:227
ItemUpdateState GetState() const
Definition Item.h:333
bool HasItemFlag(ItemFieldFlags flag) const
Definition Item.h:217
bool IsEquipped() const
Definition Item.cpp:1336
uint32 GetItemLimitCategory() const
Definition Item.h:366
ObjectGuid GetOwnerGUID() const
Definition Item.h:197
bool IsRefundable() const
Definition Item.h:258
uint16 GetPos() const
Definition Item.h:294
bool GemsFitSockets() const
Definition Item.cpp:1634
ObjectGuid GetGiftCreator() const
Definition Item.h:203
bool IsBag() const
Definition Item.h:262
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:283
uint8 GetBagSlot() const
Definition Item.cpp:1331
ObjectGuid GetChildItem() const
Definition Item.h:433
uint32 GetMaxStackCount() const
Definition Item.h:285
void SetGiftCreator(ObjectGuid guid)
Definition Item.h:204
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:1497
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition Player.cpp:13130
static bool IsEquipmentPos(uint16 pos)
Definition Player.h:1488
InventoryResult CanUnequipItem(uint16 src, bool swap) const
Definition Player.cpp:11019
void ToggleMetaGemsActive(uint8 exceptslot, bool apply)
Definition Player.cpp:24276
bool ModifyMoney(int64 amount, bool sendError=true)
Definition Player.cpp:24850
void AutoUnequipChildItem(Item *parentItem)
Definition Player.cpp:11783
InventoryResult CanEquipItem(uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading=true) const
Definition Player.cpp:10788
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition Player.cpp:1903
bool ForEachItem(ItemSearchLocation location, T callback) const
Iterate over each item in the player storage.
Definition Player.h:1404
void RemoveBagSlotFlag(uint32 bagIndex, EnumFlag< BagSlotFlags > flags)
Definition Player.h:1532
Item * BankItem(ItemPosCountVec const &dest, Item *pItem, bool update)
Definition Player.cpp:11984
UF::UpdateField< UF::ActivePlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition Player.h:3062
void SplitItem(uint16 src, uint16 dst, uint32 count)
Definition Player.cpp:12533
InventoryResult CanEquipUniqueItem(Item *pItem, uint8 except_slot=NULL_SLOT, uint32 limit_count=1) const
Definition Player.cpp:27428
InventoryResult CanEquipChildItem(Item *parentItem) const
Definition Player.cpp:10979
Item * GetChildItemByGuid(ObjectGuid guid) const
Definition Player.cpp:9721
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap=false) const
Definition Player.cpp:10055
bool IsBackpackSellJunkDisabled() const
Definition Player.h:1526
void SetBackpackSellJunkDisabled(bool disabled)
Definition Player.h:1527
void _ApplyItemMods(Item *item, uint8 slot, bool apply, bool updateItemAuras=true)
Definition Player.cpp:7917
uint8 GetItemLimitCategoryQuantity(ItemLimitCategoryEntry const *limitEntry) const
Definition Player.cpp:30870
void RemoveItemFromBuyBackSlot(uint32 slot, bool del)
Definition Player.cpp:13097
float GetReputationPriceDiscount(Creature const *creature) const
Definition Player.cpp:25877
ObjectGuid const & GetLootGUID() const
Definition Player.h:2262
void SetBackpackAutoSortDisabled(bool disabled)
Definition Player.h:1525
void ApplyEnchantment(Item *item, EnchantmentSlot slot, bool apply, bool apply_dur=true, bool ignore_condition=false)
Definition Player.cpp:13455
InventoryResult CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap, bool not_loading=true, bool reagentBankOnly=false) const
Definition Player.cpp:11064
void SendSellError(SellResult msg, Creature *creature, ObjectGuid guid) const
Definition Player.cpp:13187
EnumFlag< BagSlotFlags > GetBagSlotFlags(uint32 bagIndex) const
Definition Player.h:1530
void SwapItem(uint16 src, uint16 dst)
Definition Player.cpp:12649
void ApplyItemDependentAuras(Item *item, bool apply)
Definition Player.cpp:8351
void RemoveTradeableItem(Item *item)
Definition Player.cpp:13292
Item * StoreItem(ItemPosCountVec const &pos, Item *pItem, bool update)
Definition Player.cpp:11447
void EquipChildItem(uint8 parentBag, uint8 parentSlot, Item *parentItem)
Definition Player.cpp:11705
Item * GetItemByPos(uint16 pos) const
Definition Player.cpp:9630
void DestroyItem(uint8 bag, uint8 slot, bool update)
Definition Player.cpp:12121
static bool IsInventoryPos(uint16 pos)
Definition Player.h:1486
Optional< SellResult > SellItemToVendor(Item *item, uint32 amount)
Definition Player.cpp:23973
uint32 DestroyItemCount(uint32 item, uint32 count, bool update, bool unequip_check=false)
Definition Player.cpp:12222
void SendBuyError(BuyResult msg, Creature *creature, uint32 item, uint32 param) const
Definition Player.cpp:13178
void SetBankAutoSortDisabled(bool disabled)
Definition Player.h:1529
void SendRefundInfo(Item *item)
Definition Player.cpp:29566
void AutoUnequipOffhandIfNeed(bool force=false)
Definition Player.cpp:26170
Optional< SellResult > CanSellItemToVendor(Item const *item, uint32 amount) const
Definition Player.cpp:23942
void ItemAddedQuestCheck(uint32 entry, uint32 count, Optional< bool > boundItemFlagRequirement={}, bool *hadBoundItemObjective=nullptr)
Definition Player.cpp:16599
bool IsGameMaster() const
Definition Player.h:1309
Item * EquipItem(uint16 pos, Item *pItem, bool update)
Definition Player.cpp:11589
static bool IsBagPos(uint16 pos)
Definition Player.cpp:9783
Item * GetItemFromBuyBackSlot(uint32 slot)
Definition Player.cpp:13088
bool BuyCurrencyFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorSlot, uint32 currency, uint32 count)
Definition Player.cpp:23540
static bool IsBankPos(uint16 pos)
Definition Player.h:1491
void RemoveItem(uint8 bag, uint8 slot, bool update)
Definition Player.cpp:11989
void RefundItem(Item *item)
Definition Player.cpp:29893
void SendMessageToSet(WorldPacket const *data, bool self) const override
Definition Player.h:2325
Item * GetItemByGuid(ObjectGuid guid) const
Definition Player.cpp:9614
bool BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uint32 item, uint32 count, uint8 bag, uint8 slot)
Definition Player.cpp:23716
std::unique_ptr< PlayerMenu > PlayerTalkClass
Definition Player.h:2570
void SetBagSlotFlag(uint32 bagIndex, EnumFlag< BagSlotFlags > flags)
Definition Player.h:1531
Team GetTeam() const
Definition Player.h:2423
bool HasEnoughMoney(uint64 amount) const
Definition Player.h:1907
InventoryResult CanUseItem(Item *pItem, bool not_loading=true) const
Definition Player.cpp:11214
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:3955
uint32 GetClassMask() const
Definition Unit.h:766
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition Unit.cpp:10695
float GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:5069
uint8 GetLevel() const
Definition Unit.h:757
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:2974
uint32 LimitCategory
Definition Item.h:92
void Initialize(ItemTemplate const *proto)
Definition Item.cpp:2886
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