Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
PlayerStorage.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "Player.h"
7#include "Bag.h"
8#include "Battleground.h"
9#include "BattlegroundMgr.h"
10#include "DatabaseEnv.h"
11#include "DB2Stores.h"
12#include "GameEventMgr.h"
13#include "Group.h"
14#include "Item.h"
15#include "ItemPrototype.h"
16#include "LFGMgr.h"
17#include "Log.h"
18#include "Map.h"
19#include "ObjectMgr.h"
20#include "SpellInfo.h"
21#include "SpellMgr.h"
22#include "UpdateData.h"
23#include "World.h"
24#include "WorldPacket.h"
25#include "WorldSession.h"
26
27uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const
28{
29 uint32 count = 0;
31 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
32 if (pItem != skipItem && pItem->GetEntry() == item)
33 count += pItem->GetCount();
34
36 if (Bag* pBag = GetBagByPos(i))
37 count += pBag->GetItemCount(item, skipItem);
38
39 if (skipItem && skipItem->GetTemplate()->GemProperties)
41 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
42 if (pItem != skipItem && pItem->GetTemplate()->Socket[0].Color)
43 count += pItem->GetGemCountWithID(item);
44
45 if (inBankAlso)
46 {
47 // checking every item from 39 to 74 (including bank bags)
49 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
50 if (pItem != skipItem && pItem->GetEntry() == item)
51 count += pItem->GetCount();
52
54 if (Bag* pBag = GetBagByPos(i))
55 count += pBag->GetItemCount(item, skipItem);
56
57 if (skipItem && skipItem->GetTemplate()->GemProperties)
59 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
60 if (pItem != skipItem && pItem->GetTemplate()->Socket[0].Color)
61 count += pItem->GetGemCountWithID(item);
62 }
63
64 return count;
65}
66
68{
69 uint32 count = 0;
70 for (int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
71 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
72 if (pItem != skipItem)
73 if (ItemTemplate const* pProto = pItem->GetTemplate())
74 if (pProto->ItemLimitCategory == limitCategory)
75 count += pItem->GetCount();
76
78 if (Bag* pBag = GetBagByPos(i))
79 count += pBag->GetItemCountWithLimitCategory(limitCategory, skipItem);
80
81 for (int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
82 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
83 if (pItem != skipItem)
84 if (ItemTemplate const* pProto = pItem->GetTemplate())
85 if (pProto->ItemLimitCategory == limitCategory)
86 count += pItem->GetCount();
87
88 for (int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
89 if (Bag* pBag = GetBagByPos(i))
90 count += pBag->GetItemCountWithLimitCategory(limitCategory, skipItem);
91
92 return count;
93}
94
96{
98 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
99 if (pItem->GetGUID() == guid)
100 return pItem;
101
102 for (int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
103 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
104 if (pItem->GetGUID() == guid)
105 return pItem;
106
108 if (Bag* pBag = GetBagByPos(i))
109 for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
110 if (Item* pItem = pBag->GetItemByPos(j))
111 if (pItem->GetGUID() == guid)
112 return pItem;
113
115 if (Bag* pBag = GetBagByPos(i))
116 for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
117 if (Item* pItem = pBag->GetItemByPos(j))
118 if (pItem->GetGUID() == guid)
119 return pItem;
120
121 return NULL;
122}
123
125{
126 uint8 bag = pos >> 8;
127 uint8 slot = pos & 255;
128 return GetItemByPos(bag, slot);
129}
130
132{
133 if (bag == INVENTORY_SLOT_BAG_0 && slot < BANK_SLOT_BAG_END)
134 return m_items[slot];
135 else if (Bag* pBag = GetBagByPos(bag))
136 return pBag->GetItemByPos(slot);
137 return NULL;
138}
139
140//Does additional check for disarmed weapons
142{
144 return NULL;
145 return GetItemByPos(bag, slot);
146}
147
149{
151 || (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END))
152 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, bag))
153 return item->ToBag();
154 return NULL;
155}
156
157Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool useable /*= false*/) const
158{
159 uint8 slot;
160 switch (attackType)
161 {
165 break;
168 break;
169
170 default: return NULL;
171 }
172
173 Item* item = NULL;
174 if (useable)
176 else
178 if (!item || item->GetTemplate()->Class != ITEM_CLASS_WEAPON)
179 return NULL;
180
181 if (!useable)
182 return item;
183
184 if (item->IsBroken() || IsInFeralForm())
185 return NULL;
186
187 return item;
188}
189
190Item* Player::GetShield(bool useable) const
191{
192 Item* item = NULL;
193 if (useable)
195 else
197 if (!item || item->GetTemplate()->Class != ITEM_CLASS_ARMOR)
198 return NULL;
199
200 if (!useable)
201 return item;
202
203 if (item->IsBroken())
204 return NULL;
205
206 return item;
207}
208
218
220{
221 if (bag == INVENTORY_SLOT_BAG_0 && slot == NULL_SLOT)
222 return true;
224 return true;
226 return true;
227 return false;
228}
229
231{
232 if (bag == INVENTORY_SLOT_BAG_0 && (slot < EQUIPMENT_SLOT_END))
233 return true;
235 return true;
236 return false;
237}
238
240{
241 if (bag == INVENTORY_SLOT_BAG_0 && (slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END))
242 return true;
243 if (bag == INVENTORY_SLOT_BAG_0 && (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END))
244 return true;
245 if (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END)
246 return true;
247 return false;
248}
249
251{
252 uint8 bag = pos >> 8;
253 uint8 slot = pos & 255;
255 return true;
256 if (bag == INVENTORY_SLOT_BAG_0 && (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END))
257 return true;
258 return false;
259}
260
261bool Player::IsValidPos(uint8 bag, uint8 slot, bool explicit_pos)
262{
263 // post selected
264 if (bag == NULL_BAG && !explicit_pos)
265 return true;
266
267 if (bag == INVENTORY_SLOT_BAG_0)
268 {
269 // any post selected
270 if (slot == NULL_SLOT && !explicit_pos)
271 return true;
272
273 // equipment
274 if (slot < EQUIPMENT_SLOT_END)
275 return true;
276
277 // bag equip slots
279 return true;
280
281 // backpack slots
283 return true;
284
285 // bank main slots
286 if (slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END)
287 return true;
288
289 // bank bag slots
290 if (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END)
291 return true;
292
293 return false;
294 }
295
296 // bag content slots
297 // bank bag content slots
298 if (Bag* pBag = GetBagByPos(bag))
299 {
300 // any post selected
301 if (slot == NULL_SLOT && !explicit_pos)
302 return true;
303
304 return slot < pBag->GetBagSize();
305 }
306
307 // where this?
308 return false;
309}
310
311bool Player::HasItemCount(uint32 item, uint32 count, bool inBankAlso) const
312{
313 uint32 tempcount = 0;
315 {
317 if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
318 {
319 tempcount += pItem->GetCount();
320 if (tempcount >= count)
321 return true;
322 }
323 }
324
326 {
327 if (Bag* pBag = GetBagByPos(i))
328 {
329 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
330 {
331 Item* pItem = GetItemByPos(i, j);
332 if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
333 {
334 tempcount += pItem->GetCount();
335 if (tempcount >= count)
336 return true;
337 }
338 }
339 }
340 }
341
342 if (inBankAlso)
343 {
345 {
347 if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
348 {
349 tempcount += pItem->GetCount();
350 if (tempcount >= count)
351 return true;
352 }
353 }
355 {
356 if (Bag* pBag = GetBagByPos(i))
357 {
358 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
359 {
360 Item* pItem = GetItemByPos(i, j);
361 if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
362 {
363 tempcount += pItem->GetCount();
364 if (tempcount >= count)
365 return true;
366 }
367 }
368 }
369 }
370 }
371
372 return false;
373}
374
375bool Player::HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot) const
376{
377 uint32 tempcount = 0;
379 {
380 if (i == except_slot)
381 continue;
382
384 if (pItem && pItem->GetEntry() == item)
385 {
386 tempcount += pItem->GetCount();
387 if (tempcount >= count)
388 return true;
389 }
390 }
391
392 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item);
393 if (pProto && pProto->GemProperties)
394 {
396 {
397 if (i == except_slot)
398 continue;
399
401 if (pItem && pItem->GetTemplate()->Socket[0].Color)
402 {
403 tempcount += pItem->GetGemCountWithID(item);
404 if (tempcount >= count)
405 return true;
406 }
407 }
408 }
409
410 return false;
411}
412
413bool Player::HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot) const
414{
415 uint32 tempcount = 0;
417 {
418 if (i == except_slot)
419 continue;
420
422 if (!pItem)
423 continue;
424
425 ItemTemplate const* pProto = pItem->GetTemplate();
426 if (!pProto)
427 continue;
428
429 if (pProto->ItemLimitCategory == limitCategory)
430 {
431 tempcount += pItem->GetCount();
432 if (tempcount >= count)
433 return true;
434 }
435
437 {
438 tempcount += pItem->GetGemCountWithLimitCategory(limitCategory);
439 if (tempcount >= count)
440 return true;
441 }
442 }
443
444 return false;
445}
446
447InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count) const
448{
449 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(entry);
450 if (!pProto)
451 {
452 if (no_space_count)
453 *no_space_count = count;
455 }
456
457 if (pItem && pItem->m_lootGenerated)
458 return EQUIP_ERR_LOOT_GONE;
459
460 // no maximum
461 if ((pProto->MaxCount <= 0 && pProto->ItemLimitCategory == 0) || pProto->MaxCount == 2147483647)
462 return EQUIP_ERR_OK;
463
464 if (pProto->MaxCount > 0)
465 {
466 uint32 curcount = GetItemCount(pProto->ItemId, true, pItem);
467 if (curcount + count > uint32(pProto->MaxCount))
468 {
469 if (no_space_count)
470 *no_space_count = count + curcount - pProto->MaxCount;
472 }
473 }
474
475 // check unique-equipped limit
476 if (pProto->ItemLimitCategory)
477 {
478 ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(pProto->ItemLimitCategory);
479 if (!limitEntry)
480 {
481 if (no_space_count)
482 *no_space_count = count;
484 }
485
486 if (limitEntry->mode == ITEM_LIMIT_CATEGORY_MODE_HAVE)
487 {
488 uint32 curcount = GetItemCountWithLimitCategory(pProto->ItemLimitCategory, pItem);
489 if (curcount + count > uint32(limitEntry->maxCount))
490 {
491 if (no_space_count)
492 *no_space_count = count + curcount - limitEntry->maxCount;
494 }
495 }
496 }
497
498 return EQUIP_ERR_OK;
499}
500
501InventoryResult Player::CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count /*= NULL*/) const
502{
503 return CanStoreItem(bag, slot, dest, item, count, NULL, false, no_space_count);
504}
505
506InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, Item* pItem, bool swap /*= false*/) const
507{
508 if (!pItem)
510 uint32 count = pItem->GetCount();
511 return CanStoreItem(bag, slot, dest, pItem->GetEntry(), count, pItem, swap, NULL);
512}
513
514InventoryResult Player::CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemTemplate const* pProto, uint32& count, bool swap, Item* pSrcItem) const
515{
516 Item* pItem2 = GetItemByPos(bag, slot);
517
518 // ignore move item (this slot will be empty at move)
519 if (pItem2 == pSrcItem)
520 pItem2 = NULL;
521
522 uint32 need_space;
523
524 if (pSrcItem && pSrcItem->IsNotEmptyBag() && !IsBagPos(uint16(bag) << 8 | slot))
526
527 // empty specific slot - check item fit to slot
528 if (!pItem2 || swap)
529 {
530 if (bag == INVENTORY_SLOT_BAG_0)
531 {
532 // prevent cheating
533 if ((slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END) || slot >= PLAYER_SLOT_END)
535 }
536 else
537 {
538 Bag* pBag = GetBagByPos(bag);
539 if (!pBag)
541
542 ItemTemplate const* pBagProto = pBag->GetTemplate();
543 if (!pBagProto)
545
546 if (slot >= pBagProto->ContainerSlots)
548
549 if (!ItemCanGoIntoBag(pProto, pBagProto))
551 }
552
553 // non empty stack with space
554 need_space = pProto->GetMaxStackSize();
555 }
556 // non empty slot, check item type
557 else
558 {
559 // can be merged at least partly
560 InventoryResult res = pItem2->CanBeMergedPartlyWith(pProto);
561 if (res != EQUIP_ERR_OK)
562 return res;
563
564 // free stack space or infinity
565 need_space = pProto->GetMaxStackSize() - pItem2->GetCount();
566 }
567
568 if (need_space > count)
569 need_space = count;
570
571 ItemPosCount newPosition = ItemPosCount((bag << 8) | slot, need_space);
572 if (!newPosition.isContainedIn(dest))
573 {
574 dest.push_back(newPosition);
575 count -= need_space;
576 }
577 return EQUIP_ERR_OK;
578}
579
580InventoryResult Player::CanStoreItem_InBag(uint8 bag, ItemPosCountVec& dest, ItemTemplate const* pProto, uint32& count, bool merge, bool non_specialized, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot) const
581{
582 // skip specific bag already processed in first called CanStoreItem_InBag
583 if (bag == skip_bag)
585
586 // skip not existed bag or self targeted bag
587 Bag* pBag = GetBagByPos(bag);
588 if (!pBag || pBag == pSrcItem)
590
591 if (pSrcItem && pSrcItem->IsNotEmptyBag())
593
594 ItemTemplate const* pBagProto = pBag->GetTemplate();
595 if (!pBagProto)
597
598 // specialized bag mode or non-specilized
599 if (non_specialized != (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER))
601
602 if (!ItemCanGoIntoBag(pProto, pBagProto))
604
605 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
606 {
607 // skip specific slot already processed in first called CanStoreItem_InSpecificSlot
608 if (j == skip_slot)
609 continue;
610
611 Item* pItem2 = GetItemByPos(bag, j);
612
613 // ignore move item (this slot will be empty at move)
614 if (pItem2 == pSrcItem)
615 pItem2 = NULL;
616
617 // if merge skip empty, if !merge skip non-empty
618 if ((pItem2 != NULL) != merge)
619 continue;
620
621 uint32 need_space = pProto->GetMaxStackSize();
622
623 if (pItem2)
624 {
625 // can be merged at least partly
626 uint8 res = pItem2->CanBeMergedPartlyWith(pProto);
627 if (res != EQUIP_ERR_OK)
628 continue;
629
630 // descrease at current stacksize
631 need_space -= pItem2->GetCount();
632 }
633
634 if (need_space > count)
635 need_space = count;
636
637 ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space);
638 if (!newPosition.isContainedIn(dest))
639 {
640 dest.push_back(newPosition);
641 count -= need_space;
642
643 if (count == 0)
644 return EQUIP_ERR_OK;
645 }
646 }
647 return EQUIP_ERR_OK;
648}
649
650InventoryResult Player::CanStoreItem_InInventorySlots(uint8 slot_begin, uint8 slot_end, ItemPosCountVec& dest, ItemTemplate const* pProto, uint32& count, bool merge, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot) const
651{
652 //this is never called for non-bag slots so we can do this
653 if (pSrcItem && pSrcItem->IsNotEmptyBag())
655
656 for (uint32 j = slot_begin; j < slot_end; j++)
657 {
658 // skip specific slot already processed in first called CanStoreItem_InSpecificSlot
659 if (INVENTORY_SLOT_BAG_0 == skip_bag && j == skip_slot)
660 continue;
661
663
664 // ignore move item (this slot will be empty at move)
665 if (pItem2 == pSrcItem)
666 pItem2 = NULL;
667
668 // if merge skip empty, if !merge skip non-empty
669 if ((pItem2 != NULL) != merge)
670 continue;
671
672 uint32 need_space = pProto->GetMaxStackSize();
673
674 if (pItem2)
675 {
676 // can be merged at least partly
677 uint8 res = pItem2->CanBeMergedPartlyWith(pProto);
678 if (res != EQUIP_ERR_OK)
679 continue;
680
681 // descrease at current stacksize
682 need_space -= pItem2->GetCount();
683 }
684
685 if (need_space > count)
686 need_space = count;
687
688 ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space);
689 if (!newPosition.isContainedIn(dest))
690 {
691 dest.push_back(newPosition);
692 count -= need_space;
693
694 if (count == 0)
695 return EQUIP_ERR_OK;
696 }
697 }
698 return EQUIP_ERR_OK;
699}
700
701InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item* pItem, bool swap, uint32* no_space_count) const
702{
703 SF_LOG_DEBUG("entities.player.items", "STORAGE: CanStoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, entry, count);
704
705 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(entry);
706 if (!pProto)
707 {
708 if (no_space_count)
709 *no_space_count = count;
711 }
712
713 if (pItem)
714 {
715 // item used
716 if (pItem->m_lootGenerated)
717 {
718 if (no_space_count)
719 *no_space_count = count;
720 return EQUIP_ERR_LOOT_GONE;
721 }
722
723 if (pItem->IsBindedNotWith(this))
724 {
725 if (no_space_count)
726 *no_space_count = count;
727 return EQUIP_ERR_NOT_OWNER;
728 }
729 }
730
731 // check count of items (skip for auto move for same player from bank)
732 uint32 no_similar_count = 0; // can't store this amount similar items
733 InventoryResult res = CanTakeMoreSimilarItems(entry, count, pItem, &no_similar_count);
734 if (res != EQUIP_ERR_OK)
735 {
736 if (count == no_similar_count)
737 {
738 if (no_space_count)
739 *no_space_count = no_similar_count;
740 return res;
741 }
742 count -= no_similar_count;
743 }
744
745 // in specific slot
746 if (bag != NULL_BAG && slot != NULL_SLOT)
747 {
748 res = CanStoreItem_InSpecificSlot(bag, slot, dest, pProto, count, swap, pItem);
749 if (res != EQUIP_ERR_OK)
750 {
751 if (no_space_count)
752 *no_space_count = count + no_similar_count;
753 return res;
754 }
755
756 if (count == 0)
757 {
758 if (no_similar_count == 0)
759 return EQUIP_ERR_OK;
760
761 if (no_space_count)
762 *no_space_count = count + no_similar_count;
764 }
765 }
766
767 // not specific slot or have space for partly store only in specific slot
768
769 // in specific bag
770 if (bag != NULL_BAG)
771 {
772 // search stack in bag for merge to
773 if (pProto->Stackable != 1)
774 {
775 if (bag == INVENTORY_SLOT_BAG_0) // inventory
776 {
777 res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, true, pItem, bag, slot);
778 if (res != EQUIP_ERR_OK)
779 {
780 if (no_space_count)
781 *no_space_count = count + no_similar_count;
782 return res;
783 }
784
785 if (count == 0)
786 {
787 if (no_similar_count == 0)
788 return EQUIP_ERR_OK;
789
790 if (no_space_count)
791 *no_space_count = count + no_similar_count;
793 }
794 }
795 else // equipped bag
796 {
797 // we need check 2 time (specialized/non_specialized), use NULL_BAG to prevent skipping bag
798 res = CanStoreItem_InBag(bag, dest, pProto, count, true, false, pItem, NULL_BAG, slot);
799 if (res != EQUIP_ERR_OK)
800 res = CanStoreItem_InBag(bag, dest, pProto, count, true, true, pItem, NULL_BAG, slot);
801
802 if (res != EQUIP_ERR_OK)
803 {
804 if (no_space_count)
805 *no_space_count = count + no_similar_count;
806 return res;
807 }
808
809 if (count == 0)
810 {
811 if (no_similar_count == 0)
812 return EQUIP_ERR_OK;
813
814 if (no_space_count)
815 *no_space_count = count + no_similar_count;
817 }
818 }
819 }
820
821 // search free slot in bag for place to
822 if (bag == INVENTORY_SLOT_BAG_0) // inventory
823 {
824 res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, false, pItem, bag, slot);
825 if (res != EQUIP_ERR_OK)
826 {
827 if (no_space_count)
828 *no_space_count = count + no_similar_count;
829 return res;
830 }
831
832 if (count == 0)
833 {
834 if (no_similar_count == 0)
835 return EQUIP_ERR_OK;
836
837 if (no_space_count)
838 *no_space_count = count + no_similar_count;
840 }
841 }
842 else // equipped bag
843 {
844 res = CanStoreItem_InBag(bag, dest, pProto, count, false, false, pItem, NULL_BAG, slot);
845 if (res != EQUIP_ERR_OK)
846 res = CanStoreItem_InBag(bag, dest, pProto, count, false, true, pItem, NULL_BAG, slot);
847
848 if (res != EQUIP_ERR_OK)
849 {
850 if (no_space_count)
851 *no_space_count = count + no_similar_count;
852 return res;
853 }
854
855 if (count == 0)
856 {
857 if (no_similar_count == 0)
858 return EQUIP_ERR_OK;
859
860 if (no_space_count)
861 *no_space_count = count + no_similar_count;
863 }
864 }
865 }
866
867 // not specific bag or have space for partly store only in specific bag
868
869 // search stack for merge to
870 if (pProto->Stackable != 1)
871 {
872 res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, true, pItem, bag, slot);
873 if (res != EQUIP_ERR_OK)
874 {
875 if (no_space_count)
876 *no_space_count = count + no_similar_count;
877 return res;
878 }
879
880 if (count == 0)
881 {
882 if (no_similar_count == 0)
883 return EQUIP_ERR_OK;
884
885 if (no_space_count)
886 *no_space_count = count + no_similar_count;
888 }
889
890 if (pProto->BagFamily)
891 {
893 {
894 res = CanStoreItem_InBag(i, dest, pProto, count, true, false, pItem, bag, slot);
895 if (res != EQUIP_ERR_OK)
896 continue;
897
898 if (count == 0)
899 {
900 if (no_similar_count == 0)
901 return EQUIP_ERR_OK;
902
903 if (no_space_count)
904 *no_space_count = count + no_similar_count;
906 }
907 }
908 }
909
911 {
912 res = CanStoreItem_InBag(i, dest, pProto, count, true, true, pItem, bag, slot);
913 if (res != EQUIP_ERR_OK)
914 continue;
915
916 if (count == 0)
917 {
918 if (no_similar_count == 0)
919 return EQUIP_ERR_OK;
920
921 if (no_space_count)
922 *no_space_count = count + no_similar_count;
924 }
925 }
926 }
927
928 // search free slot - special bag case
929 if (pProto->BagFamily)
930 {
932 {
933 res = CanStoreItem_InBag(i, dest, pProto, count, false, false, pItem, bag, slot);
934 if (res != EQUIP_ERR_OK)
935 continue;
936
937 if (count == 0)
938 {
939 if (no_similar_count == 0)
940 return EQUIP_ERR_OK;
941
942 if (no_space_count)
943 *no_space_count = count + no_similar_count;
945 }
946 }
947 }
948
949 if (pItem && pItem->IsNotEmptyBag())
951
952 // search free slot
953 res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, false, pItem, bag, slot);
954 if (res != EQUIP_ERR_OK)
955 {
956 if (no_space_count)
957 *no_space_count = count + no_similar_count;
958 return res;
959 }
960
961 if (count == 0)
962 {
963 if (no_similar_count == 0)
964 return EQUIP_ERR_OK;
965
966 if (no_space_count)
967 *no_space_count = count + no_similar_count;
969 }
970
972 {
973 res = CanStoreItem_InBag(i, dest, pProto, count, false, true, pItem, bag, slot);
974 if (res != EQUIP_ERR_OK)
975 continue;
976
977 if (count == 0)
978 {
979 if (no_similar_count == 0)
980 return EQUIP_ERR_OK;
981
982 if (no_space_count)
983 *no_space_count = count + no_similar_count;
985 }
986 }
987
988 if (no_space_count)
989 *no_space_count = count + no_similar_count;
990
991 return EQUIP_ERR_INV_FULL;
992}
993
996{
997 Item* pItem2;
998
999 // fill space table
1002
1003 memset(inv_slot_items, 0, sizeof(int) * (INVENTORY_SLOT_ITEM_END - INVENTORY_SLOT_ITEM_START));
1004 memset(inv_bags, 0, sizeof(int) * (INVENTORY_SLOT_BAG_END - INVENTORY_SLOT_BAG_START) * MAX_BAG_SIZE);
1005
1007 {
1009 if (pItem2 && !pItem2->IsInTrade())
1010 inv_slot_items[i - INVENTORY_SLOT_ITEM_START] = pItem2->GetCount();
1011 }
1012
1014 if (Bag* pBag = GetBagByPos(i))
1015 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
1016 {
1017 pItem2 = GetItemByPos(i, j);
1018 if (pItem2 && !pItem2->IsInTrade())
1019 inv_bags[i - INVENTORY_SLOT_BAG_START][j] = pItem2->GetCount();
1020 }
1021
1022 // check free space for all items
1023 for (int k = 0; k < count; ++k)
1024 {
1025 Item* pItem = pItems[k];
1026
1027 // no item
1028 if (!pItem)
1029 continue;
1030
1031 SF_LOG_DEBUG("entities.player.items", "STORAGE: CanStoreItems %i. item = %u, count = %u", k + 1, pItem->GetEntry(), pItem->GetCount());
1032 ItemTemplate const* pProto = pItem->GetTemplate();
1033
1034 // strange item
1035 if (!pProto)
1037
1038 // item used
1039 if (pItem->m_lootGenerated)
1040 return EQUIP_ERR_LOOT_GONE;
1041
1042 // item it 'bind'
1043 if (pItem->IsBindedNotWith(this))
1044 return EQUIP_ERR_NOT_OWNER;
1045
1046 ItemTemplate const* pBagProto;
1047
1048 // item is 'one item only'
1050 if (res != EQUIP_ERR_OK)
1051 return res;
1052
1053 // search stack for merge to
1054 if (pProto->Stackable != 1)
1055 {
1056 bool b_found = false;
1057
1059 {
1061 if (pItem2 && pItem2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inv_slot_items[t - INVENTORY_SLOT_ITEM_START] + pItem->GetCount() <= pProto->GetMaxStackSize())
1062 {
1063 inv_slot_items[t - INVENTORY_SLOT_ITEM_START] += pItem->GetCount();
1064 b_found = true;
1065 break;
1066 }
1067 }
1068 if (b_found)
1069 continue;
1070
1071 for (int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t)
1072 {
1073 if (Bag* bag = GetBagByPos(t))
1074 {
1075 if (ItemCanGoIntoBag(pItem->GetTemplate(), bag->GetTemplate()))
1076 {
1077 for (uint32 j = 0; j < bag->GetBagSize(); j++)
1078 {
1079 pItem2 = GetItemByPos(t, j);
1080 if (pItem2 && pItem2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inv_bags[t - INVENTORY_SLOT_BAG_START][j] + pItem->GetCount() <= pProto->GetMaxStackSize())
1081 {
1082 inv_bags[t - INVENTORY_SLOT_BAG_START][j] += pItem->GetCount();
1083 b_found = true;
1084 break;
1085 }
1086 }
1087 }
1088 }
1089 }
1090 if (b_found)
1091 continue;
1092 }
1093
1094 // special bag case
1095 if (pProto->BagFamily)
1096 {
1097 bool b_found = false;
1098
1099 for (int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t)
1100 {
1101 if (Bag* bag = GetBagByPos(t))
1102 {
1103 pBagProto = bag->GetTemplate();
1104
1105 // not plain container check
1106 if (pBagProto && (pBagProto->Class != ITEM_CLASS_CONTAINER || pBagProto->SubClass != ITEM_SUBCLASS_CONTAINER) &&
1107 ItemCanGoIntoBag(pProto, pBagProto))
1108 {
1109 for (uint32 j = 0; j < bag->GetBagSize(); j++)
1110 {
1111 if (inv_bags[t - INVENTORY_SLOT_BAG_START][j] == 0)
1112 {
1113 inv_bags[t - INVENTORY_SLOT_BAG_START][j] = 1;
1114 b_found = true;
1115 break;
1116 }
1117 }
1118 }
1119 }
1120 }
1121 if (b_found)
1122 continue;
1123 }
1124
1125 // search free slot
1126 bool b_found = false;
1128 {
1129 if (inv_slot_items[t - INVENTORY_SLOT_ITEM_START] == 0)
1130 {
1131 inv_slot_items[t - INVENTORY_SLOT_ITEM_START] = 1;
1132 b_found = true;
1133 break;
1134 }
1135 }
1136 if (b_found)
1137 continue;
1138
1139 // search free slot in bags
1140 for (int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t)
1141 {
1142 if (Bag* bag = GetBagByPos(t))
1143 {
1144 pBagProto = bag->GetTemplate();
1145
1146 // special bag already checked
1147 if (pBagProto && (pBagProto->Class != ITEM_CLASS_CONTAINER || pBagProto->SubClass != ITEM_SUBCLASS_CONTAINER))
1148 continue;
1149
1150 for (uint32 j = 0; j < bag->GetBagSize(); j++)
1151 {
1152 if (inv_bags[t - INVENTORY_SLOT_BAG_START][j] == 0)
1153 {
1154 inv_bags[t - INVENTORY_SLOT_BAG_START][j] = 1;
1155 b_found = true;
1156 break;
1157 }
1158 }
1159 }
1160 }
1161
1162 // no free slot found?
1163 if (!b_found)
1164 return EQUIP_ERR_INV_FULL;
1165 }
1166
1167 return EQUIP_ERR_OK;
1168}
1169
1171{
1172 SF_LOG_DEBUG("entities.player.items", "STORAGE: Creating initial item, itemId = %u, count = %u", titem_id, titem_amount);
1173
1174 // attempt equip by one
1175 while (titem_amount > 0)
1176 {
1177 uint16 eDest;
1178 InventoryResult msg = CanEquipNewItem(NULL_SLOT, eDest, titem_id, false);
1179 if (msg != EQUIP_ERR_OK)
1180 break;
1181
1182 EquipNewItem(eDest, titem_id, true);
1184 --titem_amount;
1185 }
1186
1187 if (titem_amount == 0)
1188 return true; // equipped
1189
1190 // attempt store
1191 ItemPosCountVec sDest;
1192 // store in main bag to simplify second pass (special bags can be not equipped yet at this moment)
1193 InventoryResult msg = CanStoreNewItem(INVENTORY_SLOT_BAG_0, NULL_SLOT, sDest, titem_id, titem_amount);
1194 if (msg == EQUIP_ERR_OK)
1195 {
1196 StoreNewItem(sDest, titem_id, true, Item::GenerateItemRandomPropertyId(titem_id));
1197 return true; // stored
1198 }
1199
1200 // item can't be added
1201 SF_LOG_ERROR("entities.player.items", "STORAGE: Can't equip or store initial item %u for race %u class %u, error msg = %u", titem_id, getRace(), getClass(), msg);
1202 return false;
1203}
1204
1206{
1207 uint32 tempcount = 0;
1208
1210
1212 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
1213 if (pItem->GetEntry() == item)
1214 {
1215 InventoryResult ires = CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i, false);
1216 if (ires == EQUIP_ERR_OK)
1217 {
1218 tempcount += pItem->GetCount();
1219 if (tempcount >= count)
1220 return EQUIP_ERR_OK;
1221 }
1222 else
1223 res = ires;
1224 }
1225
1227 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
1228 if (pItem->GetEntry() == item)
1229 {
1230 tempcount += pItem->GetCount();
1231 if (tempcount >= count)
1232 return EQUIP_ERR_OK;
1233 }
1234
1235
1237 if (Bag* pBag = GetBagByPos(i))
1238 for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
1239 if (Item* pItem = GetItemByPos(i, j))
1240 if (pItem->GetEntry() == item)
1241 {
1242 tempcount += pItem->GetCount();
1243 if (tempcount >= count)
1244 return EQUIP_ERR_OK;
1245 }
1246
1247 // not found req. item count and have unequippable items
1248 return res;
1249}
1250
1251InventoryResult Player::CanEquipNewItem(uint8 slot, uint16& dest, uint32 item, bool swap) const
1252{
1253 dest = 0;
1254 Item* pItem = Item::CreateItem(item, 1, this);
1255 if (pItem)
1256 {
1257 InventoryResult result = CanEquipItem(slot, dest, pItem, swap);
1258 delete pItem;
1259 return result;
1260 }
1261
1263}
1264
1265InventoryResult Player::CanEquipItem(uint8 slot, uint16& dest, Item* pItem, bool swap, bool not_loading) const
1266{
1267 dest = 0;
1268 if (pItem)
1269 {
1270 SF_LOG_DEBUG("entities.player.items", "STORAGE: CanEquipItem slot = %u, item = %u, count = %u", slot, pItem->GetEntry(), pItem->GetCount());
1271 ItemTemplate const* pProto = pItem->GetTemplate();
1272 if (pProto)
1273 {
1274 // item used
1275 if (pItem->m_lootGenerated)
1276 return EQUIP_ERR_LOOT_GONE;
1277
1278 if (pItem->IsBindedNotWith(this))
1279 return EQUIP_ERR_NOT_OWNER;
1280
1281 // check count of items (skip for auto move for same player from bank)
1283 if (res != EQUIP_ERR_OK)
1284 return res;
1285
1286 // check this only in game
1287 if (not_loading)
1288 {
1289 // May be here should be more stronger checks; STUNNED checked
1290 // ROOT, CONFUSED, DISTRACTED, FLEEING this needs to be checked.
1293
1294 // do not allow equipping gear except weapons, offhands, projectiles, relics in
1295 // - combat
1296 // - in-progress arenas
1297 if (!pProto->CanChangeEquipStateInCombat())
1298 {
1299 if (IsInCombat())
1301
1302 if (Battleground* bg = GetBattleground())
1303 if (bg->isArena() && bg->GetStatus() == STATUS_IN_PROGRESS)
1305 }
1306
1307 if (IsInCombat() && (pProto->Class == ITEM_CLASS_WEAPON || pProto->InventoryType == INVTYPE_RELIC) && m_weaponChangeTimer != 0)
1308 return EQUIP_ERR_CLIENT_LOCKED_OUT; // maybe exist better err
1309
1310 if (IsNonMeleeSpellCasted(false))
1312 }
1313
1315 // check allowed level (extend range to upper values if MaxLevel more or equal max player level, this let GM set high level with 1...max range items)
1316 if (ssd && ssd->MaxLevel < DEFAULT_MAX_LEVEL && ssd->MaxLevel < getLevel())
1318
1319 uint8 eslot = FindEquipSlot(pProto, slot, swap);
1320 if (eslot == NULL_SLOT)
1322
1323 res = CanUseItem(pItem, not_loading);
1324 if (res != EQUIP_ERR_OK)
1325 return res;
1326
1327 if (!swap && GetItemByPos(INVENTORY_SLOT_BAG_0, eslot))
1329
1330 // if we are swapping 2 equiped items, CanEquipUniqueItem check
1331 // should ignore the item we are trying to swap, and not the
1332 // destination item. CanEquipUniqueItem should ignore destination
1333 // item only when we are swapping weapon from bag
1334 uint8 ignore = uint8(NULL_SLOT);
1335 switch (eslot)
1336 {
1338 ignore = EQUIPMENT_SLOT_OFFHAND;
1339 break;
1341 ignore = EQUIPMENT_SLOT_MAINHAND;
1342 break;
1344 ignore = EQUIPMENT_SLOT_FINGER2;
1345 break;
1347 ignore = EQUIPMENT_SLOT_FINGER1;
1348 break;
1350 ignore = EQUIPMENT_SLOT_TRINKET2;
1351 break;
1353 ignore = EQUIPMENT_SLOT_TRINKET1;
1354 break;
1355 }
1356
1357 if (ignore == uint8(NULL_SLOT) || pItem != GetItemByPos(INVENTORY_SLOT_BAG_0, ignore))
1358 ignore = eslot;
1359
1360 InventoryResult res2 = CanEquipUniqueItem(pItem, swap ? ignore : uint8(NULL_SLOT));
1361 if (res2 != EQUIP_ERR_OK)
1362 return res2;
1363
1364 // check unique-equipped special item classes
1365 if (pProto->Class == ITEM_CLASS_QUIVER)
1367 if (Item* pBag = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
1368 if (pBag != pItem)
1369 if (ItemTemplate const* pBagProto = pBag->GetTemplate())
1370 if (pBagProto->Class == pProto->Class && (!swap || pBag->GetSlot() != eslot))
1371 return (pBagProto->SubClass == ITEM_SUBCLASS_AMMO_POUCH)
1374
1375 uint32 type = pProto->InventoryType;
1376
1377 if (eslot == EQUIPMENT_SLOT_OFFHAND)
1378 {
1379 // Do not allow polearm to be equipped in the offhand (rare case for the only 1h polearm 41750)
1380 if (type == INVTYPE_WEAPON && pProto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM)
1382 else if (type == INVTYPE_WEAPON || type == INVTYPE_WEAPONOFFHAND)
1383 {
1384 if (!CanDualWield())
1386 }
1387 else if (type == INVTYPE_2HWEAPON)
1388 {
1389 if (!CanDualWield() || !CanTitanGrip())
1391 }
1392
1393 if (IsTwoHandUsed())
1395 }
1396
1397 // equip two-hand weapon case (with possible unequip 2 items)
1398 if (type == INVTYPE_2HWEAPON)
1399 {
1400 if (eslot == EQUIPMENT_SLOT_OFFHAND)
1401 {
1402 if (!CanTitanGrip())
1404 }
1405 else if (eslot != EQUIPMENT_SLOT_MAINHAND)
1407
1408 if (!CanTitanGrip())
1409 {
1410 // offhand item must can be stored in inventory for offhand item and it also must be unequipped
1412 ItemPosCountVec off_dest;
1413 if (offItem && (!not_loading ||
1415 CanStoreItem(NULL_BAG, NULL_SLOT, off_dest, offItem, false) != EQUIP_ERR_OK))
1417 }
1418 }
1419 dest = ((INVENTORY_SLOT_BAG_0 << 8) | eslot);
1420 return EQUIP_ERR_OK;
1421 }
1422 }
1423
1425}
1426
1428{
1429 // Applied only to equipped items and bank bags
1430 if (!IsEquipmentPos(pos) && !IsBagPos(pos))
1431 return EQUIP_ERR_OK;
1432
1433 Item* pItem = GetItemByPos(pos);
1434
1435 // Applied only to existed equipped item
1436 if (!pItem)
1437 return EQUIP_ERR_OK;
1438
1439 SF_LOG_DEBUG("entities.player.items", "STORAGE: CanUnequipItem slot = %u, item = %u, count = %u", pos, pItem->GetEntry(), pItem->GetCount());
1440
1441 ItemTemplate const* pProto = pItem->GetTemplate();
1442 if (!pProto)
1444
1445 // item used
1446 if (pItem->m_lootGenerated)
1447 return EQUIP_ERR_LOOT_GONE;
1448
1449 // do not allow unequipping gear except weapons, offhands, projectiles, relics in
1450 // - combat
1451 // - in-progress arenas
1452 if (!pProto->CanChangeEquipStateInCombat())
1453 {
1454 if (IsInCombat())
1456
1457 if (Battleground* bg = GetBattleground())
1458 if (bg->isArena() && bg->GetStatus() == STATUS_IN_PROGRESS)
1460 }
1461
1462 if (!swap && pItem->IsNotEmptyBag())
1464
1465 return EQUIP_ERR_OK;
1466}
1467
1468InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, Item* pItem, bool swap, bool not_loading) const
1469{
1470 if (!pItem)
1472
1473 uint32 count = pItem->GetCount();
1474
1475 SF_LOG_DEBUG("entities.player.items", "STORAGE: CanBankItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount());
1476 ItemTemplate const* pProto = pItem->GetTemplate();
1477 if (!pProto)
1479
1480 // item used
1481 if (pItem->m_lootGenerated)
1482 return EQUIP_ERR_LOOT_GONE;
1483
1484 if (pItem->IsBindedNotWith(this))
1485 return EQUIP_ERR_NOT_OWNER;
1486
1487 // Currency Tokenizer are not supposed to be swapped out of their hidden bag
1488 if (pItem->IsCurrencyToken())
1489 {
1490 SF_LOG_ERROR("entities.player", "Possible hacking attempt: Player %s [guid: %u] tried to move token [guid: %u, entry: %u] out of the currency bag!",
1491 GetName().c_str(), GetGUIDLow(), pItem->GetGUIDLow(), pProto->ItemId);
1492 return EQUIP_ERR_CANT_SWAP;
1493 }
1494
1495 // check count of items (skip for auto move for same player from bank)
1497 if (res != EQUIP_ERR_OK)
1498 return res;
1499
1500 // in specific slot
1501 if (bag != NULL_BAG && slot != NULL_SLOT)
1502 {
1503 if (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END)
1504 {
1505 if (!pItem->IsBag())
1506 return EQUIP_ERR_WRONG_SLOT;
1507
1510
1511 res = CanUseItem(pItem, not_loading);
1512 if (res != EQUIP_ERR_OK)
1513 return res;
1514 }
1515
1516 res = CanStoreItem_InSpecificSlot(bag, slot, dest, pProto, count, swap, pItem);
1517 if (res != EQUIP_ERR_OK)
1518 return res;
1519
1520 if (count == 0)
1521 return EQUIP_ERR_OK;
1522 }
1523
1524 // not specific slot or have space for partly store only in specific slot
1525
1526 // in specific bag
1527 if (bag != NULL_BAG)
1528 {
1529 if (pItem->IsNotEmptyBag())
1530 return EQUIP_ERR_BAG_IN_BAG;
1531
1532 // search stack in bag for merge to
1533 if (pProto->Stackable != 1)
1534 {
1535 if (bag == INVENTORY_SLOT_BAG_0)
1536 {
1537 res = CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START, BANK_SLOT_ITEM_END, dest, pProto, count, true, pItem, bag, slot);
1538 if (res != EQUIP_ERR_OK)
1539 return res;
1540
1541 if (count == 0)
1542 return EQUIP_ERR_OK;
1543 }
1544 else
1545 {
1546 res = CanStoreItem_InBag(bag, dest, pProto, count, true, false, pItem, NULL_BAG, slot);
1547 if (res != EQUIP_ERR_OK)
1548 res = CanStoreItem_InBag(bag, dest, pProto, count, true, true, pItem, NULL_BAG, slot);
1549
1550 if (res != EQUIP_ERR_OK)
1551 return res;
1552
1553 if (count == 0)
1554 return EQUIP_ERR_OK;
1555 }
1556 }
1557
1558 // search free slot in bag
1559 if (bag == INVENTORY_SLOT_BAG_0)
1560 {
1561 res = CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START, BANK_SLOT_ITEM_END, dest, pProto, count, false, pItem, bag, slot);
1562 if (res != EQUIP_ERR_OK)
1563 return res;
1564
1565 if (count == 0)
1566 return EQUIP_ERR_OK;
1567 }
1568 else
1569 {
1570 res = CanStoreItem_InBag(bag, dest, pProto, count, false, false, pItem, NULL_BAG, slot);
1571 if (res != EQUIP_ERR_OK)
1572 res = CanStoreItem_InBag(bag, dest, pProto, count, false, true, pItem, NULL_BAG, slot);
1573
1574 if (res != EQUIP_ERR_OK)
1575 return res;
1576
1577 if (count == 0)
1578 return EQUIP_ERR_OK;
1579 }
1580 }
1581
1582 // not specific bag or have space for partly store only in specific bag
1583
1584 // search stack for merge to
1585 if (pProto->Stackable != 1)
1586 {
1587 // in slots
1588 res = CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START, BANK_SLOT_ITEM_END, dest, pProto, count, true, pItem, bag, slot);
1589 if (res != EQUIP_ERR_OK)
1590 return res;
1591
1592 if (count == 0)
1593 return EQUIP_ERR_OK;
1594
1595 // in special bags
1596 if (pProto->BagFamily)
1597 {
1598 for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
1599 {
1600 res = CanStoreItem_InBag(i, dest, pProto, count, true, false, pItem, bag, slot);
1601 if (res != EQUIP_ERR_OK)
1602 continue;
1603
1604 if (count == 0)
1605 return EQUIP_ERR_OK;
1606 }
1607 }
1608
1609 for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
1610 {
1611 res = CanStoreItem_InBag(i, dest, pProto, count, true, true, pItem, bag, slot);
1612 if (res != EQUIP_ERR_OK)
1613 continue;
1614
1615 if (count == 0)
1616 return EQUIP_ERR_OK;
1617 }
1618 }
1619
1620 // search free place in special bag
1621 if (pProto->BagFamily)
1622 {
1623 for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
1624 {
1625 res = CanStoreItem_InBag(i, dest, pProto, count, false, false, pItem, bag, slot);
1626 if (res != EQUIP_ERR_OK)
1627 continue;
1628
1629 if (count == 0)
1630 return EQUIP_ERR_OK;
1631 }
1632 }
1633
1634 // search free space
1635 res = CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START, BANK_SLOT_ITEM_END, dest, pProto, count, false, pItem, bag, slot);
1636 if (res != EQUIP_ERR_OK)
1637 return res;
1638
1639 if (count == 0)
1640 return EQUIP_ERR_OK;
1641
1642 for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
1643 {
1644 res = CanStoreItem_InBag(i, dest, pProto, count, false, true, pItem, bag, slot);
1645 if (res != EQUIP_ERR_OK)
1646 continue;
1647
1648 if (count == 0)
1649 return EQUIP_ERR_OK;
1650 }
1651 return EQUIP_ERR_BANK_FULL;
1652}
1653
1654InventoryResult Player::CanUseItem(Item* pItem, bool not_loading) const
1655{
1656 if (pItem)
1657 {
1658 SF_LOG_DEBUG("entities.player.items", "STORAGE: CanUseItem item = %u", pItem->GetEntry());
1659
1660 if (!IsAlive() && not_loading)
1661 return EQUIP_ERR_PLAYER_DEAD;
1662
1663 //if (isStunned())
1664 // return EQUIP_ERR_GENERIC_STUNNED;
1665
1666 ItemTemplate const* pProto = pItem->GetTemplate();
1667 if (pProto)
1668 {
1669 if (pItem->IsBindedNotWith(this))
1670 return EQUIP_ERR_NOT_OWNER;
1671
1672 InventoryResult res = CanUseItem(pProto);
1673 if (res != EQUIP_ERR_OK)
1674 return res;
1675
1676 if (pItem->GetSkill() != 0)
1677 {
1678 bool allowEquip = false;
1679 uint32 itemSkill = pItem->GetSkill();
1680 // Armor that is binded to account can "morph" from plate to mail, etc. if skill is not learned yet.
1681 if (pProto->Quality == ITEM_QUALITY_HEIRLOOM && pProto->Class == ITEM_CLASS_ARMOR && !HasSkill(itemSkill))
1682 {
1684 // In fact it's a visual bug, everything works properly... I need sniffs of operations with
1685 // binded to account items from off server.
1686
1687 switch (getClass())
1688 {
1689 case CLASS_HUNTER:
1690 case CLASS_SHAMAN:
1691 allowEquip = (itemSkill == SKILL_MAIL);
1692 break;
1693 case CLASS_PALADIN:
1694 case CLASS_WARRIOR:
1695 allowEquip = (itemSkill == SKILL_PLATE_MAIL);
1696 break;
1697 }
1698 }
1699 if (!allowEquip && GetSkillValue(itemSkill) == 0)
1701 }
1702
1705
1706 return EQUIP_ERR_OK;
1707 }
1708 }
1710}
1711
1713{
1714 // Used by group, function NeedBeforeGreed, to know if a prototype can be used by a player
1715
1716 if (proto)
1717 {
1718 if ((proto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && GetTeam() != HORDE)
1720
1723
1724 if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0)
1726
1727 if (proto->RequiredSkill != 0)
1728 {
1729 if (GetSkillValue(proto->RequiredSkill) == 0)
1731 else if (GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank)
1733 }
1734
1735 if (proto->RequiredSpell != 0 && !HasSpell(proto->RequiredSpell))
1737
1738 if (getLevel() < proto->RequiredLevel)
1740
1741 // If World Event is not active, prevent using event dependant items
1742 if (proto->HolidayId && !IsHolidayActive((HolidayIds)proto->HolidayId))
1744
1745 return EQUIP_ERR_OK;
1746 }
1747
1749}
1750
1752{
1753 if (!GetGroup() || !GetGroup()->isLFGGroup())
1754 return EQUIP_ERR_OK; // not in LFG group
1755
1756 // check if looted object is inside the lfg dungeon
1757 Map const* map = lootedObject->GetMap();
1758 if (!sLFGMgr->inLfgDungeonMap(GetGroup()->GetGUID(), map->GetId(), map->GetDifficulty()))
1759 return EQUIP_ERR_OK;
1760
1761 if (!proto)
1763 // Used by group, function NeedBeforeGreed, to know if a prototype can be used by a player
1764
1765 const static uint32 item_weapon_skills[MAX_ITEM_SUBCLASS_WEAPON] =
1766 {
1772 }; //Copy from function Item::GetSkill()
1773
1774 if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0)
1776
1777 if (proto->RequiredSpell != 0 && !HasSpell(proto->RequiredSpell))
1779
1780 if (proto->RequiredSkill != 0)
1781 {
1782 if (!GetSkillValue(proto->RequiredSkill))
1784 else if (GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank)
1786 }
1787
1788 uint8 _class = getClass();
1789
1790 if (proto->Class == ITEM_CLASS_WEAPON && GetSkillValue(item_weapon_skills[proto->SubClass]) == 0)
1792
1794 {
1795 if (_class == CLASS_WARRIOR || _class == CLASS_PALADIN || _class == CLASS_DEATH_KNIGHT)
1796 {
1797 if (getLevel() < 50)
1798 {
1799 if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL)
1801 }
1802 else if (proto->SubClass != ITEM_SUBCLASS_ARMOR_PLATE)
1804 }
1805 else if (_class == CLASS_HUNTER || _class == CLASS_SHAMAN)
1806 {
1807 if (getLevel() < 50)
1808 {
1811 }
1812 else if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL)
1814 }
1815 else if (_class == CLASS_MONK)
1816 {
1817 if (getLevel() < 50)
1818 {
1819 if (proto->SubClass != ITEM_SUBCLASS_ARMOR_CLOTH)
1821 }
1822 else if (proto->SubClass != ITEM_SUBCLASS_LEATHER)
1824 }
1825
1826 if (_class == CLASS_ROGUE || _class == CLASS_DRUID)
1829
1830 if (_class == CLASS_MAGE || _class == CLASS_PRIEST || _class == CLASS_WARLOCK)
1831 if (proto->SubClass != ITEM_SUBCLASS_ARMOR_CLOTH)
1833 }
1834
1835 return EQUIP_ERR_OK;
1836}
1837
1838// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
1839Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update, int32 randomPropertyId, AllowedLooterSet const& allowedLooters)
1840{
1841 uint32 count = 0;
1842 for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ++itr)
1843 count += itr->count;
1844
1845 Item* pItem = Item::CreateItem(item, count, this);
1846 if (pItem)
1847 {
1848 ItemAddedQuestCheck(item, count);
1851 if (randomPropertyId)
1852 pItem->SetItemRandomProperties(randomPropertyId);
1853 pItem = StoreItem(dest, pItem, update);
1854
1855 if (allowedLooters.size() > 1 && pItem->GetTemplate()->GetMaxStackSize() == 1 && pItem->IsSoulBound())
1856 {
1857 pItem->SetSoulboundTradeable(allowedLooters);
1859 AddTradeableItem(pItem);
1860
1861 // save data
1862 std::ostringstream ss;
1863 AllowedLooterSet::const_iterator itr = allowedLooters.begin();
1864 ss << *itr;
1865 for (++itr; itr != allowedLooters.end(); ++itr)
1866 ss << ' ' << *itr;
1867
1868 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_BOP_TRADE);
1869 stmt->setUInt32(0, pItem->GetGUIDLow());
1870 stmt->setString(1, ss.str());
1871 CharacterDatabase.Execute(stmt);
1872 }
1873 }
1874 return pItem;
1875}
1876
1877Item* Player::StoreItem(ItemPosCountVec const& dest, Item* pItem, bool update)
1878{
1879 if (!pItem)
1880 return NULL;
1881
1882 Item* lastItem = pItem;
1883 for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end();)
1884 {
1885 uint16 pos = itr->pos;
1886 uint32 count = itr->count;
1887
1888 ++itr;
1889
1890 if (itr == dest.end())
1891 {
1892 lastItem = _StoreItem(pos, pItem, count, false, update);
1893 break;
1894 }
1895
1896 lastItem = _StoreItem(pos, pItem, count, true, update);
1897 }
1898 return lastItem;
1899}
1900
1901// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
1902Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool update)
1903{
1904 if (!pItem)
1905 return NULL;
1906
1907 uint8 bag = pos >> 8;
1908 uint8 slot = pos & 255;
1909
1910 SF_LOG_DEBUG("entities.player.items", "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u, guid = %u", bag, slot, pItem->GetEntry(), count, pItem->GetGUIDLow());
1911
1912 Item* pItem2 = GetItemByPos(bag, slot);
1913
1914 if (!pItem2)
1915 {
1916 if (clone)
1917 pItem = pItem->CloneItem(count, this);
1918 else
1919 pItem->SetCount(count);
1920
1921 if (!pItem)
1922 return NULL;
1923
1924 if (pItem->GetTemplate()->Bonding == BIND_WHEN_PICKED_UP ||
1925 pItem->GetTemplate()->Bonding == BIND_QUEST_ITEM ||
1926 (pItem->GetTemplate()->Bonding == BIND_WHEN_EQUIPED && IsBagPos(pos)))
1927 pItem->SetBinding(true);
1928
1929 Bag* pBag = (bag == INVENTORY_SLOT_BAG_0) ? NULL : GetBagByPos(bag);
1930 if (!pBag)
1931 {
1932 m_items[slot] = pItem;
1933 SetUInt64Value(PLAYER_FIELD_INV_SLOTS + (slot * 2), pItem->GetGUID());
1936
1937 pItem->SetSlot(slot);
1938 pItem->SetContainer(NULL);
1939 }
1940 else
1941 pBag->StoreItem(slot, pItem, update);
1942
1943 if (IsInWorld() && update)
1944 {
1945 pItem->AddToWorld();
1946 pItem->SendUpdateToPlayer(this);
1947 }
1948
1949 pItem->SetState(ITEM_CHANGED, this);
1950 if (pBag)
1951 pBag->SetState(ITEM_CHANGED, this);
1952
1954 AddItemDurations(pItem);
1955
1956 const ItemTemplate* proto = pItem->GetTemplate();
1957 for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
1958 if (proto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE && proto->Spells[i].SpellId > 0) // On obtain trigger
1960 if (!HasAura(proto->Spells[i].SpellId))
1961 CastSpell(this, proto->Spells[i].SpellId, true, pItem);
1962
1963 return pItem;
1964 }
1965 else
1966 {
1967 if (pItem2->GetTemplate()->Bonding == BIND_WHEN_PICKED_UP ||
1968 pItem2->GetTemplate()->Bonding == BIND_QUEST_ITEM ||
1969 (pItem2->GetTemplate()->Bonding == BIND_WHEN_EQUIPED && IsBagPos(pos)))
1970 pItem2->SetBinding(true);
1971
1972 pItem2->SetCount(pItem2->GetCount() + count);
1973 if (IsInWorld() && update)
1974 pItem2->SendUpdateToPlayer(this);
1975
1976 if (!clone)
1977 {
1978 // delete item (it not in any slot currently)
1979 if (IsInWorld() && update)
1980 {
1981 pItem->RemoveFromWorld();
1982 pItem->DestroyForPlayer(this);
1983 }
1984
1986 RemoveItemDurations(pItem);
1987
1988 pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor
1989 pItem->SetNotRefundable(this);
1990 pItem->ClearSoulboundTradeable(this);
1991 RemoveTradeableItem(pItem);
1992 pItem->SetState(ITEM_REMOVED, this);
1993 }
1994
1996
1997 pItem2->SetState(ITEM_CHANGED, this);
1998
1999 const ItemTemplate* proto = pItem2->GetTemplate();
2000 for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
2001 if (proto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE && proto->Spells[i].SpellId > 0) // On obtain trigger
2003 if (!HasAura(proto->Spells[i].SpellId))
2004 CastSpell(this, proto->Spells[i].SpellId, true, pItem2);
2005
2006 return pItem2;
2007 }
2008}
2009
2010Item* Player::EquipNewItem(uint16 pos, uint32 item, bool update)
2011{
2012 if (Item* pItem = Item::CreateItem(item, 1, this))
2013 {
2014 ItemAddedQuestCheck(item, 1);
2016 return EquipItem(pos, pItem, update);
2017 }
2018
2019 return NULL;
2020}
2021
2022Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
2023{
2025 AddItemDurations(pItem);
2026
2027 uint8 bag = pos >> 8;
2028 uint8 slot = pos & 255;
2029
2030 Item* pItem2 = GetItemByPos(bag, slot);
2031
2032 if (!pItem2)
2033 {
2034 VisualizeItem(slot, pItem);
2035
2036 if (IsAlive())
2037 {
2038 ItemTemplate const* pProto = pItem->GetTemplate();
2039
2040 // item set bonuses applied only at equip and removed at unequip, and still active for broken items
2041 if (pProto && pProto->ItemSet)
2042 AddItemsSetItem(this, pItem);
2043
2044 _ApplyItemMods(pItem, slot, true);
2045
2046 if (pProto && IsInCombat() && (pProto->Class == ITEM_CLASS_WEAPON || pProto->InventoryType == INVTYPE_RELIC) && m_weaponChangeTimer == 0)
2047 {
2048 uint32 cooldownSpell = getClass() == CLASS_ROGUE ? 6123 : 6119;
2049 SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cooldownSpell);
2050
2051 if (!spellProto)
2052 SF_LOG_ERROR("entities.player", "Weapon switch cooldown spell %u couldn't be found in Spell.dbc", cooldownSpell);
2053 else
2054 {
2056
2058 ObjectGuid guid = GetGUID();
2059
2060 WorldPacket data(SMSG_SPELL_COOLDOWN, 9 + 3 + 8);
2061 data.WriteBit(guid[0]);
2062 data.WriteBit(guid[6]);
2063 data.WriteBit(1); // Missing flags
2064 data.WriteBit(guid[7]);
2065 data.WriteBit(guid[3]);
2066 data.WriteBit(guid[1]);
2067 data.WriteBit(guid[5]);
2068 size_t bitpos = data.bitwpos();
2069 data.WriteBits(1, 21);
2070 data.WriteBit(guid[2]);
2071 data.WriteBit(guid[4]);
2072
2073 data << uint32(cooldownSpell);
2074 data << uint32(0);
2075 data.WriteByteSeq(guid[5]);
2076 data.WriteByteSeq(guid[3]);
2077 data.WriteByteSeq(guid[7]);
2078 data.WriteByteSeq(guid[4]);
2079 data.WriteByteSeq(guid[1]);
2080 data.WriteByteSeq(guid[0]);
2081 data.WriteByteSeq(guid[2]);
2082 data.WriteByteSeq(guid[6]);
2083 GetSession()->SendPacket(&data);
2084 }
2085 }
2086 }
2087
2088 if (IsInWorld() && update)
2089 {
2090 pItem->AddToWorld();
2091 pItem->SendUpdateToPlayer(this);
2092 }
2093
2094 ApplyEquipCooldown(pItem);
2095
2096 // update expertise and armor penetration - passive auras may need it
2097
2098 if (slot == EQUIPMENT_SLOT_MAINHAND)
2100
2101 else if (slot == EQUIPMENT_SLOT_OFFHAND)
2103
2104 switch (slot)
2105 {
2108 {
2110 break;
2111 }
2112 default:
2113 break;
2114 }
2115 }
2116 else
2117 {
2118 pItem2->SetCount(pItem2->GetCount() + pItem->GetCount());
2119 if (IsInWorld() && update)
2120 pItem2->SendUpdateToPlayer(this);
2121
2122 // delete item (it not in any slot currently)
2123 //pItem->DeleteFromDB();
2124 if (IsInWorld() && update)
2125 {
2126 pItem->RemoveFromWorld();
2127 pItem->DestroyForPlayer(this);
2128 }
2129
2131 RemoveItemDurations(pItem);
2132
2133 pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor
2134 pItem->SetNotRefundable(this);
2135 pItem->ClearSoulboundTradeable(this);
2136 RemoveTradeableItem(pItem);
2137 pItem->SetState(ITEM_REMOVED, this);
2138 pItem2->SetState(ITEM_CHANGED, this);
2139
2140 ApplyEquipCooldown(pItem2);
2141
2142 return pItem2;
2143 }
2144
2145 // only for full equip instead adding to stack
2148
2149 return pItem;
2150}
2151
2153{
2154 if (pItem)
2155 {
2157 AddItemDurations(pItem);
2158
2159 uint8 slot = pos & 255;
2160 VisualizeItem(slot, pItem);
2161
2162 if (IsInWorld())
2163 {
2164 pItem->AddToWorld();
2165 pItem->SendUpdateToPlayer(this);
2166 }
2167
2170 }
2171}
2172
2174{
2175 if (pItem)
2176 {
2180 }
2181 else
2182 {
2184 SetUInt32Value(PLAYER_FIELD_VISIBLE_ITEMS + 1 + (slot * 2), 0);
2185 }
2186}
2187
2189{
2190 if (!pItem)
2191 return;
2192
2193 // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory)
2195 pItem->SetBinding(true);
2196
2197 SF_LOG_DEBUG("entities.player.items", "STORAGE: EquipItem slot = %u, item = %u", slot, pItem->GetEntry());
2198
2199 m_items[slot] = pItem;
2200 SetUInt64Value(PLAYER_FIELD_INV_SLOTS + (slot * 2), pItem->GetGUID());
2203 pItem->SetSlot(slot);
2204 pItem->SetContainer(NULL);
2205
2206 if (slot < EQUIPMENT_SLOT_END)
2207 SetVisibleItemSlot(slot, pItem);
2208
2209 pItem->SetState(ITEM_CHANGED, this);
2210}
2211
2212Item* Player::BankItem(ItemPosCountVec const& dest, Item* pItem, bool update)
2213{
2214 return StoreItem(dest, pItem, update);
2215}
2216
2217void Player::RemoveItem(uint8 bag, uint8 slot, bool update)
2218{
2219 // note: removeitem does not actually change the item
2220 // it only takes the item out of storage temporarily
2221 // note2: if removeitem is to be used for delinking
2222 // the item must be removed from the player's updatequeue
2223
2224 Item* pItem = GetItemByPos(bag, slot);
2225 if (pItem)
2226 {
2227 SF_LOG_DEBUG("entities.player.items", "STORAGE: RemoveItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry());
2228
2230 RemoveItemDurations(pItem);
2231 RemoveTradeableItem(pItem);
2232
2233 if (bag == INVENTORY_SLOT_BAG_0)
2234 {
2235 if (slot < INVENTORY_SLOT_BAG_END)
2236 {
2237 ItemTemplate const* pProto = pItem->GetTemplate();
2238 // item set bonuses applied only at equip and removed at unequip, and still active for broken items
2239
2240 if (pProto && pProto->ItemSet)
2241 RemoveItemsSetItem(this, pProto);
2242
2243 _ApplyItemMods(pItem, slot, false);
2244
2245 // remove item dependent auras and casts (only weapon and armor slots)
2246 if (slot < EQUIPMENT_SLOT_END)
2247 {
2249
2250 // remove held enchantments, update expertise
2251 if (slot == EQUIPMENT_SLOT_MAINHAND)
2252 {
2253 if (pItem->GetItemSuffixFactor())
2254 {
2257 }
2258 else
2259 {
2262 }
2263
2265 }
2266 else if (slot == EQUIPMENT_SLOT_OFFHAND)
2268 // update armor penetration - passive auras may need it
2269 switch (slot)
2270 {
2273 {
2275 break;
2276 }
2277 default:
2278 break;
2279 }
2280 }
2281 }
2282
2283 m_items[slot] = NULL;
2284 SetUInt64Value(PLAYER_FIELD_INV_SLOTS + (slot * 2), 0);
2285
2286 if (slot < EQUIPMENT_SLOT_END)
2287 SetVisibleItemSlot(slot, NULL);
2288 }
2289 else if (Bag* pBag = GetBagByPos(bag))
2290 pBag->RemoveItem(slot, update);
2291
2293 // pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0); not clear owner at remove (it will be set at store). This used in mail and auction code
2294 pItem->SetSlot(NULL_SLOT);
2295 if (IsInWorld() && update)
2296 pItem->SendUpdateToPlayer(this);
2297 }
2298}
2299
2300// Common operation need to remove item from inventory without delete in trade, auction, guild bank, mail....
2301void Player::MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
2302{
2303 if (Item* it = GetItemByPos(bag, slot))
2304 {
2305 ItemRemovedQuestCheck(it->GetEntry(), it->GetCount());
2306 RemoveItem(bag, slot, update);
2307 it->SetNotRefundable(this, false);
2308 it->RemoveFromUpdateQueueOf(this);
2309 if (it->IsInWorld())
2310 {
2311 it->RemoveFromWorld();
2312 it->DestroyForPlayer(this);
2313 }
2314 }
2315}
2316
2317// Common operation need to add item from inventory without delete in trade, guild bank, mail....
2318void Player::MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool update, bool in_characterInventoryDB)
2319{
2320 // update quest counters
2321 ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount());
2323
2324 // store item
2325 Item* pLastItem = StoreItem(dest, pItem, update);
2326
2327 // only set if not merged to existed stack (pItem can be deleted already but we can compare pointers any way)
2328 if (pLastItem == pItem)
2329 {
2330 // update owner for last item (this can be original item with wrong owner
2331 if (pLastItem->GetOwnerGUID() != GetGUID())
2332 pLastItem->SetOwnerGUID(GetGUID());
2333
2334 // if this original item then it need create record in inventory
2335 // in case trade we already have item in other player inventory
2336 pLastItem->SetState(in_characterInventoryDB ? ITEM_CHANGED : ITEM_NEW, this);
2337
2339 AddTradeableItem(pLastItem);
2340 }
2341}
2342
2343void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
2344{
2345 Item* pItem = GetItemByPos(bag, slot);
2346 if (pItem)
2347 {
2348 SF_LOG_DEBUG("entities.player.items", "STORAGE: DestroyItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry());
2349 // Also remove all contained items if the item is a bag.
2350 // This if () prevents item saving crashes if the condition for a bag to be empty before being destroyed was bypassed somehow.
2351 if (pItem->IsNotEmptyBag())
2352 for (uint8 i = 0; i < MAX_BAG_SIZE; ++i)
2353 DestroyItem(slot, i, update);
2354
2356 {
2357 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT);
2358
2359 stmt->setUInt32(0, pItem->GetGUIDLow());
2360
2361 CharacterDatabase.Execute(stmt);
2362 }
2363
2365 RemoveItemDurations(pItem);
2366
2367 pItem->SetNotRefundable(this);
2368 pItem->ClearSoulboundTradeable(this);
2369 RemoveTradeableItem(pItem);
2370
2371 const ItemTemplate* proto = pItem->GetTemplate();
2372 for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
2373 if (proto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE && proto->Spells[i].SpellId > 0) // On obtain trigger
2375
2376 ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount());
2377
2378 if (bag == INVENTORY_SLOT_BAG_0)
2379 {
2380 SetUInt64Value(PLAYER_FIELD_INV_SLOTS + (slot * 2), 0);
2381
2382 // equipment and equipped bags can have applied bonuses
2383 if (slot < INVENTORY_SLOT_BAG_END)
2384 {
2385 ItemTemplate const* pProto = pItem->GetTemplate();
2386
2387 // item set bonuses applied only at equip and removed at unequip, and still active for broken items
2388 if (pProto && pProto->ItemSet)
2389 RemoveItemsSetItem(this, pProto);
2390
2391 _ApplyItemMods(pItem, slot, false);
2392 }
2393
2394 if (slot < EQUIPMENT_SLOT_END)
2395 {
2396 // remove item dependent auras and casts (only weapon and armor slots)
2398
2399 // update expertise and armor penetration - passive auras may need it
2400 switch (slot)
2401 {
2404 {
2406 break;
2407 }
2408 default:
2409 break;
2410 }
2411
2412 if (slot == EQUIPMENT_SLOT_MAINHAND)
2414 else if (slot == EQUIPMENT_SLOT_OFFHAND)
2416
2417 // equipment visual show
2418 SetVisibleItemSlot(slot, NULL);
2419 }
2420
2421 m_items[slot] = NULL;
2422 }
2423 else if (Bag* pBag = GetBagByPos(bag))
2424 pBag->RemoveItem(slot, update);
2425
2426 // Delete rolled money / loot from db.
2427 // MUST be done before RemoveFromWorld() or GetTemplate() fails
2428 if (ItemTemplate const* pTmp = pItem->GetTemplate())
2429 if (pTmp->Flags & ITEM_PROTO_FLAG_OPENABLE)
2431
2432 if (IsInWorld() && update)
2433 {
2434 pItem->RemoveFromWorld();
2435 pItem->DestroyForPlayer(this);
2436 }
2437
2438 //pItem->SetOwnerGUID(0);
2440 pItem->SetSlot(NULL_SLOT);
2441 pItem->SetState(ITEM_REMOVED, this);
2442 }
2443}
2444
2445void Player::DestroyItemCount(uint32 itemEntry, uint32 count, bool update, bool unequip_check)
2446{
2447 SF_LOG_DEBUG("entities.player.items", "STORAGE: DestroyItemCount item = %u, count = %u", itemEntry, count);
2448 uint32 remcount = 0;
2449
2450 // in inventory
2452 {
2453 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
2454 {
2455 if (item->GetEntry() == itemEntry && !item->IsInTrade())
2456 {
2457 if (item->GetCount() + remcount <= count)
2458 {
2459 // all items in inventory can unequipped
2460 remcount += item->GetCount();
2462
2463 if (remcount >= count)
2464 return;
2465 }
2466 else
2467 {
2468 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
2469 item->SetCount(item->GetCount() - count + remcount);
2470 if (IsInWorld() && update)
2471 item->SendUpdateToPlayer(this);
2472 item->SetState(ITEM_CHANGED, this);
2473 return;
2474 }
2475 }
2476 }
2477 }
2478
2479 // in inventory bags
2481 {
2482 if (Bag* bag = GetBagByPos(i))
2483 {
2484 for (uint32 j = 0; j < bag->GetBagSize(); j++)
2485 {
2486 if (Item* item = bag->GetItemByPos(j))
2487 {
2488 if (item->GetEntry() == itemEntry && !item->IsInTrade())
2489 {
2490 // all items in bags can be unequipped
2491 if (item->GetCount() + remcount <= count)
2492 {
2493 remcount += item->GetCount();
2494 DestroyItem(i, j, update);
2495
2496 if (remcount >= count)
2497 return;
2498 }
2499 else
2500 {
2501 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
2502 item->SetCount(item->GetCount() - count + remcount);
2503 if (IsInWorld() && update)
2504 item->SendUpdateToPlayer(this);
2505 item->SetState(ITEM_CHANGED, this);
2506 return;
2507 }
2508 }
2509 }
2510 }
2511 }
2512 }
2513
2514 // in equipment and bag list
2516 {
2517 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
2518 {
2519 if (item && item->GetEntry() == itemEntry && !item->IsInTrade())
2520 {
2521 if (item->GetCount() + remcount <= count)
2522 {
2523 if (!unequip_check || CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i, false) == EQUIP_ERR_OK)
2524 {
2525 remcount += item->GetCount();
2527
2528 if (remcount >= count)
2529 return;
2530 }
2531 }
2532 else
2533 {
2534 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
2535 item->SetCount(item->GetCount() - count + remcount);
2536 if (IsInWorld() && update)
2537 item->SendUpdateToPlayer(this);
2538 item->SetState(ITEM_CHANGED, this);
2539 return;
2540 }
2541 }
2542 }
2543 }
2544
2545 // in bank
2547 {
2548 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
2549 {
2550 if (item->GetEntry() == itemEntry && !item->IsInTrade())
2551 {
2552 if (item->GetCount() + remcount <= count)
2553 {
2554 remcount += item->GetCount();
2556 if (remcount >= count)
2557 return;
2558 }
2559 else
2560 {
2561 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
2562 item->SetCount(item->GetCount() - count + remcount);
2563 if (IsInWorld() && update)
2564 item->SendUpdateToPlayer(this);
2565 item->SetState(ITEM_CHANGED, this);
2566 return;
2567 }
2568 }
2569 }
2570 }
2571
2572 // in bank bags
2573 for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
2574 {
2575 if (Bag* bag = GetBagByPos(i))
2576 {
2577 for (uint32 j = 0; j < bag->GetBagSize(); j++)
2578 {
2579 if (Item* item = bag->GetItemByPos(j))
2580 {
2581 if (item->GetEntry() == itemEntry && !item->IsInTrade())
2582 {
2583 // all items in bags can be unequipped
2584 if (item->GetCount() + remcount <= count)
2585 {
2586 remcount += item->GetCount();
2587 DestroyItem(i, j, update);
2588
2589 if (remcount >= count)
2590 return;
2591 }
2592 else
2593 {
2594 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
2595 item->SetCount(item->GetCount() - count + remcount);
2596 if (IsInWorld() && update)
2597 item->SendUpdateToPlayer(this);
2598 item->SetState(ITEM_CHANGED, this);
2599 return;
2600 }
2601 }
2602 }
2603 }
2604 }
2605 }
2606}
2607
2608void Player::DestroyZoneLimitedItem(bool update, uint32 new_zone)
2609{
2610 SF_LOG_DEBUG("entities.player.items", "STORAGE: DestroyZoneLimitedItem in map %u and area %u", GetMapId(), new_zone);
2611
2612 // in inventory
2614 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
2615 if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(), new_zone))
2617
2618 // in inventory bags
2620 if (Bag* pBag = GetBagByPos(i))
2621 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
2622 if (Item* pItem = pBag->GetItemByPos(j))
2623 if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(), new_zone))
2624 DestroyItem(i, j, update);
2625
2626 // in equipment and bag list
2628 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
2629 if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(), new_zone))
2631}
2632
2634{
2635 // used when entering arena
2636 // destroys all conjured items
2637 SF_LOG_DEBUG("entities.player.items", "STORAGE: DestroyConjuredItems");
2638
2639 // in inventory
2641 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
2642 if (pItem->IsConjuredConsumable())
2644
2645 // in inventory bags
2647 if (Bag* pBag = GetBagByPos(i))
2648 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
2649 if (Item* pItem = pBag->GetItemByPos(j))
2650 if (pItem->IsConjuredConsumable())
2651 DestroyItem(i, j, update);
2652
2653 // in equipment and bag list
2655 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
2656 if (pItem->IsConjuredConsumable())
2658}
2659
2661{
2662 // in inventory
2664 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
2665 if (pItem->GetEntry() == entry)
2666 return pItem;
2667
2668 for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
2669 if (Bag* pBag = GetBagByPos(i))
2670 for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
2671 if (Item* pItem = pBag->GetItemByPos(j))
2672 if (pItem->GetEntry() == entry)
2673 return pItem;
2674
2675 for (int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; ++i)
2676 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
2677 if (pItem->GetEntry() == entry)
2678 return pItem;
2679
2680 return NULL;
2681}
2682
2683void Player::DestroyItemCount(Item* pItem, uint32& count, bool update)
2684{
2685 if (!pItem)
2686 return;
2687
2688 SF_LOG_DEBUG("entities.player.items", "STORAGE: DestroyItemCount item (GUID: %u, Entry: %u) count = %u", pItem->GetGUIDLow(), pItem->GetEntry(), count);
2689
2690 if (pItem->GetCount() <= count)
2691 {
2692 count -= pItem->GetCount();
2693
2694 DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), update);
2695 }
2696 else
2697 {
2698 ItemRemovedQuestCheck(pItem->GetEntry(), count);
2699 pItem->SetCount(pItem->GetCount() - count);
2700 count = 0;
2701 if (IsInWorld() && update)
2702 pItem->SendUpdateToPlayer(this);
2703 pItem->SetState(ITEM_CHANGED, this);
2704 }
2705}
2706
2708{
2709 uint8 srcbag = src >> 8;
2710 uint8 srcslot = src & 255;
2711
2712 uint8 dstbag = dst >> 8;
2713 uint8 dstslot = dst & 255;
2714
2715 Item* pSrcItem = GetItemByPos(srcbag, srcslot);
2716 if (!pSrcItem)
2717 {
2719 return;
2720 }
2721
2722 if (pSrcItem->m_lootGenerated) // prevent split looting item (item
2723 {
2724 //best error message found for attempting to split while looting
2725 SendEquipError(EQUIP_ERR_SPLIT_FAILED, pSrcItem, NULL);
2726 return;
2727 }
2728
2729 // not let split all items (can be only at cheating)
2730 if (pSrcItem->GetCount() == count)
2731 {
2732 SendEquipError(EQUIP_ERR_SPLIT_FAILED, pSrcItem, NULL);
2733 return;
2734 }
2735
2736 // not let split more existed items (can be only at cheating)
2737 if (pSrcItem->GetCount() < count)
2738 {
2740 return;
2741 }
2742
2744 if (TradeData* tradeData = GetTradeData())
2745 {
2747 if (tradeData->GetTradeSlotForItem(pSrcItem->GetGUID()) != TRADE_SLOT_INVALID)
2748 return;
2749 }
2750
2751 SF_LOG_DEBUG("entities.player.items", "STORAGE: SplitItem bag = %u, slot = %u, item = %u, count = %u", dstbag, dstslot, pSrcItem->GetEntry(), count);
2752 Item* pNewItem = pSrcItem->CloneItem(count, this);
2753 if (!pNewItem)
2754 {
2756 return;
2757 }
2758
2759 if (IsInventoryPos(dst))
2760 {
2761 // change item amount before check (for unique max count check)
2762 pSrcItem->SetCount(pSrcItem->GetCount() - count);
2763
2764 ItemPosCountVec dest;
2765 InventoryResult msg = CanStoreItem(dstbag, dstslot, dest, pNewItem, false);
2766 if (msg != EQUIP_ERR_OK)
2767 {
2768 delete pNewItem;
2769 pSrcItem->SetCount(pSrcItem->GetCount() + count);
2770 SendEquipError(msg, pSrcItem, NULL);
2771 return;
2772 }
2773
2774 if (IsInWorld())
2775 pSrcItem->SendUpdateToPlayer(this);
2776 pSrcItem->SetState(ITEM_CHANGED, this);
2777 StoreItem(dest, pNewItem, true);
2778 }
2779 else if (IsBankPos(dst))
2780 {
2781 // change item amount before check (for unique max count check)
2782 pSrcItem->SetCount(pSrcItem->GetCount() - count);
2783
2784 ItemPosCountVec dest;
2785 InventoryResult msg = CanBankItem(dstbag, dstslot, dest, pNewItem, false);
2786 if (msg != EQUIP_ERR_OK)
2787 {
2788 delete pNewItem;
2789 pSrcItem->SetCount(pSrcItem->GetCount() + count);
2790 SendEquipError(msg, pSrcItem, NULL);
2791 return;
2792 }
2793
2794 if (IsInWorld())
2795 pSrcItem->SendUpdateToPlayer(this);
2796 pSrcItem->SetState(ITEM_CHANGED, this);
2797 BankItem(dest, pNewItem, true);
2798 }
2799 else if (IsEquipmentPos(dst))
2800 {
2801 // change item amount before check (for unique max count check), provide space for splitted items
2802 pSrcItem->SetCount(pSrcItem->GetCount() - count);
2803
2804 uint16 dest;
2805 InventoryResult msg = CanEquipItem(dstslot, dest, pNewItem, false);
2806 if (msg != EQUIP_ERR_OK)
2807 {
2808 delete pNewItem;
2809 pSrcItem->SetCount(pSrcItem->GetCount() + count);
2810 SendEquipError(msg, pSrcItem, NULL);
2811 return;
2812 }
2813
2814 if (IsInWorld())
2815 pSrcItem->SendUpdateToPlayer(this);
2816 pSrcItem->SetState(ITEM_CHANGED, this);
2817 EquipItem(dest, pNewItem, true);
2819 }
2820}
2821
2823{
2824 uint8 srcbag = src >> 8;
2825 uint8 srcslot = src & 255;
2826
2827 uint8 dstbag = dst >> 8;
2828 uint8 dstslot = dst & 255;
2829
2830 Item* pSrcItem = GetItemByPos(srcbag, srcslot);
2831 Item* pDstItem = GetItemByPos(dstbag, dstslot);
2832
2833 if (!pSrcItem)
2834 return;
2835
2836 SF_LOG_DEBUG("entities.player.items", "STORAGE: SwapItem bag = %u, slot = %u, item = %u", dstbag, dstslot, pSrcItem->GetEntry());
2837
2838 if (!IsAlive())
2839 {
2840 SendEquipError(EQUIP_ERR_PLAYER_DEAD, pSrcItem, pDstItem);
2841 return;
2842 }
2843
2844 // SRC checks
2845
2846 if (pSrcItem->m_lootGenerated) // prevent swap looting item
2847 {
2848 //best error message found for attempting to swap while looting
2850 return;
2851 }
2852
2853 // check unequip potability for equipped items and bank bags
2854 if (IsEquipmentPos(src) || IsBagPos(src))
2855 {
2856 // bags can be swapped with empty bag slots, or with empty bag (items move possibility checked later)
2857 InventoryResult msg = CanUnequipItem(src, !IsBagPos(src) || IsBagPos(dst) || (pDstItem && pDstItem->ToBag() && pDstItem->ToBag()->IsEmpty()));
2858 if (msg != EQUIP_ERR_OK)
2859 {
2860 SendEquipError(msg, pSrcItem, pDstItem);
2861 return;
2862 }
2863 }
2864
2865 // prevent put equipped/bank bag in self
2866 if (IsBagPos(src) && srcslot == dstbag)
2867 {
2868 SendEquipError(EQUIP_ERR_BAG_IN_BAG, pSrcItem, pDstItem);
2869 return;
2870 }
2871
2872 // prevent equipping bag in the same slot from its inside
2873 if (IsBagPos(dst) && srcbag == dstslot)
2874 {
2875 SendEquipError(EQUIP_ERR_CANT_SWAP, pSrcItem, pDstItem);
2876 return;
2877 }
2878
2879 // DST checks
2880
2881 if (pDstItem)
2882 {
2883 if (pDstItem->m_lootGenerated) // prevent swap looting item
2884 {
2885 //best error message found for attempting to swap while looting
2887 return;
2888 }
2889
2890 // check unequip potability for equipped items and bank bags
2891 if (IsEquipmentPos(dst) || IsBagPos(dst))
2892 {
2893 // bags can be swapped with empty bag slots, or with empty bag (items move possibility checked later)
2894 InventoryResult msg = CanUnequipItem(dst, !IsBagPos(dst) || IsBagPos(src) || (pSrcItem->ToBag() && pSrcItem->ToBag()->IsEmpty()));
2895 if (msg != EQUIP_ERR_OK)
2896 {
2897 SendEquipError(msg, pSrcItem, pDstItem);
2898 return;
2899 }
2900 }
2901 }
2902
2903 // NOW this is or item move (swap with empty), or swap with another item (including bags in bag possitions)
2904 // or swap empty bag with another empty or not empty bag (with items exchange)
2905
2906 // Move case
2907 if (!pDstItem)
2908 {
2909 if (IsInventoryPos(dst))
2910 {
2911 ItemPosCountVec dest;
2912 InventoryResult msg = CanStoreItem(dstbag, dstslot, dest, pSrcItem, false);
2913 if (msg != EQUIP_ERR_OK)
2914 {
2915 SendEquipError(msg, pSrcItem, NULL);
2916 return;
2917 }
2918
2919 RemoveItem(srcbag, srcslot, true);
2920 StoreItem(dest, pSrcItem, true);
2921 if (IsBankPos(src))
2922 ItemAddedQuestCheck(pSrcItem->GetEntry(), pSrcItem->GetCount());
2923 }
2924 else if (IsBankPos(dst))
2925 {
2926 ItemPosCountVec dest;
2927 InventoryResult msg = CanBankItem(dstbag, dstslot, dest, pSrcItem, false);
2928 if (msg != EQUIP_ERR_OK)
2929 {
2930 SendEquipError(msg, pSrcItem, NULL);
2931 return;
2932 }
2933
2934 RemoveItem(srcbag, srcslot, true);
2935 BankItem(dest, pSrcItem, true);
2936 ItemRemovedQuestCheck(pSrcItem->GetEntry(), pSrcItem->GetCount());
2937 }
2938 else if (IsEquipmentPos(dst))
2939 {
2940 uint16 dest;
2941 InventoryResult msg = CanEquipItem(dstslot, dest, pSrcItem, false);
2942 if (msg != EQUIP_ERR_OK)
2943 {
2944 SendEquipError(msg, pSrcItem, NULL);
2945 return;
2946 }
2947
2948 RemoveItem(srcbag, srcslot, true);
2949 EquipItem(dest, pSrcItem, true);
2951 }
2952
2953 return;
2954 }
2955
2956 // attempt merge to / fill target item
2957 if (!pSrcItem->IsBag() && !pDstItem->IsBag())
2958 {
2959 InventoryResult msg;
2960 ItemPosCountVec sDest;
2961 uint16 eDest = 0;
2962 if (IsInventoryPos(dst))
2963 msg = CanStoreItem(dstbag, dstslot, sDest, pSrcItem, false);
2964 else if (IsBankPos(dst))
2965 msg = CanBankItem(dstbag, dstslot, sDest, pSrcItem, false);
2966 else if (IsEquipmentPos(dst))
2967 msg = CanEquipItem(dstslot, eDest, pSrcItem, false);
2968 else
2969 return;
2970
2971 // can be merge/fill
2972 if (msg == EQUIP_ERR_OK)
2973 {
2974 if (pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetTemplate()->GetMaxStackSize())
2975 {
2976 RemoveItem(srcbag, srcslot, true);
2977
2978 if (IsInventoryPos(dst))
2979 StoreItem(sDest, pSrcItem, true);
2980 else if (IsBankPos(dst))
2981 BankItem(sDest, pSrcItem, true);
2982 else if (IsEquipmentPos(dst))
2983 {
2984 EquipItem(eDest, pSrcItem, true);
2986 }
2987 }
2988 else
2989 {
2990 pSrcItem->SetCount(pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetTemplate()->GetMaxStackSize());
2991 pDstItem->SetCount(pSrcItem->GetTemplate()->GetMaxStackSize());
2992 pSrcItem->SetState(ITEM_CHANGED, this);
2993 pDstItem->SetState(ITEM_CHANGED, this);
2994 if (IsInWorld())
2995 {
2996 pSrcItem->SendUpdateToPlayer(this);
2997 pDstItem->SendUpdateToPlayer(this);
2998 }
2999 }
3000 SendRefundInfo(pDstItem);
3001 return;
3002 }
3003 }
3004
3005 // impossible merge/fill, do real swap
3007
3008 // check src->dest move possibility
3009 ItemPosCountVec sDest;
3010 uint16 eDest = 0;
3011 if (IsInventoryPos(dst))
3012 msg = CanStoreItem(dstbag, dstslot, sDest, pSrcItem, true);
3013 else if (IsBankPos(dst))
3014 msg = CanBankItem(dstbag, dstslot, sDest, pSrcItem, true);
3015 else if (IsEquipmentPos(dst))
3016 {
3017 msg = CanEquipItem(dstslot, eDest, pSrcItem, true);
3018 if (msg == EQUIP_ERR_OK)
3019 msg = CanUnequipItem(eDest, true);
3020 }
3021
3022 if (msg != EQUIP_ERR_OK)
3023 {
3024 SendEquipError(msg, pSrcItem, pDstItem);
3025 return;
3026 }
3027
3028 // check dest->src move possibility
3029 ItemPosCountVec sDest2;
3030 uint16 eDest2 = 0;
3031 if (IsInventoryPos(src))
3032 msg = CanStoreItem(srcbag, srcslot, sDest2, pDstItem, true);
3033 else if (IsBankPos(src))
3034 msg = CanBankItem(srcbag, srcslot, sDest2, pDstItem, true);
3035 else if (IsEquipmentPos(src))
3036 {
3037 msg = CanEquipItem(srcslot, eDest2, pDstItem, true);
3038 if (msg == EQUIP_ERR_OK)
3039 msg = CanUnequipItem(eDest2, true);
3040 }
3041
3042 if (msg != EQUIP_ERR_OK)
3043 {
3044 SendEquipError(msg, pDstItem, pSrcItem);
3045 return;
3046 }
3047
3048 // Check bag swap with item exchange (one from empty in not bag possition (equipped (not possible in fact) or store)
3049 if (Bag* srcBag = pSrcItem->ToBag())
3050 {
3051 if (Bag* dstBag = pDstItem->ToBag())
3052 {
3053 Bag* emptyBag = NULL;
3054 Bag* fullBag = NULL;
3055 if (srcBag->IsEmpty() && !IsBagPos(src))
3056 {
3057 emptyBag = srcBag;
3058 fullBag = dstBag;
3059 }
3060 else if (dstBag->IsEmpty() && !IsBagPos(dst))
3061 {
3062 emptyBag = dstBag;
3063 fullBag = srcBag;
3064 }
3065
3066 // bag swap (with items exchange) case
3067 if (emptyBag && fullBag)
3068 {
3069 ItemTemplate const* emptyProto = emptyBag->GetTemplate();
3070
3071 uint32 count = 0;
3072
3073 for (uint32 i = 0; i < fullBag->GetBagSize(); ++i)
3074 {
3075 Item* bagItem = fullBag->GetItemByPos(i);
3076 if (!bagItem)
3077 continue;
3078
3079 ItemTemplate const* bagItemProto = bagItem->GetTemplate();
3080 if (!bagItemProto || !ItemCanGoIntoBag(bagItemProto, emptyProto))
3081 {
3082 // one from items not go to empty target bag
3083 SendEquipError(EQUIP_ERR_BAG_IN_BAG, pSrcItem, pDstItem);
3084 return;
3085 }
3086
3087 ++count;
3088 }
3089
3090 if (count > emptyBag->GetBagSize())
3091 {
3092 // too small targeted bag
3093 SendEquipError(EQUIP_ERR_CANT_SWAP, pSrcItem, pDstItem);
3094 return;
3095 }
3096
3097 // Items swap
3098 count = 0; // will pos in new bag
3099 for (uint32 i = 0; i < fullBag->GetBagSize(); ++i)
3100 {
3101 Item* bagItem = fullBag->GetItemByPos(i);
3102 if (!bagItem)
3103 continue;
3104
3105 fullBag->RemoveItem(i, true);
3106 emptyBag->StoreItem(count, bagItem, true);
3107 bagItem->SetState(ITEM_CHANGED, this);
3108
3109 ++count;
3110 }
3111 }
3112 }
3113 }
3114
3115 // now do moves, remove...
3116 RemoveItem(dstbag, dstslot, false);
3117 RemoveItem(srcbag, srcslot, false);
3118
3119 // add to dest
3120 if (IsInventoryPos(dst))
3121 StoreItem(sDest, pSrcItem, true);
3122 else if (IsBankPos(dst))
3123 BankItem(sDest, pSrcItem, true);
3124 else if (IsEquipmentPos(dst))
3125 EquipItem(eDest, pSrcItem, true);
3126
3127 // add to src
3128 if (IsInventoryPos(src))
3129 StoreItem(sDest2, pDstItem, true);
3130 else if (IsBankPos(src))
3131 BankItem(sDest2, pDstItem, true);
3132 else if (IsEquipmentPos(src))
3133 EquipItem(eDest2, pDstItem, true);
3134
3135 // if player is moving bags and is looting an item inside this bag
3136 // release the loot
3137 if (GetLootGUID())
3138 {
3139 bool released = false;
3140 if (IsBagPos(src))
3141 {
3142 Bag* bag = pSrcItem->ToBag();
3143 for (uint32 i = 0; i < bag->GetBagSize(); ++i)
3144 {
3145 if (Item* bagItem = bag->GetItemByPos(i))
3146 {
3147 if (bagItem->m_lootGenerated)
3148 {
3149 m_session->DoLootRelease(GetLootGUID());
3150 released = true; // so we don't need to look at dstBag
3151 break;
3152 }
3153 }
3154 }
3155 }
3156
3157 if (!released && IsBagPos(dst) && pDstItem)
3158 {
3159 Bag* bag = pDstItem->ToBag();
3160 for (uint32 i = 0; i < bag->GetBagSize(); ++i)
3161 {
3162 if (Item* bagItem = bag->GetItemByPos(i))
3163 {
3164 if (bagItem->m_lootGenerated)
3165 {
3166 m_session->DoLootRelease(GetLootGUID());
3167 released = true; // not realy needed here
3168 break;
3169 }
3170 }
3171 }
3172 }
3173 }
3174
3176}
3177
3179{
3180 if (pItem)
3181 {
3183 // if current back slot non-empty search oldest or free
3184 if (m_items[slot])
3185 {
3187 uint32 oldest_slot = BUYBACK_SLOT_START;
3188
3189 for (uint32 i = BUYBACK_SLOT_START + 1; i < BUYBACK_SLOT_END; ++i)
3190 {
3191 // found empty
3192 if (!m_items[i])
3193 {
3194 slot = i;
3195 break;
3196 }
3197
3199
3200 if (oldest_time > i_time)
3201 {
3202 oldest_time = i_time;
3203 oldest_slot = i;
3204 }
3205 }
3206
3207 // find oldest
3208 slot = oldest_slot;
3209 }
3210
3211 RemoveItemFromBuyBackSlot(slot, true);
3212 SF_LOG_DEBUG("entities.player.items", "STORAGE: AddItemToBuyBackSlot item = %u, slot = %u", pItem->GetEntry(), slot);
3213
3214 m_items[slot] = pItem;
3215 time_t base = time(NULL);
3216 uint32 etime = uint32(base - m_logintime + (30 * 3600));
3217 uint32 eslot = slot - BUYBACK_SLOT_START;
3218
3220 if (ItemTemplate const* proto = pItem->GetTemplate())
3221 SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE + eslot, proto->SellPrice * pItem->GetCount());
3222 else
3225
3226 // move to next (for non filled list is move most optimized choice)
3229 }
3230}
3231
3233{
3234 SF_LOG_DEBUG("entities.player.items", "STORAGE: GetItemFromBuyBackSlot slot = %u", slot);
3235 if (slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END)
3236 return m_items[slot];
3237 return NULL;
3238}
3239
3241{
3242 SF_LOG_DEBUG("entities.player.items", "STORAGE: RemoveItemFromBuyBackSlot slot = %u", slot);
3243 if (slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END)
3244 {
3245 Item* pItem = m_items[slot];
3246 if (pItem)
3247 {
3248 pItem->RemoveFromWorld();
3249 if (del)
3250 pItem->SetState(ITEM_REMOVED, this);
3251 }
3252
3253 m_items[slot] = NULL;
3254
3255 uint32 eslot = slot - BUYBACK_SLOT_START;
3259
3260 // if current backslot is filled set to now free slot
3262 m_currentBuybackSlot = slot;
3263 }
3264}
3265
3266void Player::SendEquipError(InventoryResult msg, Item* pItem, Item* pItem2, uint32 itemid)
3267{
3268 SF_LOG_DEBUG("network", "WORLD: Sent SMSG_INVENTORY_CHANGE_FAILURE (%u)", msg);
3269
3270 ObjectGuid pItemGuid = pItem ? pItem->GetGUID() : 0;
3271 ObjectGuid pItemGuid2 = pItem2 ? pItem2->GetGUID() : 0;
3272
3274
3275 if (msg != EQUIP_ERR_OK)
3276 {
3277 data.WriteGuidMask(pItemGuid2, 4);
3278 data.WriteGuidMask(pItemGuid, 3);
3279 data.WriteGuidMask(pItemGuid2, 6, 2);
3280 data.WriteGuidMask(pItemGuid, 4);
3281 data.WriteGuidMask(pItemGuid2, 5);
3282 data.WriteGuidMask(pItemGuid, 1, 6);
3283 data.WriteGuidMask(pItemGuid2, 0, 3, 1);
3284 data.WriteGuidMask(pItemGuid, 2, 0, 5, 7);
3285 data.WriteGuidMask(pItemGuid2, 7);
3286
3287 data.WriteGuidBytes(pItemGuid2, 0);
3288 data << uint8(0); // bag type subclass, used with EQUIP_ERR_EVENT_AUTOEQUIP_BIND_CONFIRM and EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG2
3289 data.WriteGuidBytes(pItemGuid2, 6);
3290 data.WriteGuidBytes(pItemGuid, 4, 0, 7, 3);
3291 data.WriteGuidBytes(pItemGuid2, 1, 5);
3292 data.WriteGuidBytes(pItemGuid, 5);
3293 data.WriteGuidBytes(pItemGuid2, 7, 2);
3294 data.WriteGuidBytes(pItemGuid, 1, 6, 2);
3295 data.WriteGuidBytes(pItemGuid2, 3, 4);
3296 data << uint8(msg);
3297
3301 {
3302 ItemTemplate const* proto = pItem ? pItem->GetTemplate() : sObjectMgr->GetItemTemplate(itemid);
3303 data << uint32(proto ? proto->ItemLimitCategory : 0);
3304 }
3305
3306 if (msg == EQUIP_ERR_NO_OUTPUT) // no idea about this one...
3307 data << uint32(0); // slot
3308
3310 {
3311 ItemTemplate const* proto = pItem ? pItem->GetTemplate() : sObjectMgr->GetItemTemplate(itemid);
3312 data << uint32(proto ? proto->RequiredLevel : 0);
3313 }
3314
3315 if (msg == EQUIP_ERR_NO_OUTPUT)
3316 {
3317 data.WriteBits(0, 8); // container
3318 data.WriteBits(0, 8); // item guid
3319 }
3320 }
3321
3322 GetSession()->SendPacket(&data);
3323}
3324
3326{
3327 SF_LOG_DEBUG("network", "WORLD: Sent SMSG_DISPLAY_GAME_ERROR (%u)", uint32(error));
3328
3330 data << uint32(error);
3331 data.WriteBit(arg1 != 0);
3332 data.WriteBit(arg2 != 0);
3333
3334 if (arg1)
3335 data << uint32(arg1);
3336
3337 if (arg2)
3338 data << uint32(arg2);
3339
3340 GetSession()->SendPacket(&data);
3341}
3342
3343bool Player::IsUseEquipedWeapon(bool mainhand) const
3344{
3345 // disarm applied only to mainhand weapon
3346 return !IsInFeralForm() && (!mainhand || !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED));
3347}
3348
3350{
3352 return mainItem && mainItem->GetTemplate()->InventoryType == INVTYPE_2HWEAPON && !CanTitanGrip();
3353}
3354
3356{
3357 ItemTemplate const* pProto = pItem->GetTemplate();
3358
3359 // proto based limitations
3360 if (InventoryResult res = CanEquipUniqueItem(pProto, eslot, limit_count))
3361 return res;
3362
3363 // check unique-equipped on gems
3364 for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + 3; ++enchant_slot)
3365 {
3366 uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot));
3367 if (!enchant_id)
3368 continue;
3369 SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3370 if (!enchantEntry)
3371 continue;
3372
3373 ItemTemplate const* pGem = sObjectMgr->GetItemTemplate(enchantEntry->GemID);
3374 if (!pGem)
3375 continue;
3376
3377 // include for check equip another gems with same limit category for not equipped item (and then not counted)
3378 uint32 gem_limit_count = !pItem->IsEquipped() && pGem->ItemLimitCategory
3380
3381 if (InventoryResult res = CanEquipUniqueItem(pGem, eslot, gem_limit_count))
3382 return res;
3383 }
3384
3385 return EQUIP_ERR_OK;
3386}
3387
3388InventoryResult Player::CanEquipUniqueItem(ItemTemplate const* itemProto, uint8 except_slot, uint32 limit_count) const
3389{
3390 // check unique-equipped on item
3391 if (itemProto->Flags & ITEM_PROTO_FLAG_UNIQUE_EQUIPPED)
3392 {
3393 // there is an equip limit on this item
3394 if (HasItemOrGemWithIdEquipped(itemProto->ItemId, 1, except_slot))
3396 }
3397
3398 // check unique-equipped limit
3399 if (itemProto->ItemLimitCategory)
3400 {
3401 ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(itemProto->ItemLimitCategory);
3402 if (!limitEntry)
3404
3405 // NOTE: limitEntry->mode not checked because if item have have-limit then it applied and to equip case
3406
3407 if (limit_count > limitEntry->maxCount)
3409
3410 // there is an equip limit on this item
3411 if (HasItemOrGemWithLimitCategoryEquipped(itemProto->ItemLimitCategory, limitEntry->maxCount - limit_count + 1, except_slot))
3413 }
3414
3415 return EQUIP_ERR_OK;
3416}
#define MAX_BAG_SIZE
Definition Bag.h:10
@ STATUS_IN_PROGRESS
@ CHAR_DEL_GIFT
@ CHAR_INS_ITEM_BOP_TRADE
@ DEFAULT_MAX_LEVEL
Definition DBCEnums.h:16
@ ITEM_LIMIT_CATEGORY_MODE_HAVE
Definition DBCEnums.h:432
@ ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM
Definition DBCEnums.h:222
@ ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM
Definition DBCEnums.h:201
@ ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM
Definition DBCEnums.h:214
@ ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM
Definition DBCEnums.h:252
DBCStorage< SpellItemEnchantmentEntry > sSpellItemEnchantmentStore(SpellItemEnchantmentfmt)
DBCStorage< ScalingStatDistributionEntry > sScalingStatDistributionStore(ScalingStatDistributionfmt)
DBCStorage< ItemLimitCategoryEntry > sItemLimitCategoryStore(ItemLimitCategoryEntryfmt)
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::uint64_t uint64
Definition Define.h:76
std::uint16_t uint16
Definition Define.h:78
bool IsHolidayActive(HolidayIds id)
bool ItemCanGoIntoBag(ItemTemplate const *pProto, ItemTemplate const *pBagProto)
Definition Item.cpp:160
EnchantmentSlot
Definition Item.h:149
@ PERM_ENCHANTMENT_SLOT
Definition Item.h:150
@ PROP_ENCHANTMENT_SLOT_0
Definition Item.h:160
@ TEMP_ENCHANTMENT_SLOT
Definition Item.h:151
@ PRISMATIC_ENCHANTMENT_SLOT
Definition Item.h:156
@ PROP_ENCHANTMENT_SLOT_1
Definition Item.h:161
@ SOCK_ENCHANTMENT_SLOT
Definition Item.h:152
@ PROP_ENCHANTMENT_SLOT_4
Definition Item.h:164
@ PROP_ENCHANTMENT_SLOT_3
Definition Item.h:163
InventoryResult
Definition Item.h:27
@ EQUIP_ERR_CANT_EQUIP_EVER
Definition Item.h:38
@ EQUIP_ERR_NO_SLOT_AVAILABLE
Definition Item.h:37
@ EQUIP_ERR_ONLY_ONE_QUIVER
Definition Item.h:61
@ EQUIP_ERR_ITEM_MAX_COUNT_EQUIPPED_SOCKETED
Definition Item.h:103
@ EQUIP_ERR_DESTROY_NONEMPTY_BAG
Definition Item.h:59
@ EQUIP_ERR_SPLIT_FAILED
Definition Item.h:55
@ EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE
Definition Item.h:95
@ EQUIP_ERR_NOT_DURING_ARENA_MATCH
Definition Item.h:106
@ EQUIP_ERR_NO_OUTPUT
Definition Item.h:109
@ EQUIP_ERR_PLAYER_DEAD
Definition Item.h:66
@ EQUIP_ERR_BAG_IN_BAG
Definition Item.h:33
@ EQUIP_ERR_CLIENT_LOCKED_OUT
Definition Item.h:67
@ EQUIP_ERR_BANK_FULL
Definition Item.h:79
@ EQUIP_ERR_NOT_IN_COMBAT
Definition Item.h:88
@ EQUIP_ERR_CANT_EQUIP_LEVEL_I
Definition Item.h:29
@ EQUIP_ERR_GENERIC_STUNNED
Definition Item.h:65
@ EQUIP_ERR_WRONG_SLOT
Definition Item.h:31
@ EQUIP_ERR_WRONG_BAG_TYPE
Definition Item.h:43
@ EQUIP_ERR_PROFICIENCY_NEEDED
Definition Item.h:36
@ EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED_IS
Definition Item.h:111
@ EQUIP_ERR_NO_BANK_SLOT
Definition Item.h:62
@ EQUIP_ERR_PURCHASE_LEVEL_TOO_LOW
Definition Item.h:114
@ EQUIP_ERR_ITEM_NOT_FOUND
Definition Item.h:51
@ EQUIP_ERR_CANT_EQUIP_REPUTATION
Definition Item.h:92
@ EQUIP_ERR_OK
Definition Item.h:28
@ EQUIP_ERR_LOOT_GONE
Definition Item.h:77
@ EQUIP_ERR_CANT_SWAP
Definition Item.h:49
@ EQUIP_ERR_NOT_OWNER
Definition Item.h:60
@ EQUIP_ERR_CANT_EQUIP_SKILL
Definition Item.h:30
@ EQUIP_ERR_2HANDED_EQUIPPED
Definition Item.h:41
@ EQUIP_ERR_INV_FULL
Definition Item.h:78
@ EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED_IS
Definition Item.h:116
@ EQUIP_ERR_NOT_EQUIPPABLE
Definition Item.h:48
@ EQUIP_ERR_2HSKILLNOTFOUND
Definition Item.h:42
@ EQUIP_ERR_ONLY_ONE_AMMO
Definition Item.h:70
@ EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED_IS
Definition Item.h:112
@ EQUIP_ERR_ITEM_MAX_COUNT
Definition Item.h:45
@ EQUIP_ERR_TOO_FEW_TO_SPLIT
Definition Item.h:54
@ ITEM_CHANGED
Definition Item.h:192
@ ITEM_REMOVED
Definition Item.h:194
@ ITEM_NEW
Definition Item.h:193
@ ITEM_SUBCLASS_WEAPON_POLEARM
@ INVTYPE_CLOAK
@ INVTYPE_RELIC
@ INVTYPE_WEAPON
@ INVTYPE_WEAPONOFFHAND
@ INVTYPE_2HWEAPON
@ ITEM_SPELLTRIGGER_ON_NO_DELAY_USE
@ ITEM_SUBCLASS_CONTAINER
@ ITEM_SUBCLASS_AMMO_POUCH
@ ITEM_PROTO_FLAG_UNIQUE_EQUIPPED
@ ITEM_PROTO_FLAG_OPENABLE
@ ITEM_SUBCLASS_ARMOR_MAIL
@ ITEM_SUBCLASS_ARMOR_BUCKLER
@ ITEM_SUBCLASS_ARMOR_CLOTH
@ ITEM_SUBCLASS_ARMOR_LEATHER
@ ITEM_SUBCLASS_ARMOR_PLATE
@ ITEM_SUBCLASS_ARMOR_MISCELLANEOUS
@ ITEM_SUBCLASS_LEATHER
@ ITEM_FLAGS_EXTRA_ALLIANCE_ONLY
@ ITEM_FLAGS_EXTRA_HORDE_ONLY
#define MAX_ITEM_PROTO_SPELLS
@ BIND_WHEN_EQUIPED
@ BIND_QUEST_ITEM
@ BIND_WHEN_PICKED_UP
@ ITEM_CLASS_QUIVER
@ ITEM_CLASS_CONTAINER
@ ITEM_CLASS_ARMOR
@ ITEM_CLASS_WEAPON
@ ITEM_FLAG_BOP_TRADEABLE
@ ITEM_FLAG_WRAPPED
#define MAX_ITEM_SUBCLASS_WEAPON
#define sLFGMgr
Definition LFGMgr.h:518
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
std::set< uint32 > AllowedLooterSet
Definition LootMgr.h:116
#define sObjectMgr
Definition ObjectMgr.h:1617
void AddItemsSetItem(Player *player, Item *item)
Definition Item.cpp:20
std::vector< ItemPosCount > ItemPosCountVec
Definition Player.h:777
@ INVENTORY_SLOT_ITEM_START
Definition Player.h:719
@ INVENTORY_SLOT_ITEM_END
Definition Player.h:720
void RemoveItemsSetItem(Player *player, ItemTemplate const *proto)
Definition Item.cpp:102
@ BUYBACK_SLOT_END
Definition Player.h:739
@ BUYBACK_SLOT_START
Definition Player.h:738
@ INVENTORY_SLOT_BAG_START
Definition Player.h:713
@ INVENTORY_SLOT_BAG_END
Definition Player.h:714
@ BANK_SLOT_BAG_END
Definition Player.h:732
@ BANK_SLOT_BAG_START
Definition Player.h:731
@ BANK_SLOT_ITEM_START
Definition Player.h:725
@ BANK_SLOT_ITEM_END
Definition Player.h:726
@ EQUIPMENT_SLOT_FINGER1
Definition Player.h:699
@ EQUIPMENT_SLOT_FINGER2
Definition Player.h:700
@ EQUIPMENT_SLOT_MAINHAND
Definition Player.h:704
@ EQUIPMENT_SLOT_TRINKET1
Definition Player.h:701
@ EQUIPMENT_SLOT_END
Definition Player.h:708
@ EQUIPMENT_SLOT_OFFHAND
Definition Player.h:705
@ EQUIPMENT_SLOT_TRINKET2
Definition Player.h:702
@ EQUIPMENT_SLOT_START
Definition Player.h:688
#define INVENTORY_SLOT_BAG_0
Definition Player.h:684
@ TRADE_SLOT_INVALID
Definition Player.h:784
@ PLAYER_SLOT_END
Definition Player.h:680
GameError
@ ITEM_QUALITY_HEIRLOOM
@ CLASS_HUNTER
@ CLASS_DRUID
@ CLASS_SHAMAN
@ CLASS_MONK
@ CLASS_PRIEST
@ CLASS_WARRIOR
@ CLASS_WARLOCK
@ CLASS_MAGE
@ CLASS_DEATH_KNIGHT
@ CLASS_PALADIN
@ CLASS_ROGUE
@ ALLIANCE
@ HORDE
HolidayIds
@ SKILL_BOWS
@ SKILL_MACES
@ SKILL_PLATE_MAIL
@ SKILL_WANDS
@ SKILL_GUNS
@ SKILL_CROSSBOWS
@ SKILL_FISHING
@ SKILL_SWORDS
@ SKILL_DAGGERS
@ SKILL_2H_AXES
@ SKILL_POLEARMS
@ SKILL_2H_SWORDS
@ SKILL_MAIL
@ SKILL_FIST_WEAPONS
@ SKILL_2H_MACES
@ SKILL_AXES
@ SKILL_STAVES
#define sSpellMgr
Definition SpellMgr.h:744
WeaponAttackType
Definition Unit.h:572
@ CR_ARMOR_PENETRATION
Definition Unit.h:605
@ NULL_BAG
Definition Unit.h:336
@ NULL_SLOT
Definition Unit.h:337
@ UNIT_STATE_STUNNED
Definition Unit.h:515
@ UNIT_FLAG_DISARMED
Definition Unit.h:646
@ UNIT_FIELD_FLAGS
@ ITEM_FIELD_CONTAINED_IN
@ ITEM_FIELD_OWNER
@ ITEM_FIELD_DYNAMIC_FLAGS
@ ITEM_FIELD_CREATE_PLAYED_TIME
@ PLAYER_FIELD_VENDORBUYBACK_SLOTS
@ PLAYER_FIELD_BUYBACK_TIMESTAMP
@ PLAYER_FIELD_BUYBACK_PRICE
@ PLAYER_FIELD_VISIBLE_ITEMS
@ PLAYER_FIELD_INV_SLOTS
Definition Bag.h:16
uint32 GetBagSize() const
Definition Bag.h:36
void StoreItem(uint8 slot, Item *pItem, bool update)
Definition Bag.cpp:144
bool IsEmpty() const
Definition Bag.cpp:169
Item * GetItemByPos(uint8 slot) const
Definition Bag.cpp:225
void RemoveItem(uint8 slot, bool update)
Definition Bag.cpp:133
void WriteGuidBytes(const ObjectGuid &guid, Offsets... offsets)
Definition ByteBuffer.h:264
bool WriteBit(uint32 bit)
Definition ByteBuffer.h:164
void WriteGuidMask(const ObjectGuid &guid, Offsets... offsets)
Definition ByteBuffer.h:248
size_t bitwpos() const
Returns position of last written bit.
Definition ByteBuffer.h:492
void WriteBits(T value, size_t bits)
Definition ByteBuffer.h:192
void WriteByteSeq(uint8 b)
Definition ByteBuffer.h:227
void AddGlobalCooldown(SpellInfo const *spellInfo, uint32 gcd)
Definition Unit.cpp:254
Definition Item.h:202
uint8 GetSlot() const
Definition Item.h:265
bool IsCurrencyToken() const
Definition Item.h:245
void SetNotRefundable(Player *owner, bool changestate=true, SQLTransaction *trans=NULL)
Definition Item.cpp:1111
void SetBinding(bool val)
Definition Item.h:217
void SetState(ItemUpdateState state, Player *forplayer=NULL)
Definition Item.cpp:667
uint32 GetEnchantmentId(EnchantmentSlot slot) const
Definition Item.h:287
void SetOwnerGUID(uint64 guid)
Definition Item.h:214
void SetSoulboundTradeable(AllowedLooterSet const &allowedLooters)
Definition Item.cpp:1169
void SetItemRandomProperties(int32 randomPropId)
Definition Item.cpp:621
uint8 GetGemCountWithID(uint32 GemID) const
Definition Item.cpp:944
Bag * ToBag()
Definition Item.h:240
Item * CloneItem(uint32 count, Player const *player=NULL) const
Definition Item.cpp:1039
void ItemContainerDeleteLootMoneyAndLootItemsFromDB()
Definition Item.cpp:1673
void SetCount(uint32 value)
Definition Item.h:259
ItemTemplate const * GetTemplate() const
Definition Item.cpp:528
uint32 GetVisibleEntry() const
Definition Item.h:353
bool IsSoulBound() const
Definition Item.h:218
bool IsBroken() const
Definition Item.h:247
uint32 GetItemSuffixFactor() const
Definition Item.h:279
bool IsBindedNotWith(Player const *player) const
Definition Item.cpp:1055
bool IsEquipped() const
Definition Item.cpp:739
uint32 GetSkill()
Definition Item.cpp:538
static Item * CreateItem(uint32 itemEntry, uint32 count, Player const *player=NULL)
Definition Item.cpp:1012
bool IsInTrade() const
Definition Item.h:250
bool IsBag() const
Definition Item.h:244
void ClearEnchantment(EnchantmentSlot slot)
Definition Item.cpp:897
InventoryResult CanBeMergedPartlyWith(ItemTemplate const *proto) const
Definition Item.cpp:803
uint64 GetOwnerGUID() const
Definition Item.h:213
uint8 GetGemCountWithLimitCategory(uint32 limitCategory) const
Definition Item.cpp:963
void ClearSoulboundTradeable(Player *currentOwner)
Definition Item.cpp:1175
void SetSlot(uint8 slot)
Definition Item.h:268
bool IsNotEmptyBag() const
Definition Item.cpp:280
bool m_lootGenerated
Definition Item.h:302
uint32 GetCount() const
Definition Item.h:258
void SetContainer(Bag *container)
Definition Item.h:270
uint8 GetBagSlot() const
Definition Item.cpp:734
static int32 GenerateItemRandomPropertyId(uint32 item_id)
Definition Item.cpp:575
Definition Map.h:238
DifficultyID GetDifficulty() const
Definition Map.h:363
uint32 GetId(void) const
Definition Map.h:300
uint64 GetGUID() const
Definition Object.h:119
void SetUInt16Value(uint16 index, uint8 offset, uint16 value)
Definition Object.cpp:1182
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:325
bool IsInWorld() const
Definition Object.h:114
virtual void DestroyForPlayer(Player *target, bool onDeath=false) const
Definition Object.cpp:287
uint32 GetGUIDLow() const
Definition Object.h:120
uint32 GetEntry() const
Definition Object.h:125
virtual void AddToWorld()
Definition Object.cpp:148
bool HasFlag(uint16 index, uint32 flag) const
Definition Object.cpp:1309
virtual void RemoveFromWorld()
Definition Object.cpp:161
void SendUpdateToPlayer(Player *player)
Definition Object.cpp:259
void SetUInt32Value(uint16 index, uint32 value)
Definition Object.cpp:1038
void SetUInt64Value(uint16 index, uint64 value)
Definition Object.cpp:1079
bool StoreNewItemInBestSlots(uint32 item_id, uint32 item_count)
void SendEquipError(InventoryResult msg, Item *pItem, Item *pItem2=NULL, uint32 itemid=0)
void ItemRemovedQuestCheck(uint32 entry, uint32 count)
static bool IsEquipmentPos(uint16 pos)
Definition Player.h:1536
uint32 GetTeam() const
Definition Player.h:2527
InventoryResult CanUnequipItem(uint16 src, bool swap) const
void RemoveItemDependentAurasAndCasts(Item *pItem)
Definition Player.cpp:19622
InventoryResult CanEquipItem(uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading=true) const
InventoryResult CanEquipNewItem(uint8 slot, uint16 &dest, uint32 item, bool swap) const
Bag * GetBagByPos(uint8 slot) const
void QuickEquipItem(uint16 pos, Item *pItem)
uint32 GetTotalPlayedTime() const
Definition Player.h:1424
InventoryResult CanRollForItemInLFG(ItemTemplate const *item, WorldObject const *lootedObject) const
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:6563
Item * BankItem(ItemPosCountVec const &dest, Item *pItem, bool update)
void SendGameError(GameError error, uint32 arg1=0, uint32 arg2=0)
void SplitItem(uint16 src, uint16 dst, uint32 count)
InventoryResult CanEquipUniqueItem(Item *pItem, uint8 except_slot=NULL_SLOT, uint32 limit_count=1) const
Item * GetItemByEntry(uint32 entry) const
Item * GetUseableItemByPos(uint8 bag, uint8 slot) const
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap=false) const
bool HasItemCount(uint32 item, uint32 count=1, bool inBankAlso=false) const
uint8 GetBankBagSlotCount() const
Definition Player.h:1552
void RemoveItemFromBuyBackSlot(uint32 slot, bool del)
bool HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot=NULL_SLOT) const
Item * EquipNewItem(uint16 pos, uint32 item, bool update)
void AddItemToBuyBackSlot(Item *pItem)
void RecalculateRating(CombatRating cr)
Definition Player.h:2352
void AddEnchantmentDurations(Item *item)
Definition Player.cpp:10818
bool CanTitanGrip() const
Definition Player.h:2616
void SwapItem(uint16 src, uint16 dst)
bool HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot=NULL_SLOT) const
uint64 GetLootGUID() const
Definition Player.h:2393
bool IsTwoHandUsed() const
InventoryResult CanStoreItems(Item **pItem, int count) const
void RemoveTradeableItem(Item *item)
Item * _StoreItem(uint16 pos, Item *pItem, uint32 count, bool clone, bool update)
Item * StoreItem(ItemPosCountVec const &pos, Item *pItem, bool update)
WorldSession * GetSession() const
Definition Player.h:2417
Item * GetItemByGuid(uint64 guid) const
void DestroyConjuredItems(bool update)
Item * GetItemByPos(uint16 pos) const
bool HasSkill(uint32 skill) const
Definition Player.cpp:6542
void UpdateExpertise(WeaponAttackType attType)
uint32 m_currentBuybackSlot
Definition Player.h:3368
InventoryResult CanTakeMoreSimilarItems(Item *pItem) const
Definition Player.h:1565
uint32 GetItemCount(uint32 item, bool inBankAlso=false, Item *skipItem=NULL) const
void DestroyItem(uint8 bag, uint8 slot, bool update)
void MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
static bool IsInventoryPos(uint16 pos)
Definition Player.h:1531
uint32 m_weaponChangeTimer
Definition Player.h:3446
void _ApplyItemMods(Item *item, uint8 slot, bool apply)
Definition Player.cpp:8399
GlobalCooldownMgr & GetGlobalCooldownMgr()
Definition Player.h:2180
void MoveItemToInventory(ItemPosCountVec const &dest, Item *pItem, bool update, bool in_characterInventoryDB=false)
Item * GetShield(bool useable=false) const
Battleground * GetBattleground() const
Definition Player.cpp:19212
uint8 FindEquipSlot(ItemTemplate const *proto, uint32 slot, bool swap) const
Definition Player.cpp:10499
TradeData * GetTradeData() const
Definition Player.h:1694
Group * GetGroup()
Definition Player.h:2972
void SendRefundInfo(Item *item)
Definition Player.cpp:22163
void AutoUnequipOffhandIfNeed(bool force=false)
Definition Player.cpp:19517
void RemoveEnchantmentDurations(Item *item)
Definition Player.cpp:10834
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, Unit *unit=NULL)
Definition Player.cpp:21033
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=NULL) const
Item * EquipItem(uint16 pos, Item *pItem, bool update)
Item * m_items[PLAYER_SLOTS_COUNT]
Definition Player.h:3367
void AddItemDurations(Item *item)
Definition Player.cpp:19508
static bool IsBagPos(uint16 pos)
void ApplyEquipCooldown(Item *pItem)
Definition Player.cpp:18751
InventoryResult CanStoreItem_InInventorySlots(uint8 slot_begin, uint8 slot_end, ItemPosCountVec &dest, ItemTemplate const *pProto, uint32 &count, bool merge, Item *pSrcItem, uint8 skip_bag, uint8 skip_slot) const
void DestroyItemCount(uint32 item, uint32 count, bool update, bool unequip_check=false)
void AddTradeableItem(Item *item)
time_t m_logintime
Definition Player.h:1421
Item * GetItemFromBuyBackSlot(uint32 slot)
void RemoveItemDurations(Item *item)
Definition Player.cpp:19496
InventoryResult CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, ItemTemplate const *pProto, uint32 &count, bool merge, bool non_specialized, Item *pSrcItem, uint8 skip_bag, uint8 skip_slot) const
InventoryResult CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap, bool not_loading=true) const
uint32 GetItemCountWithLimitCategory(uint32 limitCategory, Item *skipItem=NULL) const
ReputationRank GetReputationRank(uint32 faction_id) const
Definition Player.cpp:7098
InventoryResult CanUnequipItems(uint32 item, uint32 count) const
void ItemAddedQuestCheck(uint32 entry, uint32 count)
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
bool IsUseEquipedWeapon(bool mainhand) const
Item * StoreNewItem(ItemPosCountVec const &pos, uint32 item, bool update, int32 randomPropertyId=0, AllowedLooterSet const &allowedLooters=AllowedLooterSet())
static bool IsBankPos(uint16 pos)
Definition Player.h:1542
void RemoveItem(uint8 bag, uint8 slot, bool update)
bool HasSpell(uint32 spell) const override
Definition Player.cpp:4674
WorldSession * m_session
Definition Player.h:3430
void VisualizeItem(uint8 slot, Item *pItem)
InventoryResult CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVec &dest, ItemTemplate const *pProto, uint32 &count, bool swap, Item *pSrcItem) const
void SetVisibleItemSlot(uint8 slot, Item *pItem)
static WeaponAttackType GetAttackBySlot(uint8 slot)
void DestroyZoneLimitedItem(bool update, uint32 new_zone)
bool IsValidPos(uint16 pos, bool explicit_pos)
Definition Player.h:1547
InventoryResult CanUseItem(Item *pItem, bool not_loading=true) const
void setString(const uint8 index, const std::string &value)
void setUInt32(const uint8 index, const uint32 value)
uint32 StartRecoveryTime
Definition SpellInfo.h:197
bool IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition Unit.cpp:1402
void CastSpell(SpellCastTargets const &targets, SpellInfo const *spellInfo, CustomSpellValues const *value, TriggerCastFlags triggerFlags=TRIGGERED_NONE, Item *castItem=NULL, AuraEffect const *triggeredByAura=NULL, uint64 originalCaster=0)
void RemoveAurasDueToSpell(uint32 spellId, uint64 casterGUID=0, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
bool CanDualWield() const
Definition Unit.h:1437
uint8 getClass() const
Definition Unit.h:1543
bool IsAlive() const
Definition Unit.h:2032
bool HasAura(uint32 spellId, uint64 casterGUID=0, uint64 itemCasterGUID=0, uint32 reqEffMask=0) const
bool CanUseAttackType(WeaponAttackType attacktype) const
Definition Unit.cpp:744
uint32 getRaceMask() const
Definition Unit.h:1539
bool HasUnitState(const uint32 f) const
Definition Unit.h:1485
uint32 getClassMask() const
Definition Unit.h:1547
bool IsInFeralForm() const
Definition Unit.cpp:4936
uint8 getLevel() const
Definition Unit.h:1528
bool IsInCombat() const
Definition Unit.h:1896
uint8 getRace() const
Definition Unit.h:1535
uint32 GetMapId() const
Definition Object.h:546
Map * GetMap() const
Definition Object.h:740
std::string const & GetName() const
Definition Object.h:664
WorldObject(bool isWorldObject)
Definition Object.cpp:1514
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
CharacterDatabaseWorkerPool CharacterDatabase
Accessor to the character database.
Definition Main.cpp:41
@ SMSG_DISPLAY_GAME_ERROR
Definition Opcodes.h:639
@ SMSG_SPELL_COOLDOWN
Definition Opcodes.h:979
@ SMSG_INVENTORY_CHANGE_FAILURE
Definition Opcodes.h:727
uint32 Color
uint32 SpellTrigger
int32 SpellId
uint32 maxCount
uint32 mode
bool isContainedIn(std::vector< ItemPosCount > const &vec) const
Definition Player.cpp:20254
bool CanChangeEquipStateInCombat() const
uint32 RequiredSkill
uint32 RequiredSpell
uint32 AllowableClass
uint32 RequiredSkillRank
uint32 GetMaxStackSize() const
_Spell Spells[MAX_ITEM_PROTO_SPELLS]
uint32 RequiredLevel
uint32 GemProperties
uint32 RequiredReputationRank
uint32 ContainerSlots
uint32 AllowableRace
uint32 RequiredReputationFaction
uint32 ItemLimitCategory
uint32 ScalingStatDistribution
uint32 InventoryType
_Socket Socket[MAX_ITEM_PROTO_SOCKETS]
uint32 MaxLevel
uint32 GemID