aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Chat/Commands/Debugcmds.cpp2
-rw-r--r--src/server/game/Chat/Commands/Level2.cpp4
-rw-r--r--src/server/game/Chat/Commands/Level3.cpp2
-rw-r--r--src/server/game/DataStores/DBCEnums.h6
-rw-r--r--src/server/game/DataStores/DBCStructure.h2
-rw-r--r--src/server/game/DataStores/DBCfmt.h2
-rw-r--r--src/server/game/Entities/Item/Container/Bag.cpp13
-rw-r--r--src/server/game/Entities/Item/Container/Bag.h1
-rw-r--r--src/server/game/Entities/Item/Item.h9
-rw-r--r--src/server/game/Entities/Player/Player.cpp257
-rw-r--r--src/server/game/Entities/Player/Player.h8
-rw-r--r--src/server/game/Groups/Group.cpp4
-rw-r--r--src/server/game/Maps/Map.cpp2
-rw-r--r--src/server/game/Server/Protocol/Handlers/ItemHandler.cpp33
-rw-r--r--src/server/game/Server/Protocol/Handlers/LootHandler.cpp7
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp2
-rw-r--r--src/server/game/Spells/Spell.cpp5
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
-rw-r--r--src/server/scripts/Outland/zangarmarsh.cpp7
-rw-r--r--src/server/scripts/World/item_scripts.cpp9
20 files changed, 198 insertions, 179 deletions
diff --git a/src/server/game/Chat/Commands/Debugcmds.cpp b/src/server/game/Chat/Commands/Debugcmds.cpp
index a6c973ea002..64fa3efdcba 100644
--- a/src/server/game/Chat/Commands/Debugcmds.cpp
+++ b/src/server/game/Chat/Commands/Debugcmds.cpp
@@ -104,7 +104,7 @@ bool ChatHandler::HandleDebugSendEquipErrorCommand(const char* args)
return false;
uint8 msg = atoi(args);
- m_session->GetPlayer()->SendEquipError(msg, 0, 0);
+ m_session->GetPlayer()->SendEquipError(msg, NULL, NULL);
return true;
}
diff --git a/src/server/game/Chat/Commands/Level2.cpp b/src/server/game/Chat/Commands/Level2.cpp
index c66311f1277..15534e801aa 100644
--- a/src/server/game/Chat/Commands/Level2.cpp
+++ b/src/server/game/Chat/Commands/Level2.cpp
@@ -1959,10 +1959,10 @@ bool ChatHandler::HandleItemMoveCommand(const char* args)
if (srcslot == dstslot)
return true;
- if (!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,srcslot))
+ if (!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0, srcslot, true))
return false;
- if (!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,dstslot))
+ if (!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0, dstslot, false))
return false;
uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot);
diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp
index 860718d4908..8cade4bb397 100644
--- a/src/server/game/Chat/Commands/Level3.cpp
+++ b/src/server/game/Chat/Commands/Level3.cpp
@@ -2961,7 +2961,7 @@ bool ChatHandler::HandleAddItemSetCommand(const char *args)
}
else
{
- pl->SendEquipError(msg, NULL, NULL);
+ pl->SendEquipError(msg, NULL, NULL, pProto->ItemId);
PSendSysMessage(LANG_ITEM_CANNOT_CREATE, pProto->ItemId, 1);
}
}
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index bd72026d753..8caa77cddff 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -336,6 +336,12 @@ enum ItemEnchantmentType
ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET = 8
};
+enum ItemLimitCategoryMode
+{
+ ITEM_LIMIT_CATEGORY_MODE_HAVE = 0, // limit applied to amount items in inventory/bank
+ ITEM_LIMIT_CATEGORY_MODE_EQUIP = 1, // limit applied to amount equipped items (including used gems)
+};
+
enum TotemCategoryType
{
TOTEM_CATEGORY_TYPE_KNIFE = 1,
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index c8eb3701c33..562cd740c72 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -1060,7 +1060,7 @@ struct ItemLimitCategoryEntry
//char* name[16] // 1-16 m_name_lang
// 17 name flags
uint32 maxCount; // 18, max allowed equipped as item or in gem slot
- //uint32 unk; // 19, 1 for gems only...
+ uint32 mode; // 19, 0 = have, 1 = equip (enum ItemLimitCategoryMode)
};
struct ItemRandomPropertiesEntry
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index b83ea207804..1fb0fcbdf65 100644
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -69,7 +69,7 @@ const char ItemBagFamilyfmt[]="nxxxxxxxxxxxxxxxxx";
//const char ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx";
//const char ItemCondExtCostsEntryfmt[]="xiii";
const char ItemExtendedCostEntryfmt[]="niiiiiiiiiiiiiix";
-const char ItemLimitCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxix";
+const char ItemLimitCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii";
const char ItemRandomPropertiesfmt[]="nxiiiiissssssssssssssssx";
const char ItemRandomSuffixfmt[]="nssssssssssssssssxxiiiiiiiiii";
const char ItemSetEntryfmt[]="dssssssssssssssssxiiiiiiiiiixxxxxxxiiiiiiiiiiiiiiiiii";
diff --git a/src/server/game/Entities/Item/Container/Bag.cpp b/src/server/game/Entities/Item/Container/Bag.cpp
index 2d7aa490e32..6afd3260c08 100644
--- a/src/server/game/Entities/Item/Container/Bag.cpp
+++ b/src/server/game/Entities/Item/Container/Bag.cpp
@@ -213,6 +213,19 @@ uint32 Bag::GetItemCount(uint32 item, Item* eItem) const
return count;
}
+uint32 Bag::GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem) const
+{
+ uint32 count = 0;
+ for (uint32 i = 0; i < GetBagSize(); ++i)
+ if (Item *pItem = m_bagslot[i])
+ if (pItem != skipItem)
+ if (ItemPrototype const *pProto = pItem->GetProto())
+ if (pProto->ItemLimitCategory == limitCategory)
+ count += m_bagslot[i]->GetCount();
+
+ return count;
+}
+
uint8 Bag::GetSlotByItemGUID(uint64 guid) const
{
for (uint32 i = 0; i < GetBagSize(); ++i)
diff --git a/src/server/game/Entities/Item/Container/Bag.h b/src/server/game/Entities/Item/Container/Bag.h
index 4937b307547..6d4f65cf8cc 100644
--- a/src/server/game/Entities/Item/Container/Bag.h
+++ b/src/server/game/Entities/Item/Container/Bag.h
@@ -45,6 +45,7 @@ class Bag : public Item
Item* GetItemByPos(uint8 slot) const;
uint32 GetItemCount(uint32 item, Item* eItem = NULL) const;
+ uint32 GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem = NULL) const;
uint8 GetSlotByItemGUID(uint64 guid) const;
bool IsEmpty() const;
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index 22409a6813b..c2b18badf9b 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -120,10 +120,15 @@ enum InventoryChangeFailure
EQUIP_ERR_NOT_DURING_ARENA_MATCH = 78,
EQUIP_ERR_CANNOT_TRADE_THAT = 79,
EQUIP_ERR_PERSONAL_ARENA_RATING_TOO_LOW = 80,
- // no output = 81,
+ EQUIP_ERR_EVENT_AUTOEQUIP_BIND_CONFIRM = 81,
EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS = 82,
// no output = 83,
- // crash client = 84,
+ EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED = 84,
+ EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED = 85,
+ EQUIP_ERR_SCALING_STAT_ITEM_LEVEL_EXCEEDED = 86,
+ EQUIP_ERR_PURCHASE_LEVEL_TOO_LOW = 87,
+ EQUIP_ERR_CANT_EQUIP_NEED_TALENT = 88,
+ EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED = 89
};
enum BuyFailure
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 0d1918d36fd..301b5cfd2ae 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -9483,6 +9483,41 @@ uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const
return count;
}
+uint32 Player::GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem) const
+{
+ uint32 count = 0;
+ for (int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
+ if (Item *pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ if (pItem != skipItem)
+ if (ItemPrototype const *pProto = pItem->GetProto())
+ if (pProto->ItemLimitCategory == limitCategory)
+ count += pItem->GetCount();
+
+ for (int i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
+ if (Item *pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ if (pItem != skipItem)
+ if (ItemPrototype const *pProto = pItem->GetProto())
+ if (pProto->ItemLimitCategory == limitCategory)
+ count += pItem->GetCount();
+
+ for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
+ if (Bag* pBag = (Bag*) GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ count += pBag->GetItemCountWithLimitCategory(limitCategory, skipItem);
+
+ for (int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; ++i)
+ if (Item *pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ if (pItem != skipItem)
+ if (ItemPrototype const *pProto = pItem->GetProto())
+ if (pProto->ItemLimitCategory == limitCategory)
+ count += pItem->GetCount();
+
+ for (int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
+ if (Bag* pBag = (Bag*) GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ count += pBag->GetItemCountWithLimitCategory(limitCategory, skipItem);
+
+ return count;
+}
+
Item* Player::GetItemByGuid(uint64 guid) const
{
for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
@@ -9634,16 +9669,16 @@ bool Player::IsBagPos(uint16 pos)
return false;
}
-bool Player::IsValidPos(uint8 bag, uint8 slot)
+bool Player::IsValidPos(uint8 bag, uint8 slot, bool explicit_pos)
{
// post selected
- if (bag == NULL_BAG)
+ if (bag == NULL_BAG && !explicit_pos)
return true;
if (bag == INVENTORY_SLOT_BAG_0)
{
// any post selected
- if (slot == NULL_SLOT)
+ if (slot == NULL_SLOT && !explicit_pos)
return true;
// equipment
@@ -9681,7 +9716,7 @@ bool Player::IsValidPos(uint8 bag, uint8 slot)
return false;
// any post selected
- if (slot == NULL_SLOT)
+ if (slot == NULL_SLOT && !explicit_pos)
return true;
return slot < pBag->GetBagSize();
@@ -9695,7 +9730,7 @@ bool Player::IsValidPos(uint8 bag, uint8 slot)
return false;
// any post selected
- if (slot == NULL_SLOT)
+ if (slot == NULL_SLOT && !explicit_pos)
return true;
return slot < pBag->GetBagSize();
@@ -9850,96 +9885,6 @@ bool Player::HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32
return false;
}
-uint8 Player::CountItemWithLimitCategory(uint32 limitCategory, Item* skipItem) const
-{
- uint8 tempcount = 0;
- for (int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
- {
- Item *pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (!pItem)
- continue;
-
- if (pItem == skipItem)
- continue;
-
- ItemPrototype const *pProto = pItem->GetProto();
- if (pProto && pProto->ItemLimitCategory == limitCategory)
- tempcount += pItem->GetCount();
- }
-
- for (int i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
- {
- Item *pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (!pItem)
- continue;
-
- if (pItem == skipItem)
- continue;
-
- ItemPrototype const *pProto = pItem->GetProto();
- if (pProto && pProto->ItemLimitCategory == limitCategory)
- tempcount += pItem->GetCount();
- }
-
- for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
- {
- Bag* pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (!pBag)
- continue;
-
- for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
- {
- Item *pItem = GetItemByPos(i, j);
-
- if (!pItem)
- continue;
-
- if (pItem == skipItem)
- continue;
-
- if (pItem->GetProto()->ItemLimitCategory == limitCategory)
- tempcount += pItem->GetCount();
- }
- }
-
- for (int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; ++i)
- {
- Item *pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (!pItem)
- continue;
-
- if (pItem == skipItem)
- continue;
-
- ItemPrototype const *pProto = pItem->GetProto();
- if (pProto && pProto->ItemLimitCategory == limitCategory)
- tempcount += pItem->GetCount();
- }
-
- for (int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
- {
- Bag* pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (!pBag)
- continue;
-
- for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
- {
- Item *pItem = GetItemByPos(i, j);
-
- if (!pItem)
- continue;
-
- if (pItem == skipItem)
- continue;
-
- if (pItem->GetProto()->ItemLimitCategory == limitCategory)
- tempcount += pItem->GetCount();
- }
- }
-
- return tempcount;
-}
-
uint8 Player::_CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count) const
{
ItemPrototype const *pProto = objmgr.GetItemPrototype(entry);
@@ -9957,30 +9902,37 @@ uint8 Player::_CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem,
if (pProto->MaxCount <= 0 && pProto->ItemLimitCategory == 0 || pProto->MaxCount == 2147483647)
return EQUIP_ERR_OK;
- uint32 curcount;
- if (pProto->ItemLimitCategory)
- curcount = CountItemWithLimitCategory(pProto->ItemLimitCategory,pItem);
- else
- curcount = GetItemCount(pProto->ItemId,true,pItem);
-
- if ((curcount + count > uint32(pProto->MaxCount)) && !(pProto->ItemLimitCategory))
+ if (pProto->MaxCount > 0)
{
- if (no_space_count)
- *no_space_count = count +curcount - pProto->MaxCount;
- return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
+ uint32 curcount = GetItemCount(pProto->ItemId, true, pItem);
+ if (curcount + count > uint32(pProto->MaxCount))
+ {
+ if (no_space_count)
+ *no_space_count = count + curcount - pProto->MaxCount;
+ return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
+ }
}
- if (pProto->ItemLimitCategory && pProto->Class != ITEM_CLASS_GEM) // gem have equip check (maybe sort by bonding?)
+ // check unique-equipped limit
+ if (pProto->ItemLimitCategory)
{
ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(pProto->ItemLimitCategory);
if (!limitEntry)
- return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
-
- if (curcount + count > limitEntry->maxCount)
{
if (no_space_count)
- *no_space_count = count + curcount - limitEntry->maxCount;
- return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; // attempt add too many limit category items
+ *no_space_count = count;
+ return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
+ }
+
+ if (limitEntry->mode == ITEM_LIMIT_CATEGORY_MODE_HAVE)
+ {
+ uint32 curcount = GetItemCountWithLimitCategory(pProto->ItemLimitCategory, pItem);
+ if (curcount + count > uint32(limitEntry->maxCount))
+ {
+ if (no_space_count)
+ *no_space_count = count + curcount - limitEntry->maxCount;
+ return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED;
+ }
}
}
@@ -10094,8 +10046,9 @@ uint8 Player::_CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, ItemPrototyp
if (bag == skip_bag)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
+ // skip not existed bag or self targeted bag
Bag* pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, bag);
- if (!pBag)
+ if (!pBag || pBag == pSrcItem)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
ItemPrototype const* pBagProto = pBag->GetProto();
@@ -10588,6 +10541,9 @@ uint8 Player::_CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32
}
}
+ if (pItem && pItem->IsBag() && !((Bag*)pItem)->IsEmpty())
+ return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG;
+
// search free slot
res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot);
if (res != EQUIP_ERR_OK)
@@ -11401,7 +11357,7 @@ void Player::SetAmmo(uint32 item)
uint8 msg = CanUseAmmo(item);
if (msg != EQUIP_ERR_OK)
{
- SendEquipError(msg, NULL, NULL);
+ SendEquipError(msg, NULL, NULL, item);
return;
}
}
@@ -12752,7 +12708,7 @@ void Player::RemoveItemFromBuyBackSlot(uint32 slot, bool del)
}
}
-void Player::SendEquipError(uint8 msg, Item* pItem, Item *pItem2)
+void Player::SendEquipError(uint8 msg, Item* pItem, Item *pItem2, uint32 itemid)
{
sLog.outDebug("WORLD: Sent SMSG_INVENTORY_CHANGE_FAILURE (%u)", msg);
WorldPacket data(SMSG_INVENTORY_CHANGE_FAILURE, (msg == EQUIP_ERR_CANT_EQUIP_LEVEL_I ? 22 : 18));
@@ -12762,17 +12718,34 @@ void Player::SendEquipError(uint8 msg, Item* pItem, Item *pItem2)
{
data << uint64(pItem ? pItem->GetGUID() : 0);
data << uint64(pItem2 ? pItem2->GetGUID() : 0);
- data << uint8(0); // not 0 there...
+ data << uint8(0); // bag type subclass, used with EQUIP_ERR_EVENT_AUTOEQUIP_BIND_CONFIRM and EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG2
- if (msg == EQUIP_ERR_CANT_EQUIP_LEVEL_I)
+ switch(msg)
{
- uint8 level = 0;
-
- if (pItem)
- if (ItemPrototype const* proto = pItem->GetProto())
- level = proto->RequiredLevel;
-
- data << uint32(level); // new 2.4.0
+ case EQUIP_ERR_CANT_EQUIP_LEVEL_I:
+ case EQUIP_ERR_PURCHASE_LEVEL_TOO_LOW:
+ {
+ ItemPrototype const* proto = pItem ? pItem->GetProto() : objmgr.GetItemPrototype(itemid);
+ data << uint32(proto ? proto->RequiredLevel : 0);
+ break;
+ }
+ case EQUIP_ERR_EVENT_AUTOEQUIP_BIND_CONFIRM: // no idea about this one...
+ {
+ data << uint64(0);
+ data << uint32(0);
+ data << uint64(0);
+ break;
+ }
+ case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED:
+ case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED:
+ case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED:
+ {
+ ItemPrototype const* proto = pItem ? pItem->GetProto() : objmgr.GetItemPrototype(itemid);
+ data << uint32(proto ? proto->ItemLimitCategory : 0);
+ break;
+ }
+ default:
+ break;
}
}
GetSession()->SendPacket(&data);
@@ -14049,7 +14022,7 @@ bool Player::CanAddQuest(Quest const *pQuest, bool msg)
return true;
else if (msg2 != EQUIP_ERR_OK)
{
- SendEquipError(msg2, NULL, NULL);
+ SendEquipError(msg2, NULL, NULL, srcitem);
return false;
}
}
@@ -14165,7 +14138,7 @@ bool Player::CanRewardQuest(Quest const *pQuest, bool msg)
GetItemCount(pQuest->ReqItemId[i]) < pQuest->ReqItemCount[i])
{
if (msg)
- SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
+ SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL, pQuest->ReqItemId[i]);
return false;
}
}
@@ -14192,7 +14165,7 @@ bool Player::CanRewardQuest(Quest const *pQuest, uint32 reward, bool msg)
uint8 res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward]);
if (res != EQUIP_ERR_OK)
{
- SendEquipError(res, NULL, NULL);
+ SendEquipError(res, NULL, NULL, pQuest->RewChoiceItemId[reward]);
return false;
}
}
@@ -14208,7 +14181,7 @@ bool Player::CanRewardQuest(Quest const *pQuest, uint32 reward, bool msg)
uint8 res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, pQuest->RewItemId[i], pQuest->RewItemCount[i]);
if (res != EQUIP_ERR_OK)
{
- SendEquipError(res, NULL, NULL);
+ SendEquipError(res, NULL, NULL, pQuest->RewItemId[i]);
return false;
}
}
@@ -14929,7 +14902,7 @@ bool Player::GiveQuestSourceItem(Quest const *pQuest)
else if (msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS)
return true;
else
- SendEquipError(msg, NULL, NULL);
+ SendEquipError(msg, NULL, NULL, srcitem);
return false;
}
@@ -14950,11 +14923,11 @@ bool Player::TakeQuestSourceItem(uint32 quest_id, bool msg)
// exist one case when destroy source quest item not possible:
// non un-equippable item (equipped non-empty bag, for example)
- uint8 res = CanUnequipItems(srcitem,count);
+ uint8 res = CanUnequipItems(srcitem, count);
if (res != EQUIP_ERR_OK)
{
if (msg)
- SendEquipError(res, NULL, NULL);
+ SendEquipError(res, NULL, NULL, srcitem);
return false;
}
@@ -19717,7 +19690,7 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32
uint8 msg = CanStoreNewItem(bag, slot, dest, item, pProto->BuyCount * count);
if (msg != EQUIP_ERR_OK)
{
- SendEquipError(msg, NULL, NULL);
+ SendEquipError(msg, NULL, NULL, item);
return false;
}
@@ -19774,7 +19747,7 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32
uint8 msg = CanEquipNewItem(slot, dest, item, false);
if (msg != EQUIP_ERR_OK)
{
- SendEquipError(msg, NULL, NULL);
+ SendEquipError(msg, NULL, NULL, item);
return false;
}
@@ -22608,18 +22581,18 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons
LootItem* lootItem = loot.LootItemInSlot(i,this);
ItemPosCountVec dest;
- uint8 msg = CanStoreNewItem (bag,slot,dest,lootItem->itemid,lootItem->count);
+ uint8 msg = CanStoreNewItem(bag, slot, dest,lootItem->itemid, lootItem->count);
if (msg != EQUIP_ERR_OK && slot != NULL_SLOT)
- msg = CanStoreNewItem(bag, NULL_SLOT,dest,lootItem->itemid,lootItem->count);
+ msg = CanStoreNewItem(bag, NULL_SLOT, dest, lootItem->itemid, lootItem->count);
if (msg != EQUIP_ERR_OK && bag != NULL_BAG)
- msg = CanStoreNewItem(NULL_BAG, NULL_SLOT,dest,lootItem->itemid,lootItem->count);
+ msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, lootItem->itemid, lootItem->count);
if (msg != EQUIP_ERR_OK)
{
- SendEquipError(msg, NULL, NULL);
+ SendEquipError(msg, NULL, NULL, lootItem->itemid);
continue;
}
- Item* pItem = StoreNewItem (dest,lootItem->itemid,true,lootItem->randomPropertyId);
+ Item* pItem = StoreNewItem(dest,lootItem->itemid, true, lootItem->randomPropertyId);
SendNewItem(pItem, lootItem->count, false, false, broadcast);
}
}
@@ -22823,14 +22796,16 @@ uint8 Player::CanEquipUniqueItem(ItemPrototype const* itemProto, uint8 except_sl
{
ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(itemProto->ItemLimitCategory);
if (!limitEntry)
- return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE;
+ return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
+
+ // NOTE: limitEntry->mode not checked because if item have have-limit then it applied and to equip case
if (limit_count > limitEntry->maxCount)
- return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE; // attempt add too many limit category items (gems)
+ return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED;
// there is an equip limit on this item
- if (HasItemOrGemWithLimitCategoryEquipped(itemProto->ItemLimitCategory,limitEntry->maxCount-limit_count+1,except_slot))
- return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE;
+ if (HasItemOrGemWithLimitCategoryEquipped(itemProto->ItemLimitCategory, limitEntry->maxCount - limit_count + 1, except_slot))
+ return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED;
}
return EQUIP_ERR_OK;
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 85f69219195..4f8da387fb2 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1120,6 +1120,7 @@ class Player : public Unit, public GridObject<Player>
void SetSheath(SheathState sheathed); // overwrite Unit version
uint8 FindEquipSlot(ItemPrototype const* proto, uint32 slot, bool swap) const;
uint32 GetItemCount(uint32 item, bool inBankAlso = false, Item* skipItem = NULL) const;
+ uint32 GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem = NULL) const;
Item* GetItemByGuid(uint64 guid) const;
Item* GetItemByEntry(uint32 entry) const;
Item* GetItemByPos(uint16 pos) const;
@@ -1141,8 +1142,8 @@ class Player : public Unit, public GridObject<Player>
static bool IsBagPos(uint16 pos);
static bool IsBankPos(uint16 pos) { return IsBankPos(pos >> 8,pos & 255); }
static bool IsBankPos(uint8 bag, uint8 slot);
- bool IsValidPos(uint16 pos) { return IsBankPos(pos >> 8,pos & 255); }
- bool IsValidPos(uint8 bag, uint8 slot);
+ bool IsValidPos(uint16 pos, bool explicit_pos) { return IsValidPos(pos >> 8, pos & 255, explicit_pos); }
+ bool IsValidPos(uint8 bag, uint8 slot, bool explicit_pos);
uint8 GetBankBagSlotCount() const { return GetByteValue(PLAYER_BYTES_2, 2); }
void SetBankBagSlotCount(uint8 count) { SetByteValue(PLAYER_BYTES_2, 2, count); }
bool HasItemCount(uint32 item, uint32 count, bool inBankAlso = false) const;
@@ -1150,7 +1151,6 @@ class Player : public Unit, public GridObject<Player>
bool CanNoReagentCast(SpellEntry const* spellInfo) const;
bool HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot = NULL_SLOT) const;
bool HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot = NULL_SLOT) const;
- uint8 CountItemWithLimitCategory(uint32 limitCategory, Item* skipItem = NULL) const;
uint8 CanTakeMoreSimilarItems(Item* pItem) const { return _CanTakeMoreSimilarItems(pItem->GetEntry(),pItem->GetCount(),pItem); }
uint8 CanTakeMoreSimilarItems(uint32 entry, uint32 count) const { return _CanTakeMoreSimilarItems(entry,count,NULL); }
uint8 CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count = NULL) const
@@ -1223,7 +1223,7 @@ class Player : public Unit, public GridObject<Player>
Item* GetItemFromBuyBackSlot(uint32 slot);
void RemoveItemFromBuyBackSlot(uint32 slot, bool del);
uint32 GetMaxKeyringSize() const { return KEYRING_SLOT_END-KEYRING_SLOT_START; }
- void SendEquipError(uint8 msg, Item* pItem, Item *pItem2);
+ void SendEquipError(uint8 msg, Item* pItem, Item *pItem2 = NULL, uint32 itemid = 0);
void SendBuyError(uint8 msg, Creature* pCreature, uint32 item, uint32 param);
void SendSellError(uint8 msg, Creature* pCreature, uint64 guid, uint32 param);
void AddWeaponProficiency(uint32 newflag) { m_WeaponProficiency |= newflag; }
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 52dbe80cd0a..b1cd770a538 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -925,7 +925,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
else
{
item->is_blocked = false;
- player->SendEquipError(msg, NULL, NULL);
+ player->SendEquipError(msg, NULL, NULL, roll->itemid);
}
}
}
@@ -977,7 +977,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
else
{
item->is_blocked = false;
- player->SendEquipError(msg, NULL, NULL);
+ player->SendEquipError(msg, NULL, NULL, roll->itemid);
}
}
else if (rollvote == DISENCHANT)
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index fda97fed3ec..f6b66427f6a 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -3500,7 +3500,7 @@ void Map::ScriptsProcess()
pReceiver->SendNewItem(item, step.script->datalong2, false, true);
}
else
- pReceiver->SendEquipError(msg, NULL, NULL);
+ pReceiver->SendEquipError(msg, NULL, NULL, step.script->datalong);
}
break;
diff --git a/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp b/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp
index 262679cda6c..5087e541c0b 100644
--- a/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp
+++ b/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp
@@ -47,13 +47,13 @@ void WorldSession::HandleSplitItemOpcode(WorldPacket & recv_data)
if (count == 0)
return; //check count - if zero it's fake packet
- if (!_player->IsValidPos(srcbag,srcslot))
+ if (!_player->IsValidPos(srcbag, srcslot, true))
{
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
return;
}
- if (!_player->IsValidPos(dstbag,dstslot))
+ if (!_player->IsValidPos(dstbag, dstslot, false)) // can be autostore pos
{
_player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL);
return;
@@ -74,13 +74,13 @@ void WorldSession::HandleSwapInvItemOpcode(WorldPacket & recv_data)
if (srcslot == dstslot)
return;
- if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0,srcslot))
+ if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, srcslot, true))
{
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
return;
}
- if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0,dstslot))
+ if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, dstslot, true))
{
_player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL);
return;
@@ -126,13 +126,13 @@ void WorldSession::HandleSwapItem(WorldPacket & recv_data)
if (src == dst)
return;
- if (!_player->IsValidPos(srcbag,srcslot))
+ if (!_player->IsValidPos(srcbag, srcslot, true))
{
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
return;
}
- if (!_player->IsValidPos(dstbag,dstslot))
+ if (!_player->IsValidPos(dstbag, dstslot, true))
{
_player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL);
return;
@@ -739,7 +739,11 @@ void WorldSession::SendListInventory(uint64 vendorguid)
VendorItemData const* vItems = pCreature->GetVendorItems();
if (!vItems)
{
- _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0);
+ WorldPacket data(SMSG_LIST_INVENTORY, (8+1+1));
+ data << uint64(vendorguid);
+ data << uint8(0); // count==0, next will be error code
+ data << uint8(0); // "Vendor has no inventory"
+ SendPacket(&data);
return;
}
@@ -786,8 +790,12 @@ void WorldSession::SendListInventory(uint64 vendorguid)
}
}
- if (count == 0 || data.size() != 8 + 1 + size_t(count) * 8 * 4)
+ if (count == 0)
+ {
+ data << uint8(0);
+ SendPacket(&data);
return;
+ }
data.put<uint8>(count_pos, count);
SendPacket(&data);
@@ -805,7 +813,7 @@ void WorldSession::HandleAutoStoreBagItemOpcode(WorldPacket & recv_data)
if (!pItem)
return;
- if (!_player->IsValidPos(dstbag,NULL_SLOT))
+ if (!_player->IsValidPos(dstbag, NULL_SLOT, false)) // can be autostore pos
{
_player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL);
return;
@@ -917,6 +925,12 @@ void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket)
return;
}
+ if (dest.size() == 1 && dest[0].pos == pItem->GetPos())
+ {
+ _player->SendEquipError(EQUIP_ERR_NONE, pItem, NULL);
+ return;
+ }
+
_player->RemoveItem(srcbag, srcslot, true);
_player->BankItem(dest, pItem, true);
}
@@ -1255,6 +1269,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recv_data)
{
if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->ItemLimitCategory))
{
+ // NOTE: limitEntry->mode is not checked because if item has limit then it is applied in equip case
for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
{
if (Gems[j])
diff --git a/src/server/game/Server/Protocol/Handlers/LootHandler.cpp b/src/server/game/Server/Protocol/Handlers/LootHandler.cpp
index 0b438a15b6a..9ba7c98197a 100644
--- a/src/server/game/Server/Protocol/Handlers/LootHandler.cpp
+++ b/src/server/game/Server/Protocol/Handlers/LootHandler.cpp
@@ -155,7 +155,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recv_data)
player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count);
}
else
- player->SendEquipError(msg, NULL, NULL);
+ player->SendEquipError(msg, NULL, NULL, item->itemid);
}
void WorldSession::HandleLootMoneyOpcode(WorldPacket & /*recv_data*/)
@@ -526,8 +526,9 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket & recv_data)
uint8 msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count);
if (msg != EQUIP_ERR_OK)
{
- target->SendEquipError(msg, NULL, NULL);
- _player->SendEquipError(msg, NULL, NULL); // send duplicate of error massage to master looter
+ target->SendEquipError(msg, NULL, NULL, item.itemid);
+ // send duplicate of error massage to master looter
+ _player->SendEquipError(msg, NULL, NULL, item.itemid);
return;
}
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index ef85b293ac7..e3667913051 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -6097,7 +6097,7 @@ void AuraEffect::HandleChannelDeathItem(AuraApplication const * aurApp, uint8 mo
if (msg != EQUIP_ERR_OK)
{
count-=noSpaceForCount;
- plCaster->SendEquipError(msg, NULL, NULL);
+ plCaster->SendEquipError(msg, NULL, NULL, GetSpellProto()->EffectItemType[m_effIndex]);
if (count == 0)
return;
}
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 521781ba489..cad47652544 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -6116,9 +6116,10 @@ SpellCastResult Spell::CheckItems()
if (msg != EQUIP_ERR_OK)
{
ItemPrototype const *pProto = objmgr.GetItemPrototype(m_spellInfo->EffectItemType[i]);
+ // TODO: Needs review
if (pProto && !(pProto->ItemLimitCategory))
{
- p_caster->SendEquipError(msg, NULL, NULL);
+ p_caster->SendEquipError(msg, NULL, NULL, m_spellInfo->EffectItemType[i]);
return SPELL_FAILED_DONT_REPORT;
}
else
@@ -6149,7 +6150,7 @@ SpellCastResult Spell::CheckItems()
uint8 msg = p_caster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->EffectItemType[i], 1);
if (msg != EQUIP_ERR_OK)
{
- p_caster->SendEquipError(msg, NULL, NULL);
+ p_caster->SendEquipError(msg, NULL, NULL, m_spellInfo->EffectItemType[i]);
return SPELL_FAILED_DONT_REPORT;
}
}
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 4bfd8a44175..9fd56495db3 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -2878,7 +2878,7 @@ void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype)
else
{
// if not created by another reason from full inventory or unique items amount limitation
- player->SendEquipError(msg, NULL, NULL);
+ player->SendEquipError(msg, NULL, NULL, newitemid);
return;
}
}
diff --git a/src/server/scripts/Outland/zangarmarsh.cpp b/src/server/scripts/Outland/zangarmarsh.cpp
index db50e255118..9909b81fbec 100644
--- a/src/server/scripts/Outland/zangarmarsh.cpp
+++ b/src/server/scripts/Outland/zangarmarsh.cpp
@@ -225,13 +225,14 @@ bool GossipSelect_npc_elder_kuruti(Player* pPlayer, Creature* pCreature, uint32
if (!pPlayer->HasItemCount(24573,1))
{
ItemPosCountVec dest;
- uint8 msg = pPlayer->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, 24573, 1, false);
+ uint32 itemId = 24573;
+ uint8 msg = pPlayer->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, 1, false);
if (msg == EQUIP_ERR_OK)
{
- pPlayer->StoreNewItem(dest, 24573, true);
+ pPlayer->StoreNewItem(dest, itemId, true);
}
else
- pPlayer->SendEquipError(msg,NULL,NULL);
+ pPlayer->SendEquipError(msg, NULL, NULL, itemId);
}
pPlayer->SEND_GOSSIP_MENU(9231, pCreature->GetGUID());
break;
diff --git a/src/server/scripts/World/item_scripts.cpp b/src/server/scripts/World/item_scripts.cpp
index 013888f909d..1c70d9b2d3d 100644
--- a/src/server/scripts/World/item_scripts.cpp
+++ b/src/server/scripts/World/item_scripts.cpp
@@ -96,13 +96,14 @@ bool ItemUse_item_draenei_fishing_net(Player* pPlayer, Item* /*pItem*/, SpellCas
else
{
ItemPosCountVec dest;
- uint8 msg = pPlayer->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, 23614, 1);
+ uint32 itemId = 23614;
+ uint8 msg = pPlayer->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, 1);
if (msg == EQUIP_ERR_OK)
{
- if (Item* item = pPlayer->StoreNewItem(dest,23614,true))
- pPlayer->SendNewItem(item,1,false,true);
+ if (Item* item = pPlayer->StoreNewItem(dest, itemId, true))
+ pPlayer->SendNewItem(item, 1, false, true);
} else
- pPlayer->SendEquipError(msg,NULL,NULL);
+ pPlayer->SendEquipError(msg, NULL, NULL, itemId);
}
}
//}