diff options
author | Shauren <shauren.trinity@gmail.com> | 2025-10-05 15:13:57 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2025-10-05 15:13:57 +0200 |
commit | 8fff15ba7c63bc12fa00664bfe067bbc9586d3f2 (patch) | |
tree | 95187d99a0ad90779c838da3f603ae5db7020c10 /src | |
parent | ffbda978f32f1a70d33469b9f5b0644cc418e8ea (diff) |
Core/Items: Implemented new item bonus types: limit category and pvp item level
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/DataStores/DBCEnums.h | 3 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 46 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.h | 7 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 47 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 3 | ||||
-rw-r--r-- | src/server/game/Handlers/ItemHandler.cpp | 16 |
6 files changed, 97 insertions, 25 deletions
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index dc68d9fc594..542470a7bbf 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -1216,8 +1216,11 @@ enum ItemBonusType ITEM_BONUS_OVERRIDE_NAME = 31, // ItemNameDescription id ITEM_BONUS_ITEM_BONUS_LIST_GROUP = 34, ITEM_BONUS_ITEM_LIMIT_CATEGORY = 35, + ITEM_BONUS_PVP_ITEM_LEVEL_INCREMENT = 36, ITEM_BONUS_ITEM_CONVERSION = 37, ITEM_BONUS_ITEM_HISTORY_SLOT = 38, + ITEM_BONUS_PVP_ITEM_LEVEL_BASE = 43, + ITEM_BONUS_BONDING_WITH_PRIORITY = 47, }; enum class ItemCollectionType : uint8 diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 5401c0c9c45..6df3558d66b 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -1677,7 +1677,13 @@ uint8 Item::GetGemCountWithLimitCategory(uint32 limitCategory) const if (!gemProto) return false; - return gemProto->GetItemLimitCategory() == limitCategory; + BonusData gemBonus; + gemBonus.Initialize(gemProto); + + for (uint16 bonusListID : gemData.BonusListIDs) + gemBonus.AddBonusList(bonusListID); + + return gemBonus.LimitCategory == limitCategory; })); } @@ -2339,7 +2345,13 @@ uint32 Item::GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bon uint32 itemLevelBeforeUpgrades = itemLevel; if (pvpBonus) + { + if (bonusData.PvpItemLevel) + itemLevel = bonusData.PvpItemLevel; + + itemLevel += bonusData.PvpItemLevelBonus; itemLevel += sDB2Manager.GetPvpItemLevelBonus(itemTemplate->GetId()); + } if (itemTemplate->GetInventoryType() != INVTYPE_NON_EQUIP) { @@ -2919,6 +2931,9 @@ void BonusData::Initialize(ItemTemplate const* proto) Suffix = 0; RequiredLevelCurve = 0; + PvpItemLevel = 0; + PvpItemLevelBonus = 0; + EffectCount = 0; for (ItemEffectEntry const* itemEffect : proto->Effects) Effects[EffectCount++] = itemEffect; @@ -2926,6 +2941,8 @@ void BonusData::Initialize(ItemTemplate const* proto) for (std::size_t i = EffectCount; i < Effects.size(); ++i) Effects[i] = nullptr; + LimitCategory = proto->GetItemLimitCategory(); + CanDisenchant = !proto->HasFlag(ITEM_FLAG_NO_DISENCHANT); CanScrap = proto->HasFlag(ITEM_FLAG4_SCRAPABLE); @@ -2935,7 +2952,10 @@ void BonusData::Initialize(ItemTemplate const* proto) _state.ScalingStatDistributionPriority = std::numeric_limits<int32>::max(); _state.AzeriteTierUnlockSetPriority = std::numeric_limits<int32>::max(); _state.RequiredLevelCurvePriority = std::numeric_limits<int32>::max(); + _state.PvpItemLevelPriority = std::numeric_limits<int32>::max(); + _state.BondingPriority = std::numeric_limits<int32>::max(); _state.HasQualityBonus = false; + _state.HasItemLimitCategory = false; } void BonusData::Initialize(WorldPackets::Item::ItemInstance const& itemInstance) @@ -3072,5 +3092,29 @@ void BonusData::AddBonus(uint32 type, std::array<int32, 4> const& values) ContentTuningId = static_cast<uint32>(values[1]); } break; + case ITEM_BONUS_ITEM_LIMIT_CATEGORY: + if (!_state.HasItemLimitCategory) + { + LimitCategory = values[0]; + _state.HasItemLimitCategory = true; + } + break; + case ITEM_BONUS_PVP_ITEM_LEVEL_INCREMENT: + PvpItemLevelBonus += values[0]; + break; + case ITEM_BONUS_PVP_ITEM_LEVEL_BASE: + if (values[1] < _state.PvpItemLevelPriority) + { + PvpItemLevel = values[0]; + _state.PvpItemLevelPriority = values[1]; + } + break; + case ITEM_BONUS_BONDING_WITH_PRIORITY: + if (values[1] < _state.BondingPriority) + { + Bonding = static_cast<ItemBondingType>(values[0]); + _state.BondingPriority = values[1]; + } + break; } } diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index d8d03f1e709..d7bb941284d 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -80,8 +80,11 @@ struct BonusData int32 AzeriteTierUnlockSetId; uint32 Suffix; int32 RequiredLevelCurve; + uint16 PvpItemLevel; + int16 PvpItemLevelBonus; std::array<ItemEffectEntry const*, 13> Effects; std::size_t EffectCount; + uint32 LimitCategory; bool CanDisenchant; bool CanScrap; bool HasFixedLevel; @@ -100,7 +103,10 @@ private: int32 ScalingStatDistributionPriority; int32 AzeriteTierUnlockSetPriority; int32 RequiredLevelCurvePriority; + int32 PvpItemLevelPriority; + int32 BondingPriority; bool HasQualityBonus; + bool HasItemLimitCategory; } _state; }; @@ -347,6 +353,7 @@ class TC_GAME_API Item : public Object static ItemDisenchantLootEntry const* GetBaseDisenchantLoot(ItemTemplate const* itemTemplate, uint32 quality, uint32 itemLevel); void SetFixedLevel(uint8 level); std::span<ItemEffectEntry const* const> GetEffects() const { return { _bonusData.Effects.data(), _bonusData.EffectCount }; } + uint32 GetItemLimitCategory() const { return _bonusData.LimitCategory; } // Item Refund system void SetNotRefundable(Player* owner, bool changestate = true, CharacterDatabaseTransaction* trans = nullptr, bool addToCollection = true); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 0bcdbbd1ec7..f8ab0096a05 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -9564,9 +9564,8 @@ uint32 Player::GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipIte ForEachItem(ItemSearchLocation::Everywhere, [&count, limitCategory, skipItem](Item* item) { if (item != skipItem) - if (ItemTemplate const* pProto = item->GetTemplate()) - if (pProto->GetItemLimitCategory() == limitCategory) - count += item->GetCount(); + if (item->GetItemLimitCategory() == limitCategory) + count += item->GetCount(); return ItemSearchCallbackResult::Continue; }); @@ -9928,7 +9927,7 @@ bool Player::HasItemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count if (pItem->GetSlot() == except_slot) return ItemSearchCallbackResult::Continue; - if (pItem->GetTemplate()->GetItemLimitCategory() != limitCategory) + if (pItem->GetItemLimitCategory() != limitCategory) return ItemSearchCallbackResult::Continue; tempcount += pItem->GetCount(); @@ -9972,8 +9971,10 @@ InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item if (pItem && pItem->m_lootGenerated) return EQUIP_ERR_LOOT_GONE; + uint32 limitCategory = pItem ? pItem->GetItemLimitCategory() : pProto->GetItemLimitCategory(); + // no maximum - if ((pProto->GetMaxCount() <= 0 && pProto->GetItemLimitCategory() == 0) || pProto->GetMaxCount() == 2147483647) + if ((pProto->GetMaxCount() <= 0 && limitCategory == 0) || pProto->GetMaxCount() == 2147483647) return EQUIP_ERR_OK; if (pProto->GetMaxCount() > 0) @@ -9988,9 +9989,9 @@ InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item } // check unique-equipped limit - if (pProto->GetItemLimitCategory()) + if (limitCategory) { - ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(pProto->GetItemLimitCategory()); + ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(limitCategory); if (!limitEntry) { if (no_space_count) @@ -10001,7 +10002,7 @@ InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item if (limitEntry->Flags == ITEM_LIMIT_CATEGORY_MODE_HAVE) { uint8 limitQuantity = GetItemLimitCategoryQuantity(limitEntry); - uint32 curcount = GetItemCountWithLimitCategory(pProto->GetItemLimitCategory(), pItem); + uint32 curcount = GetItemCountWithLimitCategory(limitCategory, pItem); if (curcount + count > uint32(limitQuantity)) { if (no_space_count) @@ -13027,8 +13028,10 @@ void Player::SendEquipError(InventoryResult msg, Item const* item1 /*= nullptr*/ case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED_IS: case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED_IS: { - ItemTemplate const* proto = item1 ? item1->GetTemplate() : sObjectMgr->GetItemTemplate(itemId); - failure.LimitCategory = proto ? proto->GetItemLimitCategory() : 0; + if (item1) + failure.LimitCategory = item1->GetItemLimitCategory(); + else if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId)) + failure.LimitCategory = proto->GetItemLimitCategory(); break; } default: @@ -27014,7 +27017,7 @@ InventoryResult Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limi ItemTemplate const* pProto = pItem->GetTemplate(); // proto based limitations - if (InventoryResult res = CanEquipUniqueItem(pProto, eslot, limit_count)) + if (InventoryResult res = CanEquipUniqueItem(pProto, *pItem->GetBonus(), eslot, limit_count)) return res; // check unique-equipped on gems @@ -27024,18 +27027,24 @@ InventoryResult Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limi if (!pGem) continue; + BonusData gemBonus; + gemBonus.Initialize(pGem); + + for (uint16 bonusListID : gemData.BonusListIDs) + gemBonus.AddBonusList(bonusListID); + // include for check equip another gems with same limit category for not equipped item (and then not counted) - uint32 gem_limit_count = !pItem->IsEquipped() && pGem->GetItemLimitCategory() - ? pItem->GetGemCountWithLimitCategory(pGem->GetItemLimitCategory()) : 1; + uint32 gem_limit_count = !pItem->IsEquipped() && gemBonus.LimitCategory + ? pItem->GetGemCountWithLimitCategory(gemBonus.LimitCategory) : 1; - if (InventoryResult res = CanEquipUniqueItem(pGem, eslot, gem_limit_count)) + if (InventoryResult res = CanEquipUniqueItem(pGem, gemBonus, eslot, gem_limit_count)) return res; } return EQUIP_ERR_OK; } -InventoryResult Player::CanEquipUniqueItem(ItemTemplate const* itemProto, uint8 except_slot, uint32 limit_count) const +InventoryResult Player::CanEquipUniqueItem(ItemTemplate const* itemProto, BonusData const& itemBonus, uint8 except_slot, uint32 limit_count) const { // check unique-equipped on item if (itemProto->HasFlag(ITEM_FLAG_UNIQUE_EQUIPPABLE)) @@ -27046,9 +27055,9 @@ InventoryResult Player::CanEquipUniqueItem(ItemTemplate const* itemProto, uint8 } // check unique-equipped limit - if (itemProto->GetItemLimitCategory()) + if (itemBonus.LimitCategory) { - ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(itemProto->GetItemLimitCategory()); + ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(itemBonus.LimitCategory); if (!limitEntry) return EQUIP_ERR_NOT_EQUIPPABLE; @@ -27059,9 +27068,9 @@ InventoryResult Player::CanEquipUniqueItem(ItemTemplate const* itemProto, uint8 return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED_IS; // there is an equip limit on this item - if (HasItemWithLimitCategoryEquipped(itemProto->GetItemLimitCategory(), limitQuantity - limit_count + 1, except_slot)) + if (HasItemWithLimitCategoryEquipped(itemBonus.LimitCategory, limitQuantity - limit_count + 1, except_slot)) return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED_IS; - else if (HasGemWithLimitCategoryEquipped(itemProto->GetItemLimitCategory(), limitQuantity - limit_count + 1, except_slot)) + else if (HasGemWithLimitCategoryEquipped(itemBonus.LimitCategory, limitQuantity - limit_count + 1, except_slot)) return EQUIP_ERR_ITEM_MAX_COUNT_EQUIPPED_SOCKETED; } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 2b615518381..d6abd1c4104 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -45,6 +45,7 @@ struct AzeriteItemMilestonePowerEntry; struct AzeritePowerEntry; struct BarberShopStyleEntry; struct BattlegroundTemplate; +struct BonusData; struct CharTitlesEntry; struct ChatChannelsEntry; struct ChrSpecializationEntry; @@ -1490,7 +1491,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> InventoryResult CanEquipChildItem(Item* parentItem) const; InventoryResult CanEquipUniqueItem(Item* pItem, uint8 except_slot = NULL_SLOT, uint32 limit_count = 1) const; - InventoryResult CanEquipUniqueItem(ItemTemplate const* itemProto, uint8 except_slot = NULL_SLOT, uint32 limit_count = 1) const; + InventoryResult CanEquipUniqueItem(ItemTemplate const* itemProto, BonusData const& itemBonus, uint8 except_slot = NULL_SLOT, uint32 limit_count = 1) const; InventoryResult CanUnequipItems(uint32 item, uint32 count) const; InventoryResult CanUnequipItem(uint16 src, bool swap) const; InventoryResult CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, Item* pItem, bool swap, bool not_loading = true, bool reagentBankOnly = false) const; diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index a8602605c7d..329849c5e34 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -1048,9 +1048,9 @@ void WorldSession::HandleSocketGems(WorldPackets::Item::SocketGems& socketGems) // unique limit type item int32 limit_newcount = 0; - if (iGemProto->GetItemLimitCategory()) + if (gems[i]->GetItemLimitCategory()) { - if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->GetItemLimitCategory())) + if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(gems[i]->GetItemLimitCategory())) { // NOTE: limitEntry->Flags is not checked because if item has limit then it is applied in equip case for (int j = 0; j < MAX_GEM_SOCKETS; ++j) @@ -1058,15 +1058,23 @@ void WorldSession::HandleSocketGems(WorldPackets::Item::SocketGems& socketGems) if (gems[j]) { // new gem - if (iGemProto->GetItemLimitCategory() == gems[j]->GetTemplate()->GetItemLimitCategory()) + if (gems[i]->GetItemLimitCategory() == gems[j]->GetItemLimitCategory()) ++limit_newcount; } else if (oldGemData[j]) { // existing gem if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(oldGemData[j]->ItemID)) - if (iGemProto->GetItemLimitCategory() == jProto->GetItemLimitCategory()) + { + BonusData oldGemBonus; + oldGemBonus.Initialize(jProto); + + for (uint16 bonusListID : oldGemData[j]->BonusListIDs) + oldGemBonus.AddBonusList(bonusListID); + + if (gems[i]->GetItemLimitCategory() == oldGemBonus.LimitCategory) ++limit_newcount; + } } } |