rendered paste bodyIndex: src/game/Bag.cpp===================================================================--- src/game/Bag.cpp (revision 3677)+++ src/game/Bag.cpp (working copy)@@ -219,6 +219,17 @@ if( pItem && pItem != eItem && pItem->GetEntry() == item ) count += pItem->GetCount(); }++ if(eItem && eItem->GetProto()->GemProperties)+ {+ for(uint32 i=0; i < ContainerSlots; i++)+ {+ pItem = m_bagslot[i];+ if( pItem && pItem != eItem && pItem->GetProto()->Socket[0].Color )+ count += pItem->GetGemCountWithID(item);+ }+ }+ return count; } Index: src/game/Item.cpp===================================================================--- src/game/Item.cpp (revision 3677)+++ src/game/Item.cpp (working copy)@@ -168,6 +168,7 @@ m_container = NULL; m_lootGenerated = false; mb_in_trade = false;+ forcenextenchant = false; } bool Item::Create( uint32 guidlow, uint32 itemid, Player* owner)@@ -964,3 +965,62 @@ SetUInt32Value(ITEM_FIELD_ENCHANTMENT+slot*3+x,0); SetState(ITEM_CHANGED); }++bool Item::GemsFitSockets() const+{+ bool fits = true;+ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)+ {+ uint8 SocketColor = GetProto()->Socket[enchant_slot-SOCK_ENCHANTMENT_SLOT].Color;++ uint32 enchant_id = GetEchantmentId(EnchantmentSlot(enchant_slot));+ if(!enchant_id)+ {+ if(SocketColor) fits &= false;+ continue;+ }++ SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);+ if(!enchantEntry)+ {+ if(SocketColor) fits &= false;+ continue;+ }++ uint8 GemColor = 0;++ uint32 gemid = enchantEntry->GemID;+ if(gemid)+ {+ ItemPrototype const* gemProto = sItemStorage.LookupEntry<ItemPrototype>(gemid);+ if(gemProto)+ {+ GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gemProto->GemProperties);+ if(gemProperty)+ GemColor = gemProperty->color;+ }+ }++ fits &= (GemColor & SocketColor) ? true : false;+ }+ return fits;+}++uint8 Item::GetGemCountWithID(uint32 GemID) const+{+ uint8 count = 0;+ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)+ {+ uint32 enchant_id = GetEchantmentId(EnchantmentSlot(enchant_slot));+ if(!enchant_id)+ continue;++ SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);+ if(!enchantEntry)+ continue;++ if(GemID == enchantEntry->GemID)+ count++;+ }+ return count;+}Index: src/game/Item.h===================================================================--- src/game/Item.h (revision 3677)+++ src/game/Item.h (working copy)@@ -197,11 +197,13 @@ bool IsInTrade() const { return mb_in_trade; } bool IsFitToSpellRequirements(SpellEntry const* spellInfo) const;+ bool GemsFitSockets() const; uint32 GetEntry() const { return GetUInt32Value(OBJECT_FIELD_ENTRY); } uint32 GetCount() const { return GetUInt32Value (ITEM_FIELD_STACK_COUNT); } void SetCount(uint32 value) { SetUInt32Value (ITEM_FIELD_STACK_COUNT, value); } uint32 GetMaxStackCount() const { return GetProto()->Stackable ? GetProto()->Stackable : 1; }+ uint8 GetGemCountWithID(uint32 GemID) const; uint8 GetSlot() const {return m_slot;} Bag *GetContainer() { return m_container; }@@ -243,6 +245,8 @@ uState = state; } + bool forcenextenchant;+ bool hasQuest(uint32 quest_id) const { ItemPrototype const *itemProto = GetProto();Index: src/game/ItemHandler.cpp===================================================================--- src/game/ItemHandler.cpp (revision 3677)+++ src/game/ItemHandler.cpp (working copy)@@ -266,7 +266,8 @@ data << uint32(0); if (pItem) {- if ((s < 3) && (pItem->GetUInt32Value(ITEM_FIELD_SOCKETS_ENCHANTMENT+s*3)))+ // SOCK_ENCHANTMENT_SLOT.. SOCK_ENCHANTMENT_SLOT+2 is gem sockets+ if ((s < 3) && (pItem->GetEchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+ s)))) { data << uint32(1); }@@ -907,63 +908,86 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recv_data) {- sLog.outDebug("Received opcode CMSG_SOCKET_ITEM");- uint64 itemguid;- uint64 gemguid[3];- uint32 gemProperty[3];+ sLog.outDebug("WORLD: CMSG_SOCKET_ITEM"); - recv_data >> itemguid >> gemguid[0] >> gemguid[1] >> gemguid[2];+ CHECK_PACKET_SIZE(recv_data,8*4); - bool propercolor[3], full[3];- Item *pItem = _player->GetItemByPos(_player->GetPosByGuid(itemguid));- if(pItem)+ uint64 guids[4];+ uint32 GemEnchants[3], OldEnchants[3];+ Item *Gems[3];+ bool SocketBonusActivated, SocketBonusToBeActivated;+++ for(int i = 0; i < 4; i++)+ recv_data >> guids[i];++ //cheat -> tried to socket same gem multiple times+ if((guids[1] && (guids[1] == guids[2] || guids[1] == guids[3])) || (guids[2] && (guids[2] == guids[3]))) + return;++ uint16 pos = _player->GetPosByGuid(guids[0]);+ Item *itemTarget = _player->GetItemByPos(pos);+ if(!itemTarget) //missing item to socket+ return;++ uint16 slot = pos & 255; //this slot is excepted when applying / removing meta gem bonus++ for(int i = 0; i < 3; i++) {- bool HasBonus = 1;- for(int s = 0; s < 3; s++)- {- if(gemguid[s])- {- Item *pGem = _player->GetItemByPos(_player->GetPosByGuid(gemguid[s]));- if(pGem)- {- gemProperty[s] = pGem->GetProto()->GemProperties;- GemPropertiesEntry const *gemInfo = sGemPropertiesStore.LookupEntry(gemProperty[s]);- if(gemInfo)- {- propercolor[s] = (gemInfo->color & pItem->GetProto()->Socket[s].Color);- if ((gemInfo->color & SOCKET_COLOR_META) & !propercolor[s])- {- // ToDo : Error message- continue;- }- pItem->SetUInt32Value(ITEM_FIELD_SOCKETS_ENCHANTMENT+s*3, gemInfo->spellitemenchantement);- _player->DestroyItem(pGem->GetBagSlot(), pGem->GetSlot(), true);- full[s] = 1;- }- }- }- else- {- gemProperty[s] = 0;- propercolor[s] = 1;- if(pItem->GetProto()->Socket[s].Color)- {- full[s]=0;- }- else- {- full[s]=1;- }- HasBonus &= full[s] & propercolor[s];- }+ pos = _player->GetPosByGuid(guids[i + 1]);+ Gems[i] = _player->GetItemByPos(pos);+ } - // Now if all full[s] are true and all propercolor[s] are true, also apply the bonus pItemProto->socketBonus- if(HasBonus)- {- pItem->SetUInt32Value(ITEM_FIELD_SOCKETS_ENCHANTMENT+3*3, pItem->GetProto()->socketBonus);- }+ GemPropertiesEntry const *GemProps[3];+ for(int i = 0; i < 3; ++i) //get geminfo from dbc storage+ {+ GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetProto()->GemProperties) : NULL;+ } - _player->_ApplyItemMods(pItem, pItem->GetSlot(), true);+ for(int i = 0; i < 3; ++i) //check for hack maybe+ {+ // tried to put gem in socket where no socket exists / tried to put normal gem in meta socket+ // tried to put meta gem in normal socket+ if( GemProps[i] && ( (!itemTarget->GetProto()->Socket[i].Color) || (itemTarget->GetProto()->Socket[i].Color == 1 && GemProps[i]->color != 1) || (itemTarget->GetProto()->Socket[i].Color != 1 && GemProps[i]->color == 1))) + return;+ }++ for(int i = 0; i < 3; ++i) //get new and old enchantments+ {+ GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0;+ OldEnchants[i] = itemTarget->GetEchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i));+ }++ SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus+ _player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item)++ //if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met++ //remove ALL enchants+ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)+ _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),false);++ for(int i = 0; i < 3; ++i)+ {+ if(GemEnchants[i])+ {+ itemTarget->SetEchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i],0,0);+ pos = _player->GetPosByGuid(guids[i + 1]);+ _player->DestroyItem((pos >> 8), (pos & 255), true ); } }++ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)+ _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),true);+ + SocketBonusToBeActivated = itemTarget->GemsFitSockets(); //current socketbonus state+ if(SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change...+ {+ _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,false);+ itemTarget->SetEchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetProto()->socketBonus : 0), 0, 0);+ _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,true);+ //it is not displayed, client has an inbuilt system to determine if the bonus is activated+ }++ _player->ToggleMetaGemsActive(slot, true); //turn on all metagems (except for target item) }Index: src/game/Player.cpp===================================================================--- src/game/Player.cpp (revision 3677)+++ src/game/Player.cpp (working copy)@@ -4974,6 +4974,9 @@ ApplyEnchantment(item, apply); + if(proto->Socket[0].Color) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items+ CorrectMetaGemEnchants(slot, apply);+ sLog.outDebug("_ApplyItemMods complete."); } @@ -6454,6 +6457,16 @@ count += pBag->GetItemCount(item,eItem); } + if(eItem && eItem->GetProto()->GemProperties)+ {+ for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)+ {+ pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );+ if( pItem && pItem != eItem && pItem->GetProto()->Socket[0].Color )+ count += pItem->GetGemCountWithID(item);+ }+ }+ return count; } @@ -6474,6 +6487,17 @@ if( pBag ) count += pBag->GetItemCount(item,eItem); }+ + if(eItem && eItem->GetProto()->GemProperties)+ {+ for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)+ {+ pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );+ if( pItem && pItem != eItem && pItem->GetProto()->Socket[0].Color )+ count += pItem->GetGemCountWithID(item);+ }+ }+ return count; } @@ -8923,6 +8947,11 @@ if(!pEnchant) return; + if(pEnchant->EnchantmentCondition && !item->forcenextenchant && !((Player*)this)->EnchantmentFitsRequirements(pEnchant->EnchantmentCondition, -1))+ return;++ item->forcenextenchant = false;+ for (int s=0; s<3; s++) { uint32 enchant_display_type = pEnchant->display_type[s];@@ -12942,6 +12971,162 @@ return m_AuraModifiers[SPELL_AURA_MOD_SHIELD_BLOCKVALUE]*(m_AuraModifiers[SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT]+100)/100; } +bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) //slot to be excluded while counting+{+ if(!enchantmentcondition)+ return true;++ SpellItemEnchantmentConditionEntry const *Condition = sSpellItemEnchantmentConditionStore.LookupEntry(enchantmentcondition);++ if(!Condition)+ return true;++ uint8 curcount[4] = {0, 0, 0, 0};++ //counting current equipped gem colors+ for(uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)+ {+ if(i == slot)+ continue;+ uint16 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );+ Item *pItem2 = GetItemByPos( pos );+ if(pItem2 && pItem2->GetProto()->Socket[0].Color)+ {+ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)+ {+ uint32 enchant_id = pItem2->GetEchantmentId(EnchantmentSlot(enchant_slot));+ if(!enchant_id)+ continue;++ SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);+ if(!enchantEntry)+ continue;++ uint32 gemid = enchantEntry->GemID;+ if(!gemid)+ continue;++ ItemPrototype const* gemProto = sItemStorage.LookupEntry<ItemPrototype>(gemid);+ if(!gemProto)+ continue;++ GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gemProto->GemProperties);+ if(!gemProperty)+ continue;++ uint8 GemColor = gemProperty->color;++ for(uint8 b = 0, tmpcolormask = 1; b < 4; b++, tmpcolormask <<= 1)+ {+ if(tmpcolormask & GemColor)+ curcount[b]++;+ }+ }+ }+ }++ bool activate = true;++ for(int i = 0; i < 5; i++)+ {+ if(!Condition->Color[i])+ continue;++ uint32 _cur_gem = curcount[Condition->Color[i] - 1];++ // if have <CompareColor> use them as count, else use <value> from Condition+ uint32 _cmp_gem = Condition->CompareColor[i] ? curcount[Condition->CompareColor[i] - 1]: Condition->Value[i];++ switch(Condition->Comparator[i]) {+ case 2: // requires less <color> than (<value> || <comparecolor>) gems+ activate &= (_cur_gem < _cmp_gem) ? true : false;+ break;+ case 3: // requires more <color> than (<value> || <comparecolor>) gems+ activate &= (_cur_gem > _cmp_gem) ? true : false;+ break;+ case 5: // requires at least <color> than (<value> || <comparecolor>) gems+ activate &= (_cur_gem >= _cmp_gem) ? true : false;+ break;+ }+ }++ sLog.outDebug("Checking Condition %u, there are %u Meta Gems, %u Red Gems, %u Yellow Gems and %u Blue Gems, Activate:%s", enchantmentcondition, curcount[0], curcount[1], curcount[2], curcount[3], activate ? "yes" : "no");++ return activate;+}+++void Player::CorrectMetaGemEnchants(uint8 exceptslot, bool apply)+{++ for(uint32 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) //cycle all equipped items+ {+ //enchants for the slot being socketed are handeled by Player::ApplyItemMods+ if(slot == exceptslot)+ continue;++ uint16 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | slot );+ Item* pItem = GetItemByPos( pos );++ if(!pItem || !pItem->GetProto()->Socket[0].Color)+ continue;++ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)+ {+ uint32 enchant_id = pItem->GetEchantmentId(EnchantmentSlot(enchant_slot));+ if(!enchant_id)+ continue;++ SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);+ if(!enchantEntry)+ continue;++ uint32 condition = enchantEntry->EnchantmentCondition;+ if(condition)+ {+ bool wasactive = EnchantmentFitsRequirements(condition, apply ? exceptslot : -1); //was enchant active with/without item?+ if(wasactive ^ EnchantmentFitsRequirements(condition, apply ? -1 : exceptslot)) //should it now be?+ {+ pItem->forcenextenchant = true;+ ApplyEnchantment(pItem,EnchantmentSlot(enchant_slot),!wasactive); //if state changed, (dis)apply enchant+ }+ }+ }+ }+}++void Player::ToggleMetaGemsActive(uint16 exceptslot, bool apply) //if false -> then toggled off if was on| if true -> toggled on if was off AND meets requirements+{+ for(int slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++) //cycle all equipped items+ {+ //enchants for the slot being socketed are handeled by WorldSession::HandleSocketOpcode(WorldPacket& recv_data)+ if(slot == exceptslot) continue;++ uint16 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | slot );+ Item *pItem = GetItemByPos( pos );++ if(!pItem || !pItem->GetProto()->Socket[0].Color) //if item has no sockets or no item is equipped go to next item+ continue;++ //cycle all (gem)enchants+ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)+ {+ uint32 enchant_id = pItem->GetEchantmentId(EnchantmentSlot(enchant_slot));+ if(!enchant_id) //if no enchant go to next enchant(slot)+ continue;++ SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);+ if(!enchantEntry)+ continue;++ //only metagems to be (de)activated, so only enchants with condition+ uint32 condition = enchantEntry->EnchantmentCondition;+ if(condition)+ ApplyEnchantment(pItem,EnchantmentSlot(enchant_slot), apply);+ }+ }+}+ bool Player::DropBattleGroundFlag() { if(InBattleGround())Index: src/game/Player.h===================================================================--- src/game/Player.h (revision 3677)+++ src/game/Player.h (working copy)@@ -1182,6 +1182,9 @@ void _ApplyAllItemMods(); void _ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply); void _ApplyAmmoBonuses(bool apply);+ bool EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot);+ void ToggleMetaGemsActive(uint16 exceptslot, bool apply);+ void CorrectMetaGemEnchants(uint8 slot, bool apply); void InitDataForForm(); void CastItemEquipSpell(Item *item);Index: src/game/UpdateFields.h===================================================================--- src/game/UpdateFields.h (revision 3677)+++ src/game/UpdateFields.h (working copy)@@ -46,7 +46,6 @@ ITEM_FIELD_SPELL_CHARGES_04 = OBJECT_END + 0x0E, ITEM_FIELD_FLAGS = OBJECT_END + 0x0F, // Size:1 ITEM_FIELD_ENCHANTMENT = OBJECT_END + 0x10, // Size: 33 = (temp+perm+sockets*3+bonus+temp2*2+property*3)*3- ITEM_FIELD_SOCKETS_ENCHANTMENT = OBJECT_END + 0x16, // include (3 slots) * 3 = 9 ITEM_FIELD_PROPERTY_SEED = OBJECT_END + 0x31, // Size:1 ITEM_FIELD_RANDOM_PROPERTIES_ID = OBJECT_END + 0x32, // Size:1 ITEM_FIELD_ITEM_TEXT_ID = OBJECT_END + 0x33, // Size:1