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; ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(enchantEntry->GemID); if (!gemProto) continue; if (gemProto->ItemLimitCategory == limitCategory) ++count; } return count; }
bool Item::GemsFitSockets() const { bool fits = true; 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; uint32 enchant_id = GetEnchantmentId(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::GetJewelcraftingGemCount() 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->RequiredSkill == SKILL_JEWELCRAFTING) ++count; } return count; }
bool Item::GemsFitSockets() const { for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) { uint8 SocketColor = GetTemplate()->Socket[enchant_slot-SOCK_ENCHANTMENT_SLOT].Color; if (!SocketColor) // no socket slot continue; uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot)); if (!enchant_id) // no gems on this socket return false; SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id); if (!enchantEntry) // invalid gem id on this socket return false; uint8 GemColor = 0; uint32 gemid = enchantEntry->GemID; if (gemid) { ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemid); if (gemProto) { GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gemProto->GemProperties); if (gemProperty) GemColor = gemProperty->color; } } if (!(GemColor & SocketColor)) // bad gem color on this socket return false; } return true; }
bool Item::IsBoundByEnchant() const { // Check all enchants for soulbound for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot) { uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot)); if (!enchant_id) continue; if (enchant_slot == TRANSMOGRIFY_ENCHANTMENT_SLOT) return true; if (enchant_slot > PRISMATIC_ENCHANTMENT_SLOT && enchant_slot < PROP_ENCHANTMENT_SLOT_0) continue; SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id); if (!enchantEntry) continue; if (enchantEntry->slot & ENCHANTMENT_CAN_SOULBOUND) return true; } return false; }
void Item::SaveToDB(SQLTransaction& trans) { bool isInTransaction = !(trans.null()); if (!isInTransaction) trans = CharacterDatabase.BeginTransaction(); uint32 guid = GetGUIDLow(); switch (uState) { case ITEM_NEW: case ITEM_CHANGED: { uint8 index = 0; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(uState == ITEM_NEW ? CHAR_REP_ITEM_INSTANCE : CHAR_UPD_ITEM_INSTANCE); stmt->setUInt32( index, GetEntry()); stmt->setUInt32(++index, GUID_LOPART(GetOwnerGUID())); stmt->setUInt32(++index, GUID_LOPART(GetUInt64Value(ITEM_FIELD_CREATOR))); stmt->setUInt32(++index, GUID_LOPART(GetUInt64Value(ITEM_FIELD_GIFTCREATOR))); stmt->setUInt32(++index, GetCount()); stmt->setUInt32(++index, GetUInt32Value(ITEM_FIELD_DURATION)); std::ostringstream ssSpells; for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) ssSpells << GetSpellCharges(i) << ' '; stmt->setString(++index, ssSpells.str()); stmt->setUInt32(++index, GetUInt32Value(ITEM_FIELD_FLAGS)); std::ostringstream ssEnchants; for (uint8 i = 0; i < MAX_ENCHANTMENT_SLOT; ++i) { ssEnchants << GetEnchantmentId(EnchantmentSlot(i)) << ' '; ssEnchants << GetEnchantmentDuration(EnchantmentSlot(i)) << ' '; ssEnchants << GetEnchantmentCharges(EnchantmentSlot(i)) << ' '; } stmt->setString(++index, ssEnchants.str()); stmt->setInt16 (++index, GetItemRandomPropertyId()); stmt->setUInt16(++index, GetUInt32Value(ITEM_FIELD_DURABILITY)); stmt->setUInt32(++index, GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME)); stmt->setString(++index, m_text); stmt->setUInt32(++index, guid); trans->Append(stmt); if ((uState == ITEM_CHANGED) && HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GIFT_OWNER); stmt->setUInt32(0, GUID_LOPART(GetOwnerGUID())); stmt->setUInt32(1, guid); trans->Append(stmt); } break; } case ITEM_REMOVED: { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); stmt->setUInt32(0, guid); trans->Append(stmt); if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT); stmt->setUInt32(0, guid); trans->Append(stmt); } if (!isInTransaction) CharacterDatabase.CommitTransaction(trans); delete this; return; } case ITEM_UNCHANGED: break; } SetState(ITEM_UNCHANGED); if (!isInTransaction) CharacterDatabase.CommitTransaction(trans); }
void WorldSession::HandleSocketOpcode(WorldPacket& recv_data) { sLog.outDebug("WORLD: CMSG_SOCKET_GEMS"); CHECK_PACKET_SIZE(recv_data,8*4); 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]; if(!guids[0]) return; //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; Item *itemTarget = _player->GetItemByGuid(guids[0]); if(!itemTarget) //missing item to socket return; //this slot is excepted when applying / removing meta gem bonus uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : NULL_SLOT; for(int i = 0; i < 3; i++) Gems[i] = guids[i + 1] ? _player->GetItemByGuid(guids[i + 1]) : NULL; 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; } 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 == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META || itemTarget->GetProto()->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META ) ) return; } for(int i = 0; i < 3; ++i) //get new and old enchantments { GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0; OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i)); } // check unique-equipped conditions for(int i = 0; i < 3; ++i) { if (Gems[i] && (Gems[i]->GetProto()->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 < 3; ++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 < 3; ++j) { if (OldEnchants[j]) { SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]); if(!enchantEntry) continue; if ((enchantEntry->GemID == Gems[i]->GetProto()->ItemId) && (i != j)) { _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL ); return; } } } } } 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->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i],0,0); if(Item* guidItem = _player->GetItemByGuid(guids[i + 1])) _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), 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->SetEnchantment(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) }
void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) { TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); ByteBuffer itemData(7*2 + 7*4 + 3*4 + 3*4 + 1); uint8 count = 0; for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) if (view_trade->GetItem(TradeSlots(i))) ++count; WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 4*6 + 8 + 1 + 3 + count * 70); data << uint32(0); // this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) data << uint32(0); // unk 2 data << uint64(view_trade->GetMoney()); // trader gold data << uint32(view_trade->GetSpell()); // spell casted on lowest slot item data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = next field in most cases data << uint32(0); // unk 5 data << uint8(trader_data); // 1 means traders data, 0 means own data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = prev field in most cases data.WriteBits(count, 22); for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { Item* item = view_trade->GetItem(TradeSlots(i)); if (!item) continue; ObjectGuid giftCreatorGuid = item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR); ObjectGuid creatorGuid = item->GetUInt64Value(ITEM_FIELD_CREATOR); data.WriteBit(giftCreatorGuid[7]); data.WriteBit(giftCreatorGuid[1]); bool notWrapped = data.WriteBit(!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)); data.WriteBit(giftCreatorGuid[3]); if (notWrapped) { data.WriteBit(creatorGuid[7]); data.WriteBit(creatorGuid[1]); data.WriteBit(creatorGuid[4]); data.WriteBit(creatorGuid[6]); data.WriteBit(creatorGuid[2]); data.WriteBit(creatorGuid[3]); data.WriteBit(creatorGuid[5]); data.WriteBit(item->GetTemplate()->LockID != 0); data.WriteBit(creatorGuid[0]); itemData.WriteByteSeq(creatorGuid[1]); itemData << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS /*3*/; ++enchant_slot) itemData << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); itemData << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); itemData.WriteByteSeq(creatorGuid[6]); itemData.WriteByteSeq(creatorGuid[2]); itemData.WriteByteSeq(creatorGuid[7]); itemData.WriteByteSeq(creatorGuid[4]); itemData << uint32(item->GetEnchantmentId(REFORGE_ENCHANTMENT_SLOT)); itemData << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); itemData << uint32(item->GetItemRandomPropertyId()); itemData.WriteByteSeq(creatorGuid[3]); itemData << uint32(0); // unk7 itemData.WriteByteSeq(creatorGuid[0]); itemData << uint32(item->GetSpellCharges()); itemData << uint32(item->GetItemSuffixFactor()); itemData.WriteByteSeq(creatorGuid[5]); } data.WriteBit(giftCreatorGuid[6]); data.WriteBit(giftCreatorGuid[4]); data.WriteBit(giftCreatorGuid[2]); data.WriteBit(giftCreatorGuid[0]); data.WriteBit(giftCreatorGuid[5]); itemData.WriteByteSeq(giftCreatorGuid[6]); itemData.WriteByteSeq(giftCreatorGuid[1]); itemData.WriteByteSeq(giftCreatorGuid[7]); itemData.WriteByteSeq(giftCreatorGuid[4]); itemData << uint32(item->GetTemplate()->ItemId); itemData.WriteByteSeq(giftCreatorGuid[0]); itemData << uint32(item->GetCount()); itemData.WriteByteSeq(giftCreatorGuid[5]); itemData << uint8(i); itemData.WriteByteSeq(giftCreatorGuid[2]); itemData.WriteByteSeq(giftCreatorGuid[3]); } data.FlushBits(); data.append(itemData); SendPacket(&data); }
void WorldSession::SendUpdateTrade(bool trader_state /*= true*/) { TradeData* view_trade = trader_state ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, (100)); // guess size data << uint32(0); // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) data << uint32(0); // unk 2 data << uint64(view_trade->GetMoney()); // trader gold data << uint32(view_trade->GetSpell()); // spell casted on lowest slot item data << uint32(TRADE_SLOT_COUNT); // trade slots count/number? data << uint32(0); // unk 5 data << uint8(trader_state ? 1 : 0); // send trader or own trade windows state (last need for proper show spell apply to non-trade slot) data << uint32(TRADE_SLOT_COUNT); // trade slots count/number? uint8 itemCount = 0; for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) if (Item* item = view_trade->GetItem(TradeSlots(i))) ++itemCount; data.WriteBits(itemCount, 22); for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { if (Item* item = view_trade->GetItem(TradeSlots(i))) { ObjectGuid creatorGuid = item->GetGuidValue(ITEM_FIELD_CREATOR); ObjectGuid giftCreatorGuid = item->GetGuidValue(ITEM_FIELD_GIFTCREATOR); data.WriteGuidMask<7, 1>(giftCreatorGuid); data.WriteBit(!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED)); data.WriteGuidMask<3>(giftCreatorGuid); if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED)) { data.WriteGuidMask<7, 1, 4, 6, 2, 3, 5>(creatorGuid); data.WriteBit(item->GetProto()->LockID && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_UNLOCKED)); data.WriteGuidMask<0>(creatorGuid); } data.WriteGuidMask<6, 4, 2, 0, 5>(giftCreatorGuid); } } for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { if (Item* item = view_trade->GetItem(TradeSlots(i))) { ObjectGuid creatorGuid = item->GetGuidValue(ITEM_FIELD_CREATOR); ObjectGuid giftCreatorGuid = item->GetGuidValue(ITEM_FIELD_GIFTCREATOR); if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED)) { data.WriteGuidBytes<1>(creatorGuid); data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot) data << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); data.WriteGuidBytes<6, 2, 7, 4>(creatorGuid); data << uint32(item->GetEnchantmentId(REFORGE_ENCHANTMENT_SLOT)); // reforge Id data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); data << uint32(item->GetItemRandomPropertyId()); data.WriteGuidBytes<3>(creatorGuid); data << uint32(0); // unk data.WriteGuidBytes<0>(creatorGuid); data << uint32(item->GetSpellCharges()); // charges data << uint32(item->GetItemSuffixFactor()); data.WriteGuidBytes<5>(creatorGuid); } data.WriteGuidBytes<6, 1, 7, 4>(giftCreatorGuid); data << uint32(item->GetProto()->ItemId); // entry data.WriteGuidBytes<0>(giftCreatorGuid); data << uint32(item->GetCount()); // stack count data.WriteGuidBytes<5>(giftCreatorGuid); data << uint8(i); // slot id data.WriteGuidBytes<2, 3>(giftCreatorGuid); } } SendPacket(&data); }
void HandleAfterHit() { if (_stackAmount < 5) return; Player* player = GetCaster()->ToPlayer(); if (Unit* target = GetHitUnit()) { Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); if (item == GetCastItem()) item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); if (!item) return; // item combat enchantments for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot) { SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(EnchantmentSlot(slot))); if (!enchant) continue; for (uint8 s = 0; s < 3; ++s) { if (enchant->type[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) continue; SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(enchant->spellid[s]); if (!spellInfo) { sLog->outError("Player::CastItemCombatSpell Enchant %i, player (Name: %s, GUID: %u) cast unknown spell %i", enchant->ID, player->GetName(), player->GetGUIDLow(), enchant->spellid[s]); continue; } // Proc only rogue poisons if (spellInfo->SpellFamilyName != SPELLFAMILY_ROGUE || spellInfo->Dispel != DISPEL_POISON) continue; // Do not reproc deadly if (spellInfo->SpellFamilyFlags.IsEqual(0x10000, 0x80000, 0)) continue; if (spellInfo->IsPositive()) player->CastSpell(player, enchant->spellid[s], true, item); else player->CastSpell(target, enchant->spellid[s], true, item); } } } }
void WorldSession::HandleSocketOpcode(WorldPacket& recv_data) { DEBUG_LOG("WORLD: CMSG_SOCKET_GEMS"); ObjectGuid itemGuid; ObjectGuid gemGuids[MAX_GEM_SOCKETS]; recv_data >> itemGuid; if (!itemGuid.IsItem()) return; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) recv_data >> gemGuids[i]; // cheat -> tried to socket same gem multiple times for (int i = 0; i < MAX_GEM_SOCKETS; ++i) { ObjectGuid gemGuid = gemGuids[i]; if (!gemGuid) continue; if (!gemGuid.IsItem()) return; for (int j = i + 1; j < MAX_GEM_SOCKETS; ++j) if (gemGuids[j] == gemGuid) return; } Item* itemTarget = _player->GetItemByGuid(itemGuid); if (!itemTarget) // missing item to socket return; ItemPrototype const* itemProto = itemTarget->GetProto(); if (!itemProto) return; // this slot is excepted when applying / removing meta gem bonus uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT); Item* Gems[MAX_GEM_SOCKETS]; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) Gems[i] = gemGuids[i] ? _player->GetItemByGuid(gemGuids[i]) : NULL; GemPropertiesEntry const* GemProps[MAX_GEM_SOCKETS]; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) // get geminfo from dbc storage GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetProto()->GemProperties) : NULL; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) // check for hack maybe { if (!GemProps[i]) continue; // tried to put gem in socket where no socket exists if (!itemProto->Socket[i].Color) return; // tried to put normal gem in meta socket if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META) return; // tried to put meta gem in normal socket if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META) return; } uint32 GemEnchants[MAX_GEM_SOCKETS]; uint32 OldEnchants[MAX_GEM_SOCKETS]; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) // get new and old enchantments { GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0; OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + i)); } // check unique-equipped conditions for (int i = 0; i < MAX_GEM_SOCKETS; ++i) { 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_FLAG_UNIQUE_EQUIPPED) { for (int j = 0; j < MAX_GEM_SOCKETS; ++j) { if (i == j) // skip self continue; 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; } } } } } // for equipped item check all equipment for duplicate equipped gems if (itemTarget->IsEquipped()) { if (InventoryResult res = _player->CanEquipUniqueItem(Gems[i], slot)) { _player->SendEquipError(res, itemTarget, NULL); return; } } } bool 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 + MAX_GEM_SOCKETS; ++enchant_slot) _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), false); for (int i = 0; i < MAX_GEM_SOCKETS; ++i) { if (GemEnchants[i]) { itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + i), GemEnchants[i], 0, 0); if (Item* guidItem = gemGuids[i] ? _player->GetItemByGuid(gemGuids[i]) : NULL) _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true); } } for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot) _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), true); bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();// current socketbonus state if (SocketBonusActivated != SocketBonusToBeActivated) // if there was a change... { _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, false); itemTarget->SetEnchantment(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) }
int32 Item::GetReforgableStat(ItemModType statType) const { ItemTemplate const* proto = GetTemplate(); for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) if (proto->ItemStat[i].ItemStatType == statType) return proto->ItemStat[i].ItemStatValue; int32 randomPropId = GetItemRandomPropertyId(); if (!randomPropId) return 0; if (randomPropId < 0) { ItemRandomSuffixEntry const* randomSuffix = sItemRandomSuffixStore.LookupEntry(-randomPropId); if (!randomSuffix) return 0; for (uint32 e = PROP_ENCHANTMENT_SLOT_0; e <= PROP_ENCHANTMENT_SLOT_4; ++e) if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(GetEnchantmentId(EnchantmentSlot(e)))) for (uint32 f = 0; f < MAX_ITEM_ENCHANTMENT_EFFECTS; ++f) if (enchant->type[f] == ITEM_ENCHANTMENT_TYPE_STAT && enchant->spellid[f] == statType) for (int k = 0; k < 5; ++k) if (randomSuffix->enchant_id[k] == enchant->ID) return int32((randomSuffix->prefix[k] * GetItemSuffixFactor()) / 10000); } else { ItemRandomPropertiesEntry const* randomProp = sItemRandomPropertiesStore.LookupEntry(randomPropId); if (!randomProp) return 0; for (uint32 e = PROP_ENCHANTMENT_SLOT_0; e <= PROP_ENCHANTMENT_SLOT_4; ++e) if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(GetEnchantmentId(EnchantmentSlot(e)))) for (uint32 f = 0; f < MAX_ITEM_ENCHANTMENT_EFFECTS; ++f) if (enchant->type[f] == ITEM_ENCHANTMENT_TYPE_STAT && enchant->spellid[f] == statType) for (int k = 0; k < MAX_ITEM_ENCHANTMENT_EFFECTS; ++k) if (randomProp->enchant_id[k] == enchant->ID) return int32(enchant->amount[k]); } return 0; }
void WorldSession::HandleSocketGems(WorldPackets::Item::SocketGems& socketGems) { if (!socketGems.ItemGuid) return; //cheat -> tried to socket same gem multiple times if ((!socketGems.GemItem[0].IsEmpty() && (socketGems.GemItem[0] == socketGems.GemItem[1] || socketGems.GemItem[0] == socketGems.GemItem[2])) || (!socketGems.GemItem[1].IsEmpty() && (socketGems.GemItem[1] == socketGems.GemItem[2]))) return; Item* itemTarget = _player->GetItemByGuid(socketGems.ItemGuid); if (!itemTarget) //missing item to socket return; ItemTemplate const* itemProto = itemTarget->GetTemplate(); if (!itemProto) return; //this slot is excepted when applying / removing meta gem bonus uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT); Item* gems[MAX_GEM_SOCKETS]; memset(gems, 0, sizeof(gems)); ItemDynamicFieldGems gemData[MAX_GEM_SOCKETS]; memset(gemData, 0, sizeof(gemData)); GemPropertiesEntry const* gemProperties[MAX_GEM_SOCKETS]; memset(gemProperties, 0, sizeof(gemProperties)); ItemDynamicFieldGems const* oldGemData[MAX_GEM_SOCKETS]; memset(oldGemData, 0, sizeof(oldGemData)); for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) { if (Item* gem = _player->GetItemByGuid(socketGems.GemItem[i])) { gems[i] = gem; gemData[i].ItemId = gem->GetEntry(); gemData[i].Context = gem->GetUInt32Value(ITEM_FIELD_CONTEXT); for (std::size_t b = 0; b < gem->GetDynamicValues(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS).size() && b < 16; ++b) gemData[i].BonusListIDs[b] = gem->GetDynamicValue(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS, b); gemProperties[i] = sGemPropertiesStore.LookupEntry(gem->GetTemplate()->GetGemProperties()); } oldGemData[i] = itemTarget->GetGem(i); } // Find first prismatic socket uint32 firstPrismatic = 0; while (firstPrismatic < MAX_GEM_SOCKETS && itemTarget->GetSocketColor(firstPrismatic)) ++firstPrismatic; for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe { if (!gemProperties[i]) continue; // tried to put gem in socket where no socket exists (take care about prismatic sockets) if (!itemTarget->GetSocketColor(i)) { // no prismatic socket if (!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)) return; if (i != firstPrismatic) return; } // Gem must match socket color if (SocketColorToGemTypeMask[itemTarget->GetSocketColor(i)] != gemProperties[i]->Type) { // unless its red, blue, yellow or prismatic if (!(SocketColorToGemTypeMask[itemTarget->GetSocketColor(i)] & SOCKET_COLOR_PRISMATIC) || !(gemProperties[i]->Type & SOCKET_COLOR_PRISMATIC)) return; } } // check unique-equipped conditions for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) { if (!gems[i]) continue; // continue check for case when attempt add 2 similar unique equipped gems in one item. ItemTemplate const* iGemProto = gems[i]->GetTemplate(); // unique item (for new and already placed bit removed enchantments if (iGemProto->GetFlags() & ITEM_FLAG_UNIQUE_EQUIPPABLE) { for (uint32 j = 0; j < MAX_GEM_SOCKETS; ++j) { if (i == j) // skip self continue; if (gems[j]) { if (iGemProto->GetId() == gems[j]->GetEntry()) { _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); return; } } else if (oldGemData[j]) { if (iGemProto->GetId() == oldGemData[j]->ItemId) { _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); return; } } } } // unique limit type item int32 limit_newcount = 0; if (iGemProto->GetItemLimitCategory()) { if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->GetItemLimitCategory())) { // NOTE: limitEntry->mode is not checked because if item has limit then it is applied in equip case for (int j = 0; j < MAX_GEM_SOCKETS; ++j) { if (gems[j]) { // new gem if (iGemProto->GetItemLimitCategory() == gems[j]->GetTemplate()->GetItemLimitCategory()) ++limit_newcount; } else if (oldGemData[j]) { // existing gem if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(oldGemData[j]->ItemId)) if (iGemProto->GetItemLimitCategory() == jProto->GetItemLimitCategory()) ++limit_newcount; } } if (limit_newcount > 0 && uint32(limit_newcount) > limitEntry->Quantity) { _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 (InventoryResult res = _player->CanEquipUniqueItem(gems[i], slot, std::max(limit_newcount, 0))) { _player->SendEquipError(res, itemTarget, NULL); return; } } } bool 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 mods - gem can change item level if (itemTarget->IsEquipped()) _player->_ApplyItemMods(itemTarget, itemTarget->GetSlot(), false); for (uint16 i = 0; i < MAX_GEM_SOCKETS; ++i) { if (gems[i]) { uint32 gemScalingLevel = _player->getLevel(); if (uint32 fixedLevel = gems[i]->GetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL)) gemScalingLevel = fixedLevel; itemTarget->SetGem(i, &gemData[i], gemScalingLevel); if (gemProperties[i] && gemProperties[i]->EnchantID) itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + i), gemProperties[i]->EnchantID, 0, 0, _player->GetGUID()); uint32 gemCount = 1; _player->DestroyItemCount(gems[i], gemCount, true); } } if (itemTarget->IsEquipped()) _player->_ApplyItemMods(itemTarget, itemTarget->GetSlot(), true); if (Item* childItem = _player->GetChildItemByGuid(itemTarget->GetChildItem())) { if (childItem->IsEquipped()) _player->_ApplyItemMods(childItem, childItem->GetSlot(), false); childItem->CopyArtifactDataFromParent(itemTarget); if (childItem->IsEquipped()) _player->_ApplyItemMods(childItem, childItem->GetSlot(), true); } bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change... { _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, false); itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetTemplate()->GetSocketBonus() : 0), 0, 0, _player->GetGUID()); _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) _player->RemoveTradeableItem(itemTarget); itemTarget->ClearSoulboundTradeable(_player); // clear tradeable flag itemTarget->SendUpdateSockets(); }
void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) { TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 1+4+4+4+4+4+7*(1+4+4+4+4+8+4+4+4+4+8+4+4+4+4+4+4)); data << uint32(0); data << uint32(0); data << uint8(1); data << uint32(0); data << uint32(0); data << uint32(0); // trade ID? has to match what we sent in TRADE_STATUS for TRADE_STATUS_OPEN_WINDOW data << uint32(TRADE_SLOT_COUNT); // slot count data << uint64(view_trade->GetMoney()); // trade money data << uint32(0); for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { uint32 id = 0; if (Item* item = view_trade->GetItem(TradeSlots(i))) { uint32 id = item->GetTemplate()->ItemId; data << uint32(0); data << uint64(item->GetUInt64Value(ITEM_FIELD_CREATOR)); // Creator GUID data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); // Permanent Enchantment data << uint32(id); data << uint32(item->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+1))); // First gem socket enchant data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); // Current Durability data << uint32(0); data << uint8(0); // If 1, then the item wont display any sockets, even if it has them data << uint64(0); data << uint32(0); data << uint8(i); // trade slot number data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); // Max durability data << uint32(item->GetCount()); // Stack count data << uint32(0); data << uint32(item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)); // Temporal enchantment data << uint32(item->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+2))); // Second socket gem data << uint32(item->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+3))); // Third socket gem data << uint32(0); } else { data << uint32(0); data << uint64(0); data << uint32(0); data << uint32(id); data << uint32(0); data << uint32(0); data << uint32(0); data << uint8(0); data << uint64(0); data << uint32(0); data << uint8(i); // trade slot number data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); } } SendPacket(&data); }
void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) { TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 1+4+4+4+4+4+7*(1+4+4+4+4+8+4+4+4+4+8+4+4+4+4+4+4)); data << uint32(0); data << uint32(0); data << uint8(1); data << uint32(0); data << uint32(0); data << uint32(0); // trade ID? has to match what we sent in TRADE_STATUS for TRADE_STATUS_OPEN_WINDOW data << uint32(TRADE_SLOT_COUNT); // slot count data << uint64(view_trade->GetMoney()); // trade money data << uint32(0); // old structure. meaning of new structure fields has to be researched /*data << uint8(trader_data); // 1 means traders data, 0 means own data << uint32(0); // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = next field in most cases data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = prev field in most cases data << uint32(view_trade->GetMoney()); // trader gold data << uint32(view_trade->GetSpell()); // spell casted on lowest slot item*/ for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { uint32 id = 0; if (Item* item = view_trade->GetItem(TradeSlots(i))) { uint32 id = item->GetTemplate()->ItemId; data << uint32(0); data << uint64(item->GetUInt64Value(ITEM_FIELD_CREATOR)); // Creator GUID data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); // Permanent Enchantment data << uint32(id); data << uint32(item->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+1))); // First gem socket enchant data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); // Current Durability data << uint32(0); data << uint8(0); // If 1, then the item wont display any sockets, even if it has them data << uint64(0); data << uint32(0); data << uint8(i); // trade slot number data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); // Max durability data << uint32(item->GetCount()); // Stack count data << uint32(0); data << uint32(item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)); // Temporal enchantment data << uint32(item->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+2))); // Second socket gem data << uint32(item->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+3))); // Third socket gem data << uint32(0); } else data << uint32(0); data << uint64(0); data << uint32(0); data << uint32(id); data << uint32(0); data << uint32(0); data << uint32(0); data << uint8(0); data << uint64(0); data << uint32(0); data << uint8(i); // trade slot number data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); // old structure /*data << uint8(i); // trade slot number, if not specified, then end of packet if (Item* item = view_trade->GetItem(TradeSlots(i))) { data << uint32(item->GetTemplate()->ItemId); // entry data << uint32(item->GetTemplate()->DisplayInfoID);// display id data << uint32(item->GetCount()); // stack count // wrapped: hide stats but show giftcreator name data << uint32(item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED) ? 1 : 0); data << uint64(item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)); // perm. enchantment and gems data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) data << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); // creator data << uint64(item->GetUInt64Value(ITEM_FIELD_CREATOR)); data << uint32(item->GetSpellCharges()); // charges data << uint32(item->GetItemSuffixFactor()); // SuffixFactor data << uint32(item->GetItemRandomPropertyId());// random properties id data << uint32(item->GetTemplate()->LockID); // lock id // max durability data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); // durability data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); } else { for (uint8 j = 0; j < 18; ++j) data << uint32(0); }*/ } SendPacket(&data); }
void WorldSession::SendUpdateTrade() { Item *item = NULL; if( !_player || !_player->pTrader ) return; // reset trade status if (_player->acceptTrade) { _player->acceptTrade = false; SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); } if (_player->pTrader->acceptTrade) { _player->pTrader->acceptTrade = false; _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); } WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, (100)); // guess size data << (uint8 ) 1; // can be different (only seen 0 and 1) data << (uint32) 0; // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) data << (uint32) TRADE_SLOT_COUNT; // trade slots count/number?, = next field in most cases data << (uint32) TRADE_SLOT_COUNT; // trade slots count/number?, = prev field in most cases data << (uint32) _player->pTrader->tradeGold; // trader gold data << (uint32) 0; // spell casted on lowest slot item for(uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { item = (_player->pTrader->tradeItems[i] != NULL_SLOT ? _player->pTrader->GetItemByPos( _player->pTrader->tradeItems[i] ) : NULL); data << (uint8) i; // trade slot number, if not specified, then end of packet if(item) { data << (uint32) item->GetProto()->ItemId; // entry // display id data << (uint32) item->GetProto()->DisplayInfoID; // stack count data << (uint32) item->GetUInt32Value(ITEM_FIELD_STACK_COUNT); data << (uint32) 0; // probably gift=1, created_by=0? // gift creator data << (uint64) item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR); data << (uint32) item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT); for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) data << (uint32) item->GetEnchantmentId(EnchantmentSlot(enchant_slot)); // creator data << (uint64) item->GetUInt64Value(ITEM_FIELD_CREATOR); data << (uint32) item->GetSpellCharges(); // charges data << (uint32) item->GetItemSuffixFactor(); // SuffixFactor // random properties id data << (uint32) item->GetItemRandomPropertyId(); data << (uint32) item->GetProto()->LockID; // lock id // max durability data << (uint32) item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); // durability data << (uint32) item->GetUInt32Value(ITEM_FIELD_DURABILITY); } else { for(uint8 j = 0; j < 18; j++) data << uint32(0); } } SendPacket(&data); }
void WorldSession::HandleSocketOpcode(WorldPacket& recvData) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SOCKET_GEMS"); uint64 item_guid; uint64 gem_guids[MAX_GEM_SOCKETS]; recvData >> item_guid; if (!item_guid) return; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) recvData >> gem_guids[i]; //cheat -> tried to socket same gem multiple times if ((gem_guids[0] && (gem_guids[0] == gem_guids[1] || gem_guids[0] == gem_guids[2])) || (gem_guids[1] && (gem_guids[1] == gem_guids[2]))) return; Item* itemTarget = _player->GetItemByGuid(item_guid); if (!itemTarget) //missing item to socket return; ItemTemplate const* itemProto = itemTarget->GetTemplate(); if (!itemProto) return; //this slot is excepted when applying / removing meta gem bonus uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT); Item* Gems[MAX_GEM_SOCKETS]; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) Gems[i] = gem_guids[i] ? _player->GetItemByGuid(gem_guids[i]) : NULL; GemPropertiesEntry const* GemProps[MAX_GEM_SOCKETS]; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get geminfo from dbc storage GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetTemplate()->GemProperties) : NULL; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe { if (!GemProps[i]) continue; // tried to put gem in socket where no socket exists (take care about prismatic sockets) if (!itemProto->Socket[i].Color) { // no prismatic socket if (!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)) return; // not first not-colored (not normaly used) socket if (i != 0 && !itemProto->Socket[i-1].Color && (i+1 >= MAX_GEM_SOCKETS || itemProto->Socket[i+1].Color)) return; // ok, this is first not colored socket for item with prismatic socket } // tried to put normal gem in meta socket if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META) return; // tried to put meta gem in normal socket if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META) return; } uint32 GemEnchants[MAX_GEM_SOCKETS]; uint32 OldEnchants[MAX_GEM_SOCKETS]; for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get new and old enchantments { GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0; OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i)); } // check unique-equipped conditions for (int i = 0; i < MAX_GEM_SOCKETS; ++i) { if (!Gems[i]) continue; // continue check for case when attempt add 2 similar unique equipped gems in one item. ItemTemplate const* iGemProto = Gems[i]->GetTemplate(); // unique item (for new and already placed bit removed enchantments if (iGemProto->Flags & ITEM_PROTO_FLAG_UNIQUE_EQUIPPED) { for (int j = 0; j < MAX_GEM_SOCKETS; ++j) { if (i == j) // skip self continue; 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)) { // NOTE: limitEntry->mode is not checked because if item has limit then it is applied in equip case for (int j = 0; j < MAX_GEM_SOCKETS; ++j) { if (Gems[j]) { // new gem if (iGemProto->ItemLimitCategory == Gems[j]->GetTemplate()->ItemLimitCategory) ++limit_newcount; } else if (OldEnchants[j]) { // existing gem if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(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 (InventoryResult res = _player->CanEquipUniqueItem(Gems[i], slot, std::max(limit_newcount, 0))) { _player->SendEquipError(res, itemTarget, NULL); return; } } } bool 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 + MAX_GEM_SOCKETS; ++enchant_slot) _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), false); for (int i = 0; i < MAX_GEM_SOCKETS; ++i) { if (GemEnchants[i]) { itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i], 0, 0); if (Item* guidItem = _player->GetItemByGuid(gem_guids[i])) _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true); } } for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), true); bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change... { _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, false); itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetTemplate()->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) _player->RemoveTradeableItem(itemTarget); itemTarget->ClearSoulboundTradeable(_player); // clear tradeable flag }
void Item::SaveToDB() { uint32 guid = GetGUIDLow(); switch (uState) { case ITEM_NEW: { std::string text = m_text; CharacterDatabase.escape_string(text); std::ostringstream ss; ss << "REPLACE INTO item_instance (guid,owner_guid,creatorGuid,giftCreatorGuid,count,duration,charges,flags,enchantments,randomPropertyId,durability,playedTime,text) VALUES ("; ss << guid << ","; ss << GUID_LOPART(GetOwnerGUID()) << ","; ss << GUID_LOPART(GetUInt64Value(ITEM_FIELD_CREATOR)) << ","; ss << GUID_LOPART(GetUInt64Value(ITEM_FIELD_GIFTCREATOR)) << ","; ss << GetCount() << ","; ss << GetUInt32Value(ITEM_FIELD_DURATION) << ",'"; for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) ss << GetSpellCharges(i) << " "; ss << "'," << GetUInt32Value(ITEM_FIELD_FLAGS) << ",'"; for (uint8 i = 0; i < MAX_ENCHANTMENT_SLOT; ++i) { ss << GetEnchantmentId(EnchantmentSlot(i)) << " "; ss << GetEnchantmentDuration(EnchantmentSlot(i)) << " "; ss << GetEnchantmentCharges(EnchantmentSlot(i)) << " "; } ss << "'," << GetItemRandomPropertyId() << ","; ss << GetUInt32Value(ITEM_FIELD_DURABILITY) << ","; ss << GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME) << ",'"; ss << text << "')"; CharacterDatabase.Execute(ss.str().c_str()); }break; case ITEM_CHANGED: { std::string text = m_text; CharacterDatabase.escape_string(text); std::ostringstream ss; ss << "UPDATE item_instance SET owner_guid = " << GUID_LOPART(GetOwnerGUID()); ss << ", creatorGuid = " << GUID_LOPART(GetUInt64Value(ITEM_FIELD_CREATOR)); ss << ", giftCreatorGuid = " << GUID_LOPART(GetUInt64Value(ITEM_FIELD_GIFTCREATOR)); ss << ", count = " << GetCount(); ss << ", duration = " << GetUInt32Value(ITEM_FIELD_DURATION); ss << ", charges = '"; for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) ss << GetSpellCharges(i) << " "; ss << "', flags = " << GetUInt32Value(ITEM_FIELD_FLAGS); ss << ", enchantments = '"; for (uint8 i = 0; i < MAX_ENCHANTMENT_SLOT; ++i) { ss << GetEnchantmentId(EnchantmentSlot(i)) << " "; ss << GetEnchantmentDuration(EnchantmentSlot(i)) << " "; ss << GetEnchantmentCharges(EnchantmentSlot(i)) << " "; } ss << "', randomPropertyId = " << GetItemRandomPropertyId(); ss << ", durability = " << GetUInt32Value(ITEM_FIELD_DURABILITY); ss << ", playedTime = " << GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME); ss << ", text = '" << text << "' WHERE guid = " << guid; CharacterDatabase.Execute(ss.str().c_str()); if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED)) CharacterDatabase.PExecute("UPDATE character_gifts SET guid = '%u' WHERE item_guid = '%u'", GUID_LOPART(GetOwnerGUID()),GetGUIDLow()); }break; case ITEM_REMOVED: { CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", guid); if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED)) CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow()); delete this; return; } case ITEM_UNCHANGED: break; } SetState(ITEM_UNCHANGED); }