Implemented limit category check for item/gem at equip or gem inserting. Author: VladimirMangos
--HG-- branch : trunk
This commit is contained in:
+25
-2
@@ -806,7 +806,7 @@ void Item::ClearEnchantment(EnchantmentSlot slot)
|
||||
bool Item::GemsFitSockets() const
|
||||
{
|
||||
bool fits = true;
|
||||
for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
|
||||
for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
|
||||
{
|
||||
uint8 SocketColor = GetProto()->Socket[enchant_slot-SOCK_ENCHANTMENT_SLOT].Color;
|
||||
|
||||
@@ -846,7 +846,7 @@ bool Item::GemsFitSockets() const
|
||||
uint8 Item::GetGemCountWithID(uint32 GemID) const
|
||||
{
|
||||
uint8 count = 0;
|
||||
for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
|
||||
for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
|
||||
{
|
||||
uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot));
|
||||
if(!enchant_id)
|
||||
@@ -862,6 +862,29 @@ uint8 Item::GetGemCountWithID(uint32 GemID) const
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8 Item::GetGemCountWithLimitCategory(uint32 limitCategory) const
|
||||
{
|
||||
uint8 count = 0;
|
||||
for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
|
||||
{
|
||||
uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot));
|
||||
if(!enchant_id)
|
||||
continue;
|
||||
|
||||
SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
|
||||
if(!enchantEntry)
|
||||
continue;
|
||||
|
||||
ItemPrototype const* gemProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID);
|
||||
if(!gemProto)
|
||||
continue;
|
||||
|
||||
if(gemProto->ItemLimitCategory==limitCategory)
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool Item::IsLimitedToAnotherMapOrZone( uint32 cur_mapId, uint32 cur_zoneId) const
|
||||
{
|
||||
ItemPrototype const* proto = GetProto();
|
||||
|
||||
@@ -236,6 +236,7 @@ class TRINITY_DLL_SPEC Item : public Object
|
||||
void SetCount(uint32 value) { SetUInt32Value (ITEM_FIELD_STACK_COUNT, value); }
|
||||
uint32 GetMaxStackCount() const { return GetProto()->GetMaxStackSize(); }
|
||||
uint8 GetGemCountWithID(uint32 GemID) const;
|
||||
uint8 GetGemCountWithLimitCategory(uint32 limitCategory) const;
|
||||
|
||||
uint8 GetSlot() const {return m_slot;}
|
||||
Bag *GetContainer() { return m_container; }
|
||||
|
||||
+76
-26
@@ -1186,41 +1186,91 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recv_data)
|
||||
// check unique-equipped conditions
|
||||
for(int i = 0; i < MAX_GEM_SOCKETS; ++i)
|
||||
{
|
||||
if (Gems[i] && (Gems[i]->GetProto()->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED))
|
||||
if(!Gems[i])
|
||||
continue;
|
||||
|
||||
// continue check for case when attempt add 2 similar unique equipped gems in one item.
|
||||
ItemPrototype const* iGemProto = Gems[i]->GetProto();
|
||||
|
||||
// unique item (for new and already placed bit removed enchantments
|
||||
if (iGemProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)
|
||||
{
|
||||
// for equipped item check all equipment for duplicate equipped gems
|
||||
if(itemTarget->IsEquipped())
|
||||
{
|
||||
if(GetPlayer()->GetItemOrItemWithGemEquipped(Gems[i]->GetEntry()))
|
||||
{
|
||||
_player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE, itemTarget, NULL );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// continue check for case when attempt add 2 similar unique equipped gems in one item.
|
||||
for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
|
||||
{
|
||||
if ((i != j) && (Gems[j]) && (Gems[i]->GetProto()->ItemId == Gems[j]->GetProto()->ItemId))
|
||||
{
|
||||
_player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
|
||||
{
|
||||
if (OldEnchants[j])
|
||||
{
|
||||
SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]);
|
||||
if(!enchantEntry)
|
||||
continue;
|
||||
if(i==j) // skip self
|
||||
continue;
|
||||
|
||||
if ((enchantEntry->GemID == Gems[i]->GetProto()->ItemId) && (i != j))
|
||||
if (Gems[j])
|
||||
{
|
||||
if (iGemProto->ItemId == Gems[j]->GetEntry())
|
||||
{
|
||||
_player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(OldEnchants[j])
|
||||
{
|
||||
if(SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
|
||||
{
|
||||
if (iGemProto->ItemId == enchantEntry->GemID)
|
||||
{
|
||||
_player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// unique limit type item
|
||||
int32 limit_newcount = 0;
|
||||
if (iGemProto->ItemLimitCategory)
|
||||
{
|
||||
if(ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->ItemLimitCategory))
|
||||
{
|
||||
for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
|
||||
{
|
||||
if (Gems[j])
|
||||
{
|
||||
// destroyed gem
|
||||
if (OldEnchants[j])
|
||||
{
|
||||
if(SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
|
||||
if(ItemPrototype const* jProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID))
|
||||
if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory)
|
||||
--limit_newcount;
|
||||
}
|
||||
|
||||
// new gem
|
||||
if (iGemProto->ItemLimitCategory == Gems[j]->GetProto()->ItemLimitCategory)
|
||||
++limit_newcount;
|
||||
}
|
||||
// existed gem
|
||||
else if(OldEnchants[j])
|
||||
{
|
||||
if(SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
|
||||
if(ItemPrototype const* jProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID))
|
||||
if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory)
|
||||
++limit_newcount;
|
||||
}
|
||||
}
|
||||
|
||||
if(limit_newcount > 0 && uint32(limit_newcount) > limitEntry->maxCount)
|
||||
{
|
||||
_player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for equipped item check all equipment for duplicate equipped gems
|
||||
if(itemTarget->IsEquipped())
|
||||
{
|
||||
if(uint8 res = _player->CanEquipUniqueItem(Gems[i],slot,limit_newcount >= 0 ? limit_newcount : 0))
|
||||
{
|
||||
_player->SendEquipError( res, itemTarget, NULL );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1777,6 +1777,12 @@ void ObjectMgr::LoadItemPrototypes()
|
||||
sLog.outErrorDb("Item (Entry: %u) has wrong FoodType value (%u)",i,proto->FoodType);
|
||||
const_cast<ItemPrototype*>(proto)->FoodType = 0;
|
||||
}
|
||||
|
||||
if(proto->ItemLimitCategory && !sItemLimitCategoryStore.LookupEntry(proto->ItemLimitCategory))
|
||||
{
|
||||
sLog.outErrorDb("Item (Entry: %u) has wrong LimitCategory value (%u)",i,proto->ItemLimitCategory);
|
||||
const_cast<ItemPrototype*>(proto)->ItemLimitCategory = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6668,7 +6674,7 @@ bool PlayerCondition::Meets(Player const * player) const
|
||||
case CONDITION_ITEM:
|
||||
return player->HasItemCount(value1, value2);
|
||||
case CONDITION_ITEM_EQUIPPED:
|
||||
return player->GetItemOrItemWithGemEquipped(value1) != NULL;
|
||||
return player->HasItemOrGemWithIdEquipped(value1,1);
|
||||
case CONDITION_ZONEID:
|
||||
return player->GetZoneId() == value1;
|
||||
case CONDITION_REPUTATION_RANK:
|
||||
|
||||
+121
-39
@@ -9099,31 +9099,76 @@ bool Player::HasItemCount( uint32 item, uint32 count, bool inBankAlso ) const
|
||||
return false;
|
||||
}
|
||||
|
||||
Item* Player::GetItemOrItemWithGemEquipped( uint32 item ) const
|
||||
bool Player::HasItemOrGemWithIdEquipped( uint32 item, uint32 count, uint8 except_slot ) const
|
||||
{
|
||||
Item *pItem;
|
||||
for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
|
||||
uint32 tempcount = 0;
|
||||
for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
|
||||
{
|
||||
pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
|
||||
if( pItem && pItem->GetEntry() == item )
|
||||
return pItem;
|
||||
if(i==int(except_slot))
|
||||
continue;
|
||||
|
||||
Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
|
||||
if( pItem && pItem->GetEntry() == item)
|
||||
{
|
||||
tempcount += pItem->GetCount();
|
||||
if( tempcount >= count )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ItemPrototype const *pProto = objmgr.GetItemPrototype(item);
|
||||
if (pProto && pProto->GemProperties)
|
||||
{
|
||||
for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
|
||||
for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
|
||||
{
|
||||
pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
|
||||
if( pItem && pItem->GetProto()->Socket[0].Color )
|
||||
if(i==int(except_slot))
|
||||
continue;
|
||||
|
||||
Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
|
||||
if( pItem && pItem->GetProto()->Socket[0].Color)
|
||||
{
|
||||
if (pItem->GetGemCountWithID(item) > 0 )
|
||||
return pItem;
|
||||
tempcount += pItem->GetGemCountWithID(item);
|
||||
if( tempcount >= count )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Player::HasItemOrGemWithLimitCategoryEquipped( uint32 limitCategory, uint32 count, uint8 except_slot ) const
|
||||
{
|
||||
uint32 tempcount = 0;
|
||||
for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
|
||||
{
|
||||
if(i==int(except_slot))
|
||||
continue;
|
||||
|
||||
Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
|
||||
if (!pItem)
|
||||
continue;
|
||||
|
||||
ItemPrototype const *pProto = pItem->GetProto();
|
||||
if (!pProto)
|
||||
continue;
|
||||
|
||||
if (pProto->ItemLimitCategory == limitCategory)
|
||||
{
|
||||
tempcount += pItem->GetCount();
|
||||
if( tempcount >= count )
|
||||
return true;
|
||||
}
|
||||
|
||||
if( pProto->Socket[0].Color)
|
||||
{
|
||||
tempcount += pItem->GetGemCountWithLimitCategory(limitCategory);
|
||||
if( tempcount >= count )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8 Player::_CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count ) const
|
||||
@@ -10210,33 +10255,9 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
|
||||
if( !swap && GetItemByPos( INVENTORY_SLOT_BAG_0, eslot ) )
|
||||
return EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE;
|
||||
|
||||
// check unique-equipped on item
|
||||
if (pProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)
|
||||
{
|
||||
// there is an equip limit on this item
|
||||
Item* tItem = GetItemOrItemWithGemEquipped(pProto->ItemId);
|
||||
if (tItem && (!swap || tItem->GetSlot() != eslot ) )
|
||||
return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE;
|
||||
}
|
||||
|
||||
// check unique-equipped on gems
|
||||
for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
|
||||
{
|
||||
uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot));
|
||||
if(!enchant_id)
|
||||
continue;
|
||||
SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
|
||||
if(!enchantEntry)
|
||||
continue;
|
||||
|
||||
ItemPrototype const* pGem = objmgr.GetItemPrototype(enchantEntry->GemID);
|
||||
if(pGem && (pGem->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED))
|
||||
{
|
||||
Item* tItem = GetItemOrItemWithGemEquipped(enchantEntry->GemID);
|
||||
if(tItem && (!swap || tItem->GetSlot() != eslot ))
|
||||
return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE;
|
||||
}
|
||||
}
|
||||
// if swap ignore item (equipped also)
|
||||
if(uint8 res = CanEquipUniqueItem(pItem, swap ? eslot : NULL_SLOT))
|
||||
return res;
|
||||
|
||||
// check unique-equipped special item classes
|
||||
if (pProto->Class == ITEM_CLASS_QUIVER)
|
||||
@@ -20373,3 +20394,64 @@ uint32 Player::GetPhaseMaskForSpawn() const
|
||||
|
||||
return PHASEMASK_NORMAL;
|
||||
}
|
||||
|
||||
uint8 Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limit_count) const
|
||||
{
|
||||
ItemPrototype const* pProto = pItem->GetProto();
|
||||
|
||||
// proto based limitations
|
||||
if(uint8 res = CanEquipUniqueItem(pProto,eslot,limit_count))
|
||||
return res;
|
||||
|
||||
// check unique-equipped on gems
|
||||
for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
|
||||
{
|
||||
uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot));
|
||||
if(!enchant_id)
|
||||
continue;
|
||||
SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
|
||||
if(!enchantEntry)
|
||||
continue;
|
||||
|
||||
ItemPrototype const* pGem = objmgr.GetItemPrototype(enchantEntry->GemID);
|
||||
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->ItemLimitCategory
|
||||
? pItem->GetGemCountWithLimitCategory(pGem->ItemLimitCategory) : 1;
|
||||
|
||||
if(uint8 res = CanEquipUniqueItem(pGem, eslot,gem_limit_count))
|
||||
return res;
|
||||
}
|
||||
|
||||
return EQUIP_ERR_OK;
|
||||
}
|
||||
|
||||
uint8 Player::CanEquipUniqueItem( ItemPrototype const* itemProto, uint8 except_slot, uint32 limit_count) const
|
||||
{
|
||||
// check unique-equipped on item
|
||||
if (itemProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)
|
||||
{
|
||||
// there is an equip limit on this item
|
||||
if(HasItemOrGemWithIdEquipped(itemProto->ItemId,1,except_slot))
|
||||
return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE;
|
||||
}
|
||||
|
||||
// check unique-equipped limit
|
||||
if (itemProto->ItemLimitCategory)
|
||||
{
|
||||
ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(itemProto->ItemLimitCategory);
|
||||
if(!limitEntry)
|
||||
return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE;
|
||||
|
||||
if(limit_count > limitEntry->maxCount)
|
||||
return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE; // attempt add too many limit category items (gems)
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
return EQUIP_ERR_OK;
|
||||
}
|
||||
|
||||
+5
-1
@@ -1084,7 +1084,8 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
bool HasItemCount( uint32 item, uint32 count, bool inBankAlso = false ) const;
|
||||
bool HasItemFitToSpellReqirements(SpellEntry const* spellInfo, Item const* ignoreItem = NULL);
|
||||
bool CanNoReagentCast(SpellEntry const* spellInfo) const;
|
||||
Item* GetItemOrItemWithGemEquipped( uint32 item ) 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 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
|
||||
@@ -1102,6 +1103,9 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
uint8 CanStoreItems( Item **pItem,int count) const;
|
||||
uint8 CanEquipNewItem( uint8 slot, uint16 &dest, uint32 item, bool swap ) const;
|
||||
uint8 CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading = true ) const;
|
||||
|
||||
uint8 CanEquipUniqueItem( Item * pItem, uint8 except_slot = NULL_SLOT, uint32 limit_count = 1 ) const;
|
||||
uint8 CanEquipUniqueItem( ItemPrototype const* itemProto, uint8 except_slot = NULL_SLOT, uint32 limit_count = 1 ) const;
|
||||
uint8 CanUnequipItems( uint32 item, uint32 count ) const;
|
||||
uint8 CanUnequipItem( uint16 src, bool swap ) const;
|
||||
uint8 CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, Item *pItem, bool swap, bool not_loading = true ) const;
|
||||
|
||||
Reference in New Issue
Block a user