void WorldSession::HandleArtifactSetAppearance(WorldPackets::Artifact::ArtifactSetAppearance& artifactSetAppearance) { if (!_player->GetGameObjectIfCanInteractWith(artifactSetAppearance.ForgeGUID, GAMEOBJECT_TYPE_ARTIFACT_FORGE)) return; ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifactSetAppearance.ArtifactAppearanceID); if (!artifactAppearance) return; Item* artifact = _player->GetItemByGuid(artifactSetAppearance.ArtifactGUID); if (!artifact) return; ArtifactAppearanceSetEntry const* artifactAppearanceSet = sArtifactAppearanceSetStore.LookupEntry(artifactAppearance->ArtifactAppearanceSetID); if (!artifactAppearanceSet || artifactAppearanceSet->ArtifactID != artifact->GetTemplate()->GetArtifactID()) return; if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(artifactAppearance->UnlockPlayerConditionID)) if (!sConditionMgr->IsPlayerMeetingCondition(_player, playerCondition)) return; artifact->SetAppearanceModId(artifactAppearance->ItemAppearanceModifierID); artifact->SetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID, artifactAppearance->ID); artifact->SetState(ITEM_CHANGED, _player); Item* childItem = _player->GetChildItemByGuid(artifact->GetChildItem()); if (childItem) { childItem->SetAppearanceModId(artifactAppearance->ItemAppearanceModifierID); childItem->SetState(ITEM_CHANGED, _player); } if (artifact->IsEquipped()) { // change weapon appearance _player->SetVisibleItemSlot(artifact->GetSlot(), artifact); if (childItem) _player->SetVisibleItemSlot(childItem->GetSlot(), childItem); // change druid form appearance if (artifactAppearance->OverrideShapeshiftDisplayID && artifactAppearance->OverrideShapeshiftFormID && _player->GetShapeshiftForm() == ShapeshiftForm(artifactAppearance->OverrideShapeshiftFormID)) _player->RestoreDisplayId(); } }
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::HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem& autoEquipItem) { if (autoEquipItem.Inv.Items.size() != 1) { TC_LOG_ERROR("network", "HandleAutoEquipItemOpcode - Invalid itemCount (" SZFMTD ")", autoEquipItem.Inv.Items.size()); return; } TC_LOG_DEBUG("network", "HandleAutoEquipItemOpcode: receive PackSlot: %u, Slot: %u", autoEquipItem.PackSlot, autoEquipItem.Slot); Item* srcItem = _player->GetItemByPos(autoEquipItem.PackSlot, autoEquipItem.Slot); if (!srcItem) return; // only at cheat uint16 dest; InventoryResult msg = _player->CanEquipItem(NULL_SLOT, dest, srcItem, !srcItem->IsBag()); if (msg != EQUIP_ERR_OK) { _player->SendEquipError(msg, srcItem); return; } uint16 src = srcItem->GetPos(); if (dest == src) // prevent equip in same slot, only at cheat return; Item* dstItem = _player->GetItemByPos(dest); if (!dstItem) // empty slot, simple case { if (!srcItem->GetChildItem().IsEmpty()) { InventoryResult childEquipResult = _player->CanEquipChildItem(srcItem); if (childEquipResult != EQUIP_ERR_OK) { _player->SendEquipError(msg, srcItem); return; } } _player->RemoveItem(autoEquipItem.PackSlot, autoEquipItem.Slot, true); _player->EquipItem(dest, srcItem, true); if (!srcItem->GetChildItem().IsEmpty()) _player->EquipChildItem(autoEquipItem.PackSlot, autoEquipItem.Slot, srcItem); _player->AutoUnequipOffhandIfNeed(); } else // have currently equipped item, not simple case { uint8 dstbag = dstItem->GetBagSlot(); uint8 dstslot = dstItem->GetSlot(); msg = _player->CanUnequipItem(dest, !srcItem->IsBag()); if (msg != EQUIP_ERR_OK) { _player->SendEquipError(msg, dstItem); return; } if (!dstItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD)) { // check dest->src move possibility ItemPosCountVec sSrc; uint16 eSrc = 0; if (_player->IsInventoryPos(src)) { msg = _player->CanStoreItem(autoEquipItem.PackSlot, autoEquipItem.Slot, sSrc, dstItem, true); if (msg != EQUIP_ERR_OK) msg = _player->CanStoreItem(autoEquipItem.PackSlot, NULL_SLOT, sSrc, dstItem, true); if (msg != EQUIP_ERR_OK) msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true); } else if (_player->IsBankPos(src)) { msg = _player->CanBankItem(autoEquipItem.PackSlot, autoEquipItem.Slot, sSrc, dstItem, true); if (msg != EQUIP_ERR_OK) msg = _player->CanBankItem(autoEquipItem.PackSlot, NULL_SLOT, sSrc, dstItem, true); if (msg != EQUIP_ERR_OK) msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true); } else if (_player->IsEquipmentPos(src)) { msg = _player->CanEquipItem(autoEquipItem.Slot, eSrc, dstItem, true); if (msg == EQUIP_ERR_OK) msg = _player->CanUnequipItem(eSrc, true); } if (msg == EQUIP_ERR_OK && Player::IsEquipmentPos(dest) && !srcItem->GetChildItem().IsEmpty()) msg = _player->CanEquipChildItem(srcItem); if (msg != EQUIP_ERR_OK) { _player->SendEquipError(msg, dstItem, srcItem); return; } // now do moves, remove... _player->RemoveItem(dstbag, dstslot, false); _player->RemoveItem(autoEquipItem.PackSlot, autoEquipItem.Slot, false); // add to dest _player->EquipItem(dest, srcItem, true); // add to src if (_player->IsInventoryPos(src)) _player->StoreItem(sSrc, dstItem, true); else if (_player->IsBankPos(src)) _player->BankItem(sSrc, dstItem, true); else if (_player->IsEquipmentPos(src)) _player->EquipItem(eSrc, dstItem, true); if (Player::IsEquipmentPos(dest) && !srcItem->GetChildItem().IsEmpty()) _player->EquipChildItem(autoEquipItem.PackSlot, autoEquipItem.Slot, srcItem); } else { if (Item* parentItem = _player->GetItemByGuid(dstItem->GetGuidValue(ITEM_FIELD_CREATOR))) { if (Player::IsEquipmentPos(dest)) { _player->AutoUnequipChildItem(parentItem); // dest is now empty _player->SwapItem(src, dest); // src is now empty _player->SwapItem(parentItem->GetPos(), src); } } } _player->AutoUnequipOffhandIfNeed(); } }