aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatan Shukry <matanshukry@gmail.com>2021-04-21 11:02:42 +0300
committerGitHub <noreply@github.com>2021-04-21 10:02:42 +0200
commita8fa2a03beb4face5e12254522db93a9dd02b07d (patch)
tree2320aaa6a86de35933b44dcd8df9736f24069634
parentbf1c73dfc2c22a73e645ed41e2310b765caae80b (diff)
Core/Items: Calculating item level + organized iterating over items (#26276)
* Unified iterating player items into a single function Co-authored-by: Shauren <shauren.trinity@gmail.com>
-rw-r--r--src/server/game/Achievements/CriteriaHandler.cpp12
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp2
-rw-r--r--src/server/game/Entities/Item/Container/Bag.cpp47
-rw-r--r--src/server/game/Entities/Item/Container/Bag.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp675
-rw-r--r--src/server/game/Entities/Player/Player.h96
-rw-r--r--src/server/game/Handlers/AzeriteHandler.cpp6
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp3
-rw-r--r--src/server/game/Handlers/InspectHandler.cpp2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
10 files changed, 376 insertions, 471 deletions
diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp
index a9de265d3ba..57a45421017 100644
--- a/src/server/game/Achievements/CriteriaHandler.cpp
+++ b/src/server/game/Achievements/CriteriaHandler.cpp
@@ -2644,7 +2644,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6
}
case CRITERIA_ADDITIONAL_CONDITION_AZERITE_ITEM_LEVEL: // 235
{
- Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE);
+ Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere);
if (!heartOfAzeroth || heartOfAzeroth->ToAzeriteItem()->GetLevel() < reqValue)
return false;
break;
@@ -2693,7 +2693,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6
break;
case CRITERIA_ADDITIONAL_CONDITION_UNLOCKED_AZERITE_ESSENCE_RANK_LOWER: // 259
{
- if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE))
+ if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere))
if (AzeriteItem const* azeriteItem = heartOfAzeroth->ToAzeriteItem())
for (UF::UnlockedAzeriteEssence const& essence : azeriteItem->m_azeriteItemData->UnlockedEssences)
if (essence.AzeriteEssenceID == reqValue && essence.Rank < secondaryAsset)
@@ -2702,7 +2702,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6
}
case CRITERIA_ADDITIONAL_CONDITION_UNLOCKED_AZERITE_ESSENCE_RANK_EQUAL: // 260
{
- if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE))
+ if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere))
if (AzeriteItem const* azeriteItem = heartOfAzeroth->ToAzeriteItem())
for (UF::UnlockedAzeriteEssence const& essence : azeriteItem->m_azeriteItemData->UnlockedEssences)
if (essence.AzeriteEssenceID == reqValue && essence.Rank == secondaryAsset)
@@ -2711,7 +2711,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6
}
case CRITERIA_ADDITIONAL_CONDITION_UNLOCKED_AZERITE_ESSENCE_RANK_GREATER: // 261
{
- if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE))
+ if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere))
if (AzeriteItem const* azeriteItem = heartOfAzeroth->ToAzeriteItem())
for (UF::UnlockedAzeriteEssence const& essence : azeriteItem->m_azeriteItemData->UnlockedEssences)
if (essence.AzeriteEssenceID == reqValue && essence.Rank > secondaryAsset)
@@ -2734,7 +2734,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6
return false;
break;
case CRITERIA_ADDITIONAL_CONDITION_SELECTED_AZERITE_ESSENCE_RANK_LOWER: // 266
- if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE))
+ if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere))
if (AzeriteItem const* azeriteItem = heartOfAzeroth->ToAzeriteItem())
if (UF::SelectedAzeriteEssences const* selectedEssences = azeriteItem->GetSelectedAzeriteEssences())
for (UF::UnlockedAzeriteEssence const& essence : azeriteItem->m_azeriteItemData->UnlockedEssences)
@@ -2742,7 +2742,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6
return true;
return false;
case CRITERIA_ADDITIONAL_CONDITION_SELECTED_AZERITE_ESSENCE_RANK_GREATER: // 267
- if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE))
+ if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere))
if (AzeriteItem const* azeriteItem = heartOfAzeroth->ToAzeriteItem())
if (UF::SelectedAzeriteEssences const* selectedEssences = azeriteItem->GetSelectedAzeriteEssences())
for (UF::UnlockedAzeriteEssence const& essence : azeriteItem->m_azeriteItemData->UnlockedEssences)
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index e6f90796b89..6c50228e32c 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -2087,7 +2087,7 @@ void GameObject::Use(Unit* user)
}
case 2: // Heart Forge
{
- Item const* item = player->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE);
+ Item const* item = player->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere);
if (!item)
return;
diff --git a/src/server/game/Entities/Item/Container/Bag.cpp b/src/server/game/Entities/Item/Container/Bag.cpp
index 2b9628034f5..96449083294 100644
--- a/src/server/game/Entities/Item/Container/Bag.cpp
+++ b/src/server/game/Entities/Item/Container/Bag.cpp
@@ -263,43 +263,6 @@ bool Bag::IsEmpty() const
return true;
}
-uint32 Bag::GetItemCount(uint32 item, Item* eItem) const
-{
- Item* pItem;
- uint32 count = 0;
- for (uint32 i=0; i < GetBagSize(); ++i)
- {
- pItem = m_bagslot[i];
- if (pItem && pItem != eItem && pItem->GetEntry() == item)
- count += pItem->GetCount();
- }
-
- if (eItem && eItem->GetTemplate()->GetGemProperties())
- {
- for (uint32 i=0; i < GetBagSize(); ++i)
- {
- pItem = m_bagslot[i];
- if (pItem && pItem != eItem && pItem->GetSocketColor(0))
- count += pItem->GetGemCountWithID(item);
- }
- }
-
- 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 (ItemTemplate const* pProto = pItem->GetTemplate())
- if (pProto->GetItemLimitCategory() == limitCategory)
- count += m_bagslot[i]->GetCount();
-
- return count;
-}
-
uint8 Bag::GetSlotByItemGUID(ObjectGuid guid) const
{
for (uint32 i = 0; i < GetBagSize(); ++i)
@@ -317,3 +280,13 @@ Item* Bag::GetItemByPos(uint8 slot) const
return nullptr;
}
+
+uint32 GetBagSize(Bag const* bag)
+{
+ return bag->GetBagSize();
+}
+
+Item* GetItemInBag(Bag const* bag, uint8 slot)
+{
+ return bag->GetItemByPos(slot);
+}
diff --git a/src/server/game/Entities/Item/Container/Bag.h b/src/server/game/Entities/Item/Container/Bag.h
index c9906cb85e6..3bf36e3c5ea 100644
--- a/src/server/game/Entities/Item/Container/Bag.h
+++ b/src/server/game/Entities/Item/Container/Bag.h
@@ -40,8 +40,6 @@ class TC_GAME_API Bag : public Item
void RemoveItem(uint8 slot, bool update);
Item* GetItemByPos(uint8 slot) const;
- uint32 GetItemCount(uint32 item, Item* eItem = nullptr) const;
- uint32 GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem = nullptr) const;
uint8 GetSlotByItemGUID(ObjectGuid guid) const;
bool IsEmpty() const;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 0cf360516ac..a81ce529ff5 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -6909,7 +6909,7 @@ void Player::ModifyCurrency(uint32 id, int32 count, bool printLog/* = true*/, bo
if (id == CURRENCY_TYPE_AZERITE)
{
if (count > 0)
- if (Item* heartOfAzeroth = GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE))
+ if (Item* heartOfAzeroth = GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere))
heartOfAzeroth->ToAzeriteItem()->GiveXP(uint64(count));
return;
}
@@ -8153,7 +8153,7 @@ void Player::ApplyAzeritePowers(Item* item, bool apply)
}
else if (AzeriteEmpoweredItem* azeriteEmpoweredItem = item->ToAzeriteEmpoweredItem())
{
- if (!apply || GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_IN_EQUIPMENT))
+ if (!apply || GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Equipment))
for (int32 i = 0; i < MAX_AZERITE_EMPOWERED_TIER; ++i)
if (AzeritePowerEntry const* azeritePower = sAzeritePowerStore.LookupEntry(azeriteEmpoweredItem->GetSelectedAzeritePower(i)))
ApplyAzeritePower(azeriteEmpoweredItem, azeritePower, apply);
@@ -9934,128 +9934,53 @@ uint8 Player::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) c
InventoryResult Player::CanUnequipItems(uint32 item, uint32 count) const
{
- uint32 tempcount = 0;
-
InventoryResult res = EQUIP_ERR_OK;
-
- for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetEntry() == item)
- {
- InventoryResult ires = CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i, false);
- if (ires == EQUIP_ERR_OK)
- {
- tempcount += pItem->GetCount();
- if (tempcount >= count)
- return EQUIP_ERR_OK;
- }
- else
- res = ires;
- }
-
- uint8 inventoryEnd = INVENTORY_SLOT_ITEM_START + GetInventorySlotCount();
- for (uint8 i = INVENTORY_SLOT_ITEM_START; i < inventoryEnd; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetEntry() == item)
- {
- tempcount += pItem->GetCount();
- if (tempcount >= count)
- return EQUIP_ERR_OK;
- }
-
-
- for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetEntry() == item)
- {
- tempcount += pItem->GetCount();
- if (tempcount >= count)
- return EQUIP_ERR_OK;
- }
-
- for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetEntry() == item)
+ uint32 tempcount = 0;
+ bool result = ForEachItem(ItemSearchLocation::Equipment, [this, item, &res, &tempcount, count](Item* pItem)
+ {
+ if (pItem->GetEntry() == item)
+ {
+ InventoryResult ires = CanUnequipItem(pItem->GetPos(), false);
+ if (ires == EQUIP_ERR_OK)
{
tempcount += pItem->GetCount();
if (tempcount >= count)
- return EQUIP_ERR_OK;
+ return ItemSearchCallbackResult::Stop;
}
+ else
+ res = ires;
+ }
+ return ItemSearchCallbackResult::Continue;
+ });
- for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
- if (Bag* pBag = GetBagByPos(i))
- for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
- if (Item* pItem = GetItemByPos(i, j))
- if (pItem->GetEntry() == item)
- {
- tempcount += pItem->GetCount();
- if (tempcount >= count)
- return EQUIP_ERR_OK;
- }
+ if (!result) // we stopped early due to a sucess
+ return EQUIP_ERR_OK;
- // not found req. item count and have unequippable items
- return res;
+ return res; // return latest error if any
}
uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const
{
- uint32 count = 0;
- uint8 inventoryEnd = INVENTORY_SLOT_ITEM_START + GetInventorySlotCount();
- for (uint8 i = EQUIPMENT_SLOT_START; i < inventoryEnd; i++)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem != skipItem && pItem->GetEntry() == item)
- count += pItem->GetCount();
-
- for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
- if (Bag* pBag = GetBagByPos(i))
- count += pBag->GetItemCount(item, skipItem);
-
- if (skipItem && skipItem->GetTemplate()->GetGemProperties())
- for (uint8 i = EQUIPMENT_SLOT_START; i < inventoryEnd; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem != skipItem && pItem->GetSocketColor(0))
- count += pItem->GetGemCountWithID(item);
+ bool countGems = skipItem && skipItem->GetTemplate()->GetGemProperties();
+ ItemSearchLocation location = ItemSearchLocation::Equipment | ItemSearchLocation::Inventory | ItemSearchLocation::ReagentBank;
if (inBankAlso)
- {
- // checking every item from 39 to 74 (including bank bags)
- for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem != skipItem && pItem->GetEntry() == item)
- count += pItem->GetCount();
+ location |= ItemSearchLocation::Bank;
- for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
- if (Bag* pBag = GetBagByPos(i))
- count += pBag->GetItemCount(item, skipItem);
-
- if (skipItem && skipItem->GetTemplate()->GetGemProperties())
- for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem != skipItem && pItem->GetSocketColor(0))
- count += pItem->GetGemCountWithID(item);
- }
-
- for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem != skipItem && pItem->GetEntry() == item)
+ uint32 count = 0;
+ ForEachItem(location, [&count, item, skipItem, countGems](Item* pItem)
+ {
+ if (pItem != skipItem)
+ {
+ if (pItem->GetEntry() == item)
count += pItem->GetCount();
- if (skipItem && skipItem->GetTemplate()->GetGemProperties())
- for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem != skipItem && pItem->GetSocketColor(0))
- count += pItem->GetGemCountWithID(item);
-
- for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem != skipItem && pItem->GetEntry() == item)
- count += pItem->GetCount();
+ if (countGems)
+ count += pItem->GetGemCountWithID(item);
+ }
- if (skipItem && skipItem->GetTemplate()->GetGemProperties())
- for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem != skipItem && pItem->GetSocketColor(0))
- count += pItem->GetGemCountWithID(item);
+ return ItemSearchCallbackResult::Continue;
+ });
return count;
}
@@ -10063,84 +9988,32 @@ uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const
uint32 Player::GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem) const
{
uint32 count = 0;
- uint8 inventoryEnd = INVENTORY_SLOT_ITEM_START + GetInventorySlotCount();
- for (uint8 i = EQUIPMENT_SLOT_START; i < inventoryEnd; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem != skipItem)
- if (ItemTemplate const* pProto = pItem->GetTemplate())
- if (pProto->GetItemLimitCategory() == limitCategory)
- count += pItem->GetCount();
-
- for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
- if (Bag* pBag = GetBagByPos(i))
- count += pBag->GetItemCountWithLimitCategory(limitCategory, skipItem);
-
- for (int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem != skipItem)
- if (ItemTemplate const* pProto = pItem->GetTemplate())
- if (pProto->GetItemLimitCategory() == limitCategory)
- count += pItem->GetCount();
-
- for (int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
- if (Bag* pBag = GetBagByPos(i))
- count += pBag->GetItemCountWithLimitCategory(limitCategory, skipItem);
-
- for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem != skipItem)
- if (ItemTemplate const* pProto = pItem->GetTemplate())
- if (pProto->GetItemLimitCategory() == limitCategory)
- count += pItem->GetCount();
-
- for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem != skipItem)
- if (ItemTemplate const* pProto = pItem->GetTemplate())
- if (pProto->GetItemLimitCategory() == limitCategory)
- count += pItem->GetCount();
+ ForEachItem(ItemSearchLocation::Everywhere, [&count, limitCategory, skipItem](Item* item)
+ {
+ if (item != skipItem)
+ if (ItemTemplate const* pProto = item->GetTemplate())
+ if (pProto->GetItemLimitCategory() == limitCategory)
+ count += item->GetCount();
+ return ItemSearchCallbackResult::Continue;
+ });
return count;
}
Item* Player::GetItemByGuid(ObjectGuid guid) const
{
- uint8 inventoryEnd = INVENTORY_SLOT_ITEM_START + GetInventorySlotCount();
- for (uint8 i = EQUIPMENT_SLOT_START; i < inventoryEnd; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetGUID() == guid)
- return pItem;
-
- for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetGUID() == guid)
- return pItem;
-
- for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetGUID() == guid)
- return pItem;
-
- for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetGUID() == guid)
- return pItem;
-
- for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
- if (Bag* pBag = GetBagByPos(i))
- for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
- if (Item* pItem = pBag->GetItemByPos(j))
- if (pItem->GetGUID() == guid)
- return pItem;
-
- for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
- if (Bag* pBag = GetBagByPos(i))
- for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
- if (Item* pItem = pBag->GetItemByPos(j))
- if (pItem->GetGUID() == guid)
- return pItem;
+ Item* result = nullptr;
+ ForEachItem(ItemSearchLocation::Everywhere, [&result, guid](Item* item)
+ {
+ if (item->GetGUID() == guid)
+ {
+ result = item;
+ return ItemSearchCallbackResult::Stop;
+ }
- return nullptr;
+ return ItemSearchCallbackResult::Continue;
+ });
+ return result;
}
Item* Player::GetItemByPos(uint16 pos) const
@@ -10231,18 +10104,17 @@ Item* Player::GetShield(bool useable) const
Item* Player::GetChildItemByGuid(ObjectGuid guid) const
{
- uint8 inventoryEnd = INVENTORY_SLOT_ITEM_START + GetInventorySlotCount();
- for (uint8 i = EQUIPMENT_SLOT_START; i < inventoryEnd; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetGUID() == guid)
- return pItem;
-
- for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetGUID() == guid)
- return pItem;
-
- return nullptr;
+ Item* result = nullptr;
+ ForEachItem(ItemSearchLocation::Equipment | ItemSearchLocation::Inventory, [&result, guid](Item* item)
+ {
+ if (item->GetGUID() == guid)
+ {
+ result = item;
+ return ItemSearchCallbackResult::Stop;
+ }
+ return ItemSearchCallbackResult::Continue;
+ });
+ return result;
}
WeaponAttackType Player::GetAttackBySlot(uint8 slot, InventoryType inventoryType)
@@ -10400,181 +10272,84 @@ void Player::SetInventorySlotCount(uint8 slots)
bool Player::HasItemCount(uint32 item, uint32 count, bool inBankAlso) const
{
- uint32 tempcount = 0;
- uint8 inventoryEnd = INVENTORY_SLOT_ITEM_START + GetInventorySlotCount();
- for (uint8 i = EQUIPMENT_SLOT_START; i < inventoryEnd; i++)
- {
- Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
- {
- tempcount += pItem->GetCount();
- if (tempcount >= count)
- return true;
- }
- }
-
- for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
- {
- if (Bag* pBag = GetBagByPos(i))
- {
- for (uint32 j = 0; j < pBag->GetBagSize(); j++)
- {
- Item* pItem = GetItemByPos(i, j);
- if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
- {
- tempcount += pItem->GetCount();
- if (tempcount >= count)
- return true;
- }
- }
- }
- }
-
+ ItemSearchLocation location = ItemSearchLocation::Equipment | ItemSearchLocation::Inventory | ItemSearchLocation::ReagentBank;
if (inBankAlso)
- {
- for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; i++)
- {
- Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
- {
- tempcount += pItem->GetCount();
- if (tempcount >= count)
- return true;
- }
- }
- for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
- {
- if (Bag* pBag = GetBagByPos(i))
- {
- for (uint32 j = 0; j < pBag->GetBagSize(); j++)
- {
- Item* pItem = GetItemByPos(i, j);
- if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
- {
- tempcount += pItem->GetCount();
- if (tempcount >= count)
- return true;
- }
- }
- }
- }
- }
+ location |= ItemSearchLocation::Bank;
- for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; i++)
+ uint32 currentCount = 0;
+ return !ForEachItem(location, [item, count, &currentCount](Item* pItem)
{
- Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
+ if (pItem->GetEntry() == item && !pItem->IsInTrade())
{
- tempcount += pItem->GetCount();
- if (tempcount >= count)
- return true;
+ currentCount += pItem->GetCount();
+ if (currentCount >= count)
+ return ItemSearchCallbackResult::Stop;
}
- }
-
- for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; i++)
- {
- Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
- {
- tempcount += pItem->GetCount();
- if (tempcount >= count)
- return true;
- }
- }
-
- return false;
+ return ItemSearchCallbackResult::Continue;
+ });
}
bool Player::HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot) const
{
uint32 tempcount = 0;
- for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
- {
- if (i == except_slot)
- continue;
-
- Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (pItem && pItem->GetEntry() == item)
- {
- tempcount += pItem->GetCount();
- if (tempcount >= count)
- return true;
- }
- }
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item);
- if (pProto && pProto->GetGemProperties())
+ bool includeGems = pProto && pProto->GetGemProperties();
+ return !ForEachItem(ItemSearchLocation::Equipment, [item, &tempcount, count, except_slot, includeGems](Item* pItem)
{
- for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
+ if (pItem->GetSlot() != except_slot)
{
- if (i == except_slot)
- continue;
+ if (pItem->GetEntry() == item)
+ tempcount += pItem->GetCount();
- Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (pItem && pItem->GetSocketColor(0))
- {
+ if (includeGems)
tempcount += pItem->GetGemCountWithID(item);
- if (tempcount >= count)
- return true;
- }
+
+ if (tempcount >= count)
+ return ItemSearchCallbackResult::Stop;
}
- }
- return false;
+ return ItemSearchCallbackResult::Continue;
+ });
}
bool Player::HasItemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot) const
{
uint32 tempcount = 0;
- for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
+ return !ForEachItem(ItemSearchLocation::Equipment, [&tempcount, limitCategory, count, except_slot](Item* pItem)
{
- if (i == except_slot)
- continue;
+ if (pItem->GetSlot() == except_slot)
+ return ItemSearchCallbackResult::Continue;
- Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (!pItem)
- continue;
+ if (pItem->GetTemplate()->GetItemLimitCategory() != limitCategory)
+ return ItemSearchCallbackResult::Continue;
- ItemTemplate const* pProto = pItem->GetTemplate();
- if (!pProto)
- continue;
-
- if (pProto->GetItemLimitCategory() == limitCategory)
- {
- tempcount += pItem->GetCount();
- if (tempcount >= count)
- return true;
- }
- }
+ tempcount += pItem->GetCount();
+ if (tempcount >= count)
+ return ItemSearchCallbackResult::Stop;
- return false;
+ return ItemSearchCallbackResult::Continue;
+ });
}
bool Player::HasGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot) const
{
uint32 tempcount = 0;
- for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
+ return !ForEachItem(ItemSearchLocation::Equipment, [&tempcount, limitCategory, count, except_slot](Item* pItem)
{
- if (i == except_slot)
- continue;
-
- Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (!pItem)
- continue;
+ if (pItem->GetSlot() == except_slot)
+ return ItemSearchCallbackResult::Continue;
ItemTemplate const* pProto = pItem->GetTemplate();
if (!pProto)
- continue;
+ return ItemSearchCallbackResult::Continue;
- if (pItem->GetSocketColor(0) || pItem->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
- {
- tempcount += pItem->GetGemCountWithLimitCategory(limitCategory);
- if (tempcount >= count)
- return true;
- }
- }
+ tempcount += pItem->GetGemCountWithLimitCategory(limitCategory);
+ if (tempcount >= count)
+ return ItemSearchCallbackResult::Stop;
- return false;
+ return ItemSearchCallbackResult::Continue;
+ });
}
InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count /*= nullptr*/, uint32* offendingItemId /*= nullptr*/) const
@@ -12232,6 +12007,8 @@ Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool updat
}
}
}
+
+ UpdateAverageItemLevelTotal();
}
return item;
@@ -12488,6 +12265,8 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
UpdateCriteria(CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry());
UpdateCriteria(CRITERIA_TYPE_EQUIP_EPIC_ITEM, slot, pItem->GetEntry());
+ UpdateAverageItemLevelEquipped();
+
return pItem;
}
@@ -12738,6 +12517,9 @@ void Player::RemoveItem(uint8 bag, uint8 slot, bool update)
pItem->SendUpdateToPlayer(this);
AutoUnequipChildItem(pItem);
+
+ if (bag == INVENTORY_SLOT_BAG_0)
+ UpdateAverageItemLevelEquipped();
}
}
@@ -12875,6 +12657,10 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
pItem->SetContainedIn(ObjectGuid::Empty);
pItem->SetSlot(NULL_SLOT);
pItem->SetState(ITEM_REMOVED, this);
+
+ UpdateAverageItemLevelTotal();
+ if (bag == INVENTORY_SLOT_BAG_0)
+ UpdateAverageItemLevelEquipped();
}
}
@@ -13186,100 +12972,36 @@ void Player::DestroyConjuredItems(bool update)
DestroyItem(INVENTORY_SLOT_BAG_0, i, update);
}
-Item* Player::GetItemByEntry(uint32 entry, ItemSearchLocation where /*= ITEM_SEARCH_DEFAULT*/) const
+Item* Player::GetItemByEntry(uint32 entry, ItemSearchLocation where /*= ItemSearchLocation::Default */) const
{
- if (where & ITEM_SEARCH_IN_EQUIPMENT)
- {
- for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetEntry() == entry)
- return pItem;
-
- }
-
- if (where & ITEM_SEARCH_IN_INVENTORY)
- {
- // in inventory
- uint8 inventoryEnd = INVENTORY_SLOT_ITEM_START + GetInventorySlotCount();
- for (uint8 i = INVENTORY_SLOT_ITEM_START; i < inventoryEnd; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetEntry() == entry)
- return pItem;
-
- for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
- if (Bag* pBag = GetBagByPos(i))
- for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
- if (Item* pItem = pBag->GetItemByPos(j))
- if (pItem->GetEntry() == entry)
- return pItem;
-
- for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetEntry() == entry)
- return pItem;
- }
-
- if (where & ITEM_SEARCH_IN_BANK)
- {
- for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetEntry() == entry)
- return pItem;
-
- for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
- if (Bag* pBag = GetBagByPos(i))
- for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
- if (Item* pItem = pBag->GetItemByPos(j))
- if (pItem->GetEntry() == entry)
- return pItem;
- }
-
- if (where & ITEM_SEARCH_IN_REAGENT_BANK)
+ Item* result = nullptr;
+ ForEachItem(where, [&result, entry](Item* item)
{
- for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (pItem->GetEntry() == entry)
- return pItem;
- }
+ if (item->GetEntry() == entry)
+ {
+ result = item;
+ return ItemSearchCallbackResult::Stop;
+ }
- return nullptr;
+ return ItemSearchCallbackResult::Continue;
+ });
+ return result;
}
std::vector<Item*> Player::GetItemListByEntry(uint32 entry, bool inBankAlso) const
{
- std::vector<Item*> itemList = std::vector<Item*>();
-
- uint8 inventoryEnd = INVENTORY_SLOT_ITEM_START + GetInventorySlotCount();
- for (uint8 i = INVENTORY_SLOT_ITEM_START; i < inventoryEnd; ++i)
- if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (item->GetEntry() == entry)
- itemList.push_back(item);
-
- for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
- if (Bag* bag = GetBagByPos(i))
- for (uint32 j = 0; j < bag->GetBagSize(); ++j)
- if (Item* item = bag->GetItemByPos(j))
- if (item->GetEntry() == entry)
- itemList.push_back(item);
-
- for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; ++i)
- if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (item->GetEntry() == entry)
- itemList.push_back(item);
-
+ ItemSearchLocation location = ItemSearchLocation::Equipment | ItemSearchLocation::Inventory | ItemSearchLocation::ReagentBank;
if (inBankAlso)
- {
- for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
- if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (item->GetEntry() == entry)
- itemList.push_back(item);
- }
+ location |= ItemSearchLocation::Bank;
- for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
- if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (item->GetEntry() == entry)
- itemList.push_back(item);
+ std::vector<Item*> itemList = std::vector<Item*>();
+ ForEachItem(location, [&itemList, entry](Item* item)
+ {
+ if (item->GetEntry() == entry)
+ itemList.push_back(item);
+ return ItemSearchCallbackResult::Continue;
+ });
return itemList;
}
@@ -27855,7 +27577,7 @@ void Player::ActivateTalentGroup(ChrSpecializationEntry const* spec)
activeGlyphs.IsFullUpdate = true;
SendDirectMessage(activeGlyphs.Write());
- if (Item* item = GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE))
+ if (Item* item = GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere))
{
if (AzeriteItem* azeriteItem = item->ToAzeriteItem())
{
@@ -28950,3 +28672,132 @@ uint8 Player::GetItemLimitCategoryQuantity(ItemLimitCategoryEntry const* limitEn
return limit;
}
+
+template <typename T>
+static bool ForEachEquipmentSlot(InventoryType inventoryType, bool canDualWield, bool canTitanGrip, T callback)
+{
+ switch (inventoryType)
+ {
+ case INVTYPE_HEAD: callback(EQUIPMENT_SLOT_HEAD); return true;
+ case INVTYPE_NECK: callback(EQUIPMENT_SLOT_NECK); return true;
+ case INVTYPE_SHOULDERS: callback(EQUIPMENT_SLOT_SHOULDERS); return true;
+ case INVTYPE_BODY: callback(EQUIPMENT_SLOT_BODY); return true;
+ case INVTYPE_ROBE:
+ case INVTYPE_CHEST: callback(EQUIPMENT_SLOT_CHEST); return true;
+ case INVTYPE_WAIST: callback(EQUIPMENT_SLOT_WAIST); return true;
+ case INVTYPE_LEGS: callback(EQUIPMENT_SLOT_LEGS); return true;
+ case INVTYPE_FEET: callback(EQUIPMENT_SLOT_FEET); return true;
+ case INVTYPE_WRISTS: callback(EQUIPMENT_SLOT_WRISTS); return true;
+ case INVTYPE_HANDS: callback(EQUIPMENT_SLOT_HANDS); return true;
+ case INVTYPE_CLOAK: callback(EQUIPMENT_SLOT_BACK); return true;
+ case INVTYPE_FINGER:
+ callback(EQUIPMENT_SLOT_FINGER1);
+ callback(EQUIPMENT_SLOT_FINGER2, true);
+ return true;
+ case INVTYPE_TRINKET:
+ callback(EQUIPMENT_SLOT_TRINKET1);
+ callback(EQUIPMENT_SLOT_TRINKET2, true);
+ return true;
+ case INVTYPE_WEAPON:
+ callback(EQUIPMENT_SLOT_MAINHAND);
+ if (canDualWield)
+ callback(EQUIPMENT_SLOT_OFFHAND, true);
+ return true;
+ case INVTYPE_2HWEAPON:
+ callback(EQUIPMENT_SLOT_MAINHAND);
+ if (canDualWield && canTitanGrip)
+ callback(EQUIPMENT_SLOT_OFFHAND, true);
+ return true;
+ case INVTYPE_RANGED:
+ case INVTYPE_RANGEDRIGHT:
+ case INVTYPE_WEAPONMAINHAND: callback(EQUIPMENT_SLOT_MAINHAND); return true;
+ case INVTYPE_SHIELD:
+ case INVTYPE_HOLDABLE:
+ case INVTYPE_WEAPONOFFHAND: callback(EQUIPMENT_SLOT_OFFHAND); return true;
+
+ case INVTYPE_NON_EQUIP:
+ case INVTYPE_BAG:
+ case INVTYPE_TABARD:
+ case INVTYPE_AMMO:
+ case INVTYPE_THROWN:
+ case INVTYPE_QUIVER:
+ case INVTYPE_RELIC:
+ default:
+ return false;
+ }
+}
+
+void Player::UpdateAverageItemLevelTotal()
+{
+ std::array<std::tuple<InventoryType, uint32, ObjectGuid>, EQUIPMENT_SLOT_END> bestItemLevels = { };
+ bestItemLevels.fill({ INVTYPE_NON_EQUIP, 0, ObjectGuid::Empty });
+ float sum = 0;
+
+ ForEachItem(ItemSearchLocation::Everywhere, [this, &bestItemLevels, &sum](Item* item)
+ {
+ ItemTemplate const* itemTemplate = item->GetTemplate();
+ if (itemTemplate)
+ {
+ uint16 dest;
+ if (item->IsEquipped())
+ {
+ uint32 itemLevel = item->GetItemLevel(this);
+ InventoryType inventoryType = itemTemplate->GetInventoryType();
+ std::tuple<InventoryType, uint32, ObjectGuid>& slotData = bestItemLevels[item->GetSlot()];
+ if (itemLevel > std::get<1>(slotData))
+ {
+ sum += itemLevel - std::get<1>(slotData);
+ slotData = { inventoryType, itemLevel, item->GetGUID() };
+ }
+ }
+ else if (CanEquipItem(NULL_SLOT, dest, item, true, false) == EQUIP_ERR_OK)
+ {
+ uint32 itemLevel = item->GetItemLevel(this);
+ InventoryType inventoryType = itemTemplate->GetInventoryType();
+ ForEachEquipmentSlot(inventoryType, m_canDualWield, m_canTitanGrip, [&bestItemLevels, item, itemLevel, inventoryType, &sum](EquipmentSlots slot, bool checkDuplicateGuid = false)
+ {
+ if (checkDuplicateGuid)
+ {
+ for (std::tuple<InventoryType, uint32, ObjectGuid> const& slotData : bestItemLevels)
+ if (std::get<2>(slotData) == item->GetGUID())
+ return;
+ }
+
+ std::tuple<InventoryType, uint32, ObjectGuid>& slotData = bestItemLevels[slot];
+ if (itemLevel > std::get<1>(slotData))
+ {
+ sum += itemLevel - std::get<1>(slotData);
+ slotData = { inventoryType, itemLevel, item->GetGUID() };
+ }
+ });
+ }
+ }
+ return ItemSearchCallbackResult::Continue;
+ });
+
+ // If main hand is a 2h weapon, count it twice
+ std::tuple<InventoryType, uint32, ObjectGuid> const& mainHand = bestItemLevels[EQUIPMENT_SLOT_MAINHAND];
+ if (!m_canTitanGrip && std::get<0>(mainHand) == INVTYPE_2HWEAPON)
+ sum += std::get<1>(mainHand);
+
+ sum /= 16.0f;
+ SetAverageItemLevelTotal(sum);
+}
+
+void Player::UpdateAverageItemLevelEquipped()
+{
+ float totalItemLevel = 0;
+ for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
+ {
+ if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ {
+ uint32 itemLevel = pItem->GetItemLevel(this);
+ totalItemLevel += itemLevel;
+ if (!m_canTitanGrip && i == EQUIPMENT_SLOT_MAINHAND && pItem->GetTemplate()->GetInventoryType() == INVTYPE_2HWEAPON) // 2h weapon counts twice
+ totalItemLevel += itemLevel;
+ }
+ }
+
+ totalItemLevel /= 16.0;
+ SetAverageItemLevelEquipped(totalItemLevel);
+}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index bf512a63fd0..36a9006cb0a 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -111,6 +111,9 @@ namespace WorldPackets
}
}
+TC_GAME_API uint32 GetBagSize(Bag const* bag);
+TC_GAME_API Item* GetItemInBag(Bag const* bag, uint8 slot);
+
typedef std::deque<Mail*> PlayerMails;
#define PLAYER_MAX_SKILLS 256
@@ -675,15 +678,23 @@ struct ItemPosCount
};
typedef std::vector<ItemPosCount> ItemPosCountVec;
-enum ItemSearchLocation
+enum class ItemSearchLocation
{
- ITEM_SEARCH_IN_EQUIPMENT = 0x01,
- ITEM_SEARCH_IN_INVENTORY = 0x02,
- ITEM_SEARCH_IN_BANK = 0x04,
- ITEM_SEARCH_IN_REAGENT_BANK = 0x08,
+ Equipment = 0x01,
+ Inventory = 0x02,
+ Bank = 0x04,
+ ReagentBank = 0x08,
+
+ Default = Equipment | Inventory,
+ Everywhere = Equipment | Inventory | Bank | ReagentBank
+};
- ITEM_SEARCH_DEFAULT = ITEM_SEARCH_IN_EQUIPMENT | ITEM_SEARCH_IN_INVENTORY,
- ITEM_SEARCH_EVERYWHERE = ITEM_SEARCH_IN_EQUIPMENT | ITEM_SEARCH_IN_INVENTORY | ITEM_SEARCH_IN_BANK | ITEM_SEARCH_IN_REAGENT_BANK
+DEFINE_ENUM_FLAG(ItemSearchLocation);
+
+enum class ItemSearchCallbackResult
+{
+ Stop,
+ Continue
};
enum TransferAbortReason
@@ -1159,11 +1170,77 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
/*** STORAGE SYSTEM ***/
/*********************************************************/
+ /**
+ * @brief Iterate over each item in the player storage
+ * @tparam T ItemSearchCallbackResult ItemCallback(Item* item)
+ * @param location Locations of the items to iterate over
+ * @param callback Callback called on each item. Will continue as long as it returns ItemSearchCallbackResult::Continue
+ */
+ template <typename T>
+ bool ForEachItem(ItemSearchLocation location, T callback) const
+ {
+ EnumFlag<ItemSearchLocation> flag = location;
+
+ if (flag.HasFlag(ItemSearchLocation::Equipment))
+ for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
+ if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ if (callback(pItem) == ItemSearchCallbackResult::Stop)
+ return false;
+
+ if (flag.HasFlag(ItemSearchLocation::Inventory))
+ {
+ uint8 inventoryEnd = INVENTORY_SLOT_ITEM_START + GetInventorySlotCount();
+ for (uint8 i = INVENTORY_SLOT_BAG_START; i < inventoryEnd; ++i)
+ if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ if (callback(pItem) == ItemSearchCallbackResult::Stop)
+ return false;
+
+ for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
+ if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ if (callback(pItem) == ItemSearchCallbackResult::Stop)
+ return false;
+
+ for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
+ if (Bag* pBag = GetBagByPos(i))
+ for (uint32 j = 0; j < GetBagSize(pBag); ++j)
+ if (Item* pItem = GetItemInBag(pBag, j))
+ if (callback(pItem) == ItemSearchCallbackResult::Stop)
+ return false;
+ }
+
+ if (flag.HasFlag(ItemSearchLocation::Bank))
+ {
+ for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
+ if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ if (callback(pItem) == ItemSearchCallbackResult::Stop)
+ return false;
+
+ for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
+ if (Bag* pBag = GetBagByPos(i))
+ for (uint32 j = 0; j < GetBagSize(pBag); ++j)
+ if (Item* pItem = GetItemInBag(pBag, j))
+ if (callback(pItem) == ItemSearchCallbackResult::Stop)
+ return false;
+ }
+
+ if (flag.HasFlag(ItemSearchLocation::ReagentBank))
+ for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
+ if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ if (callback(pItem) == ItemSearchCallbackResult::Stop)
+ return false;
+
+ return true;
+ }
+
+ public:
+ void UpdateAverageItemLevelTotal();
+ void UpdateAverageItemLevelEquipped();
+
uint8 FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) const;
uint32 GetItemCount(uint32 item, bool inBankAlso = false, Item* skipItem = nullptr) const;
uint32 GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem = nullptr) const;
Item* GetItemByGuid(ObjectGuid guid) const;
- Item* GetItemByEntry(uint32 entry, ItemSearchLocation where = ITEM_SEARCH_DEFAULT) const;
+ Item* GetItemByEntry(uint32 entry, ItemSearchLocation where = ItemSearchLocation::Default) const;
std::vector<Item*> GetItemListByEntry(uint32 entry, bool inBankAlso = false) const;
Item* GetItemByPos(uint16 pos) const;
Item* GetItemByPos(uint8 bag, uint8 slot) const;
@@ -2471,6 +2548,9 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void RemovePlayerFlagEx(PlayerFlagsEx flags) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::PlayerFlagsEx), flags); }
void SetPlayerFlagsEx(PlayerFlagsEx flags) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::PlayerFlagsEx), flags); }
+ void SetAverageItemLevelTotal(float newItemLevel) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::AvgItemLevel, 0), newItemLevel); }
+ void SetAverageItemLevelEquipped(float newItemLevel) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::AvgItemLevel, 1), newItemLevel); }
+
uint32 GetCustomizationChoice(uint32 chrCustomizationOptionId) const
{
int32 choiceIndex = m_playerData->Customizations.FindIndexIf([chrCustomizationOptionId](UF::ChrCustomizationChoice choice)
diff --git a/src/server/game/Handlers/AzeriteHandler.cpp b/src/server/game/Handlers/AzeriteHandler.cpp
index f93dbca04b4..3fa3a32fe83 100644
--- a/src/server/game/Handlers/AzeriteHandler.cpp
+++ b/src/server/game/Handlers/AzeriteHandler.cpp
@@ -28,7 +28,7 @@ void WorldSession::HandleAzeriteEssenceUnlockMilestone(WorldPackets::Azerite::Az
if (!AzeriteItem::FindHeartForge(_player))
return;
- Item* item = _player->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE);
+ Item* item = _player->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere);
if (!item)
return;
@@ -59,7 +59,7 @@ void WorldSession::HandleAzeriteEssenceActivateEssence(WorldPackets::Azerite::Az
{
WorldPackets::Azerite::ActivateEssenceFailed activateEssenceResult;
activateEssenceResult.AzeriteEssenceID = azeriteEssenceActivateEssence.AzeriteEssenceID;
- Item* item = _player->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_IN_EQUIPMENT);
+ Item* item = _player->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Equipment);
if (!item)
{
activateEssenceResult.Reason = AzeriteEssenceActivateResult::NotEquipped;
@@ -200,7 +200,7 @@ void WorldSession::HandleAzeriteEmpoweredItemSelectPower(WorldPackets::Azerite::
return;
uint32 azeriteLevel = 0;
- Item const* heartOfAzeroth = _player->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE);
+ Item const* heartOfAzeroth = _player->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere);
if (!heartOfAzeroth)
return;
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index caae1003ccd..5f51fafca25 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -1364,6 +1364,9 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
if (!pCurrChar->IsStandState() && !pCurrChar->HasUnitState(UNIT_STATE_STUNNED))
pCurrChar->SetStandState(UNIT_STAND_STATE_STAND);
+ pCurrChar->UpdateAverageItemLevelTotal();
+ pCurrChar->UpdateAverageItemLevelEquipped();
+
m_playerLoading.Clear();
// Handle Login-Achievements (should be handled after loading)
diff --git a/src/server/game/Handlers/InspectHandler.cpp b/src/server/game/Handlers/InspectHandler.cpp
index c999d26e11a..90f4681bf22 100644
--- a/src/server/game/Handlers/InspectHandler.cpp
+++ b/src/server/game/Handlers/InspectHandler.cpp
@@ -65,7 +65,7 @@ void WorldSession::HandleInspectOpcode(WorldPackets::Inspect::Inspect& inspect)
inspectResult.GuildData->AchievementPoints = guild->GetAchievementMgr().GetAchievementPoints();
}
- if (Item const* heartOfAzeroth = player->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE))
+ if (Item const* heartOfAzeroth = player->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere))
if (AzeriteItem const* azeriteItem = heartOfAzeroth->ToAzeriteItem())
inspectResult.AzeriteLevel = azeriteItem->GetEffectiveLevel();
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index d7cfda76147..06ee5111fd6 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -5824,7 +5824,7 @@ void Spell::EffectLearnAzeriteEssencePower(SpellEffIndex /*effIndex*/)
if (!playerTarget)
return;
- Item* heartOfAzeroth = playerTarget->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ITEM_SEARCH_EVERYWHERE);
+ Item* heartOfAzeroth = playerTarget->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere);
if (!heartOfAzeroth)
return;