Implemented limit category check for item/gem at equip or gem inserting. Author: VladimirMangos

--HG--
branch : trunk
This commit is contained in:
megamage
2009-02-15 11:58:27 -06:00
parent 419b749520
commit 97ac3aba05
10 changed files with 249 additions and 70 deletions
+25 -2
View File
@@ -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();
+1
View File
@@ -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
View File
@@ -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;
}
}
}
+7 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;