mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/Items: Implemented new item bonus types: limit category and pvp item level
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
// 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;
|
||||
BonusData gemBonus;
|
||||
gemBonus.Initialize(pGem);
|
||||
|
||||
if (InventoryResult res = CanEquipUniqueItem(pGem, eslot, gem_limit_count))
|
||||
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() && gemBonus.LimitCategory
|
||||
? pItem->GetGemCountWithLimitCategory(gemBonus.LimitCategory) : 1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user