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 }
TransmogTrinityStrings Transmogrification::Transmogrify(Player* player, uint64 itemGUID, uint8 slot, /*uint32 newEntry, */bool no_cost) { int32 cost = 0; // slot of the transmogrified item if (slot >= EQUIPMENT_SLOT_END) { TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify an item (lowguid: %u) with a wrong slot (%u) when transmogrifying items.", player->GetGUIDLow(), player->GetName().c_str(), GUID_LOPART(itemGUID), slot); return LANG_ERR_TRANSMOG_INVALID_SLOT; } /* // GET FROM itemTransmogrifier // entry of the transmogrifier item, if it's not 0 if (newEntry) { ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newEntry); if (!proto) { TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify to an invalid item (entry: %u).", player->GetGUIDLow(), player->GetName().c_str(), newEntry); return LANG_ERR_TRANSMOG_INVALID_SRC_ENTRY; } } */ Item* itemTransmogrifier = NULL; // guid of the transmogrifier item, if it's not 0 if (itemGUID) { itemTransmogrifier = player->GetItemByGuid(itemGUID); if (!itemTransmogrifier) { TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify with an invalid item (lowguid: %u).", player->GetGUIDLow(), player->GetName().c_str(), GUID_LOPART(itemGUID)); return LANG_ERR_TRANSMOG_MISSING_SRC_ITEM; } } // transmogrified item Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); if (!itemTransmogrified) { TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetGUIDLow(), player->GetName().c_str(), slot); return LANG_ERR_TRANSMOG_MISSING_DEST_ITEM; } // uint16 tempDest; //// has to be able to equip item transmogrified item //if (!player->CanEquipItem(slot, tempDest, itemTransmogrified, true, true)) //{ // TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) can't equip the item to be transmogrified (slot: %u, entry: %u).", player->GetGUIDLow(), player->GetName().c_str(), slot, itemTransmogrified->GetEntry()); // return; //} // //// has to be able to equip item transmogrifier item //if (!player->CanEquipItem(slot, tempDest, itemTransmogrifier, true, true)) //{ // TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) can't equip the transmogrifier item (slot: %u, entry: %u).", player->GetGUIDLow(), player->GetName().c_str(), slot, itemTransmogrifier->GetEntry()); // return; //} if (!itemTransmogrifier) // reset look newEntry { // itemTransmogrified->ClearEnchantment(TRANSMOGRIFY_ENCHANTMENT_SLOT); // player->SetVisibleItemSlot(slot, itemTransmogrified); // Custom DeleteFakeEntry(player, slot, itemTransmogrified); } else { if (!CanTransmogrifyItemWithItem(player, itemTransmogrified->GetTemplate(), itemTransmogrifier->GetTemplate())) { TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetGUIDLow(), player->GetName().c_str(), itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry()); return LANG_ERR_TRANSMOG_INVALID_ITEMS; } if (!no_cost) { cost = GetSpecialPrice(itemTransmogrified->GetTemplate()); cost *= GetScaledCostModifier(); cost += GetCopperCost(); if (!player->HasEnoughMoney(cost)) return LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY; if (GetRequireToken()) { if (player->HasItemCount(GetTokenEntry(), GetTokenAmount())) player->DestroyItemCount(GetTokenEntry(), GetTokenAmount(), true); else return LANG_ERR_TRANSMOG_NOT_ENOUGH_TOKENS; } } // All okay, proceed // itemTransmogrified->SetEnchantment(TRANSMOGRIFY_ENCHANTMENT_SLOT, newEntry, 0, 0); // player->SetVisibleItemSlot(slot, itemTransmogrified); // Custom SetFakeEntry(player, itemTransmogrifier->GetEntry(), slot, itemTransmogrified); // newEntry itemTransmogrified->UpdatePlayedTime(player); itemTransmogrified->SetOwnerGUID(player->GetGUID()); itemTransmogrified->SetNotRefundable(player); itemTransmogrified->ClearSoulboundTradeable(player); if (itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_EQUIPED || itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_USE) itemTransmogrifier->SetBinding(true); itemTransmogrifier->SetOwnerGUID(player->GetGUID()); itemTransmogrifier->SetNotRefundable(player); itemTransmogrifier->ClearSoulboundTradeable(player); //cost += GetSpecialPrice(itemTransmogrified->GetTemplate()); //cost *= GetScaledCostModifier(); //cost += sT->GetCopperCost(); } // trusting the client, if it got here it has to have enough money // ... unless client was modified if (cost) // 0 cost if reverting look player->ModifyMoney(-1*cost, false); return LANG_ERR_TRANSMOG_OK; }
TransmogTrinityStrings Transmogrification::Transmogrify(Player* player, ObjectGuid itemGUID, uint8 slot, bool no_cost) { TC_LOG_DEBUG("custom.transmog", "Transmogrification::Transmogrify"); // slot of the transmogrified item if (slot >= EQUIPMENT_SLOT_END) { TC_LOG_DEBUG("custom.transmog", "Transmogrification::Transmogrify - %s (%s) tried to transmogrify an %s with a wrong slot (%u) when transmogrifying items.", player->GetName().c_str(), player->GetGUID().ToString().c_str(), itemGUID.ToString().c_str(), slot); return LANG_ERR_TRANSMOG_INVALID_SLOT; } Item* itemTransmogrifier = NULL; // guid of the transmogrifier item, if it's not 0 if (!itemGUID.IsEmpty()) { itemTransmogrifier = player->GetItemByGuid(itemGUID); if (!itemTransmogrifier) { TC_LOG_DEBUG("custom.transmog", "Transmogrification::Transmogrify - %s (%s) tried to transmogrify with an invalid %s.", player->GetName().c_str(), player->GetGUID().ToString().c_str(), itemGUID.ToString().c_str()); return LANG_ERR_TRANSMOG_MISSING_SRC_ITEM; } } // transmogrified item Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); if (!itemTransmogrified) { TC_LOG_DEBUG("custom.transmog", "Transmogrification::Transmogrify - %s (%s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetName().c_str(), player->GetGUID().ToString().c_str(), slot); return LANG_ERR_TRANSMOG_MISSING_DEST_ITEM; } if (!itemTransmogrifier) // reset look newEntry { DeleteFakeEntry(player, itemTransmogrified); } else { if (!CanTransmogrifyItemWithItem(player, itemTransmogrified->GetTemplate(), itemTransmogrifier->GetTemplate())) { TC_LOG_DEBUG("custom.transmog", "Transmogrification::Transmogrify - %s (%s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetName().c_str(), player->GetGUID().ToString().c_str(), itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry()); return LANG_ERR_TRANSMOG_INVALID_ITEMS; } if (!no_cost) { if (RequireToken) { if (player->HasItemCount(TokenEntry, TokenAmount)) player->DestroyItemCount(TokenEntry, TokenAmount, true); else return LANG_ERR_TRANSMOG_NOT_ENOUGH_TOKENS; } int32 cost = 0; cost = GetSpecialPrice(itemTransmogrified->GetTemplate()); cost *= ScaledCostModifier; cost += CopperCost; if (cost) // 0 cost if reverting look { if (cost < 0) TC_LOG_DEBUG("custom.transmog", "Transmogrification::Transmogrify - %s (%s) transmogrification invalid cost (non negative, amount %i). Transmogrified %u with %u", player->GetName().c_str(), player->GetGUID().ToString().c_str(), -cost, itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry()); else { if (!player->HasEnoughMoney(cost)) return LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY; player->ModifyMoney(-cost, false); } } } SetFakeEntry(player, itemTransmogrified, itemTransmogrifier->GetEntry()); itemTransmogrified->UpdatePlayedTime(player); itemTransmogrified->SetOwnerGUID(player->GetGUID()); itemTransmogrified->SetNotRefundable(player); itemTransmogrified->ClearSoulboundTradeable(player); if (itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_EQUIPED || itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_USE) itemTransmogrifier->SetBinding(true); itemTransmogrifier->SetOwnerGUID(player->GetGUID()); itemTransmogrifier->SetNotRefundable(player); itemTransmogrifier->ClearSoulboundTradeable(player); } return LANG_ERR_TRANSMOG_OK; }
void TransmogDisplayVendorMgr::HandleTransmogrify(Player* player, Creature* /*creature*/, uint32 vendorslot, uint32 itemEntry, bool no_cost) { TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::HandleTransmogrify"); SelectionStore::Selection selection; if (!selectionStore.GetSelection(player->GetGUID().GetCounter(), selection)) return; // cheat, no slot selected const char* slotname = TransmogDisplayVendorMgr::getSlotName(selection.slot, player->GetSession()); if (!slotname) return; uint8 slot = selection.slot; // slot of the transmogrified item if (slot >= EQUIPMENT_SLOT_END) { TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::HandleTransmogrify - %s (%s) tried to transmogrify item %u with a wrong slot (%u) when transmogrifying items.", player->GetName().c_str(), player->GetGUID().ToString().c_str(), itemEntry, slot); return; // LANG_ERR_TRANSMOG_INVALID_SLOT } const ItemTemplate* itemTransmogrifier = NULL; // guid of the transmogrifier item, if it's not 0 if (itemEntry) { itemTransmogrifier = sObjectMgr->GetItemTemplate(itemEntry); if (!itemTransmogrifier) { TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::HandleTransmogrify - %s (%s) tried to transmogrify with an invalid item entry %u.", player->GetName().c_str(), player->GetGUID().ToString().c_str(), itemEntry); return; // LANG_ERR_TRANSMOG_MISSING_SRC_ITEM } } // transmogrified item Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); if (!itemTransmogrified) { TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::HandleTransmogrify - %s (%s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetName().c_str(), player->GetGUID().ToString().c_str(), slot); player->GetSession()->SendNotification("No item in %s slot", slotname); return; // LANG_ERR_TRANSMOG_MISSING_DEST_ITEM } if (!itemTransmogrifier) // reset look newEntry { DeleteFakeEntry(player, itemTransmogrified); } else { if (!CanTransmogrifyItemWithItem(player, itemTransmogrified->GetTemplate(), itemTransmogrifier)) { TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::HandleTransmogrify - %s (%s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetName().c_str(), player->GetGUID().ToString().c_str(), itemTransmogrified->GetEntry(), itemTransmogrifier->ItemId); player->GetSession()->SendNotification("Equipped item is not suitable for selected transmogrification"); return; // LANG_ERR_TRANSMOG_INVALID_ITEMS } if (uint32 fakeEntry = GetFakeEntry(itemTransmogrified)) { if (const ItemTemplate* fakeItemTemplate = sObjectMgr->GetItemTemplate(fakeEntry)) { if (fakeItemTemplate->DisplayInfoID == itemTransmogrifier->DisplayInfoID) { player->GetSession()->SendNotification("%s already transmogrified with %s", slotname, getItemName(itemTransmogrifier, player->GetSession()).c_str()); return; } } } // {{entry}, {entry}, ...} std::list<uint32> L; uint32 counter = 0; bool over = false; if (itemTransmogrified->GetTemplate()->Class != ITEM_CLASS_WEAPON && TransmogDisplayVendorMgr::AllowMixedArmorTypes) { for (uint32 i = 0; i < MAX_ITEM_SUBCLASS_ARMOR; ++i) { const EntryVector* oM = optionMap[MAX_ITEM_SUBCLASS_WEAPON + i][getCorrectInvType(itemTransmogrified->GetTemplate()->InventoryType)][selection.quality]; if (!oM) continue; if (!over && counter + oM->size() < selection.offset) { counter += oM->size(); } else { over = true; L.insert(L.end(), oM->begin(), oM->end()); } } } else if (itemTransmogrified->GetTemplate()->Class == ITEM_CLASS_WEAPON && TransmogDisplayVendorMgr::AllowMixedWeaponTypes) { for (uint32 i = 0; i < MAX_ITEM_SUBCLASS_WEAPON; ++i) { const EntryVector* oM = optionMap[i][getCorrectInvType(itemTransmogrified->GetTemplate()->InventoryType)][selection.quality]; if (!oM) continue; if (!over && counter + oM->size() < selection.offset) { counter += oM->size(); } else { over = true; L.insert(L.end(), oM->begin(), oM->end()); } } } else { const EntryVector* oM = optionMap[(itemTransmogrified->GetTemplate()->Class != ITEM_CLASS_WEAPON ? MAX_ITEM_SUBCLASS_WEAPON : 0) + itemTransmogrified->GetTemplate()->SubClass][getCorrectInvType(itemTransmogrified->GetTemplate()->InventoryType)][selection.quality]; if (oM) { if (!over && counter + oM->size() < selection.offset) { counter += oM->size(); } else { over = true; L.insert(L.end(), oM->begin(), oM->end()); } } } std::list<uint32>::const_iterator it = L.begin(); std::advance(it, (selection.offset - counter) + vendorslot); if (it == L.end() || (*it) != itemEntry) { player->GetSession()->SendNotification("Equipped item is not suitable for selected transmogrification"); return; // either cheat or changed items (not found in correct place in transmog vendor view) } if (!no_cost) { if (RequireToken) { if (player->HasItemCount(TokenEntry, TokenAmount)) { player->DestroyItemCount(TokenEntry, TokenAmount, true); } else { player->GetSession()->SendNotification("You do not have enough %ss", getItemName(sObjectMgr->GetItemTemplate(TransmogDisplayVendorMgr::TokenEntry), player->GetSession()).c_str()); return; // LANG_ERR_TRANSMOG_NOT_ENOUGH_TOKENS } } int32 cost = 0; cost = GetSpecialPrice(itemTransmogrified->GetTemplate()); cost *= ScaledCostModifier; cost += CopperCost; if (cost) // 0 cost if reverting look { if (cost < 0) { TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::HandleTransmogrify - %s (%s) transmogrification invalid cost (non negative, amount %i). Transmogrified %u with %u", player->GetName().c_str(), player->GetGUID().ToString().c_str(), -cost, itemTransmogrified->GetEntry(), itemTransmogrifier->ItemId); } else { if (!player->HasEnoughMoney(cost)) { player->GetSession()->SendNotification("You do not have enough money"); return; // LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY } player->ModifyMoney(-cost, false); } } SetFakeEntry(player, itemTransmogrified, itemTransmogrifier->ItemId); itemTransmogrified->UpdatePlayedTime(player); itemTransmogrified->SetOwnerGUID(player->GetGUID()); itemTransmogrified->SetNotRefundable(player); itemTransmogrified->ClearSoulboundTradeable(player); //if (itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_EQUIPED || itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_USE) // itemTransmogrifier->SetBinding(true); //itemTransmogrifier->SetOwnerGUID(player->GetGUID()); //itemTransmogrifier->SetNotRefundable(player); //itemTransmogrifier->ClearSoulboundTradeable(player); } player->PlayDirectSound(3337); player->GetSession()->SendAreaTriggerMessage("%s transmogrified", slotname); //return LANG_ERR_TRANSMOG_OK; } }
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::HandleTransmogrifyItems(WorldPackets::Item::TransmogrifyItems& transmogrifyItems) { Player* player = GetPlayer(); // Validate if (!player->GetNPCIfCanInteractWith(transmogrifyItems.Npc, UNIT_NPC_FLAG_TRANSMOGRIFIER)) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - %s not found or player can't interact with it.", transmogrifyItems.Npc.ToString().c_str()); return; } int64 cost = 0; std::unordered_map<Item*, Item*> transmogItems; std::unordered_map<Item*, std::pair<VoidStorageItem*, BonusData>> transmogVoidItems; std::vector<Item*> resetAppearanceItems; for (WorldPackets::Item::TransmogrifyItem const& transmogItem : transmogrifyItems.Items) { // slot of the transmogrified item if (transmogItem.Slot >= EQUIPMENT_SLOT_END) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify wrong slot (%u) when transmogrifying items.", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.Slot); return; } // transmogrified item Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, transmogItem.Slot); if (!itemTransmogrified) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.Slot); return; } WorldPackets::Item::ItemInstance itemInstance; BonusData const* bonus = nullptr; if (transmogItem.SrcItemGUID) { // guid of the transmogrifier item Item* itemTransmogrifier = player->GetItemByGuid(*transmogItem.SrcItemGUID); if (!itemTransmogrifier) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid item (%s).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.SrcItemGUID->ToString().c_str()); return; } itemInstance.Initialize(itemTransmogrifier); bonus = itemTransmogrifier->GetBonus(); transmogItems[itemTransmogrified] = itemTransmogrifier; } else if (transmogItem.SrcVoidItemGUID) { // guid of the transmogrifier item uint8 slot; VoidStorageItem* itemTransmogrifier = player->GetVoidStorageItem(transmogItem.SrcVoidItemGUID->GetCounter(), slot); if (!itemTransmogrifier) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid void storage item (%s).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.SrcVoidItemGUID->ToString().c_str()); return; } itemInstance.Initialize(itemTransmogrifier); std::pair<VoidStorageItem*, BonusData>& transmogData = transmogVoidItems[itemTransmogrified]; transmogData.first = itemTransmogrifier; transmogData.second.Initialize(itemInstance); bonus = &transmogData.second; } else { resetAppearanceItems.push_back(itemTransmogrified); continue; } // entry of transmogrifier and from packet if (itemInstance != transmogItem.Item) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid item instance data for %s.", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.SrcItemGUID->ToString().c_str()); return; } // validity of the transmogrification items if (!Item::CanTransmogrifyItemWithItem(itemTransmogrified, transmogItem.Item, bonus)) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), itemTransmogrified->GetEntry(), transmogItem.Item.ItemID); return; } // add cost cost += itemTransmogrified->GetSpecialPrice(); } if (cost) // 0 cost if reverting look { if (!player->HasEnoughMoney(cost)) return; player->ModifyMoney(-cost); } // Everything is fine, proceed for (auto& transmogPair : transmogItems) { Item* transmogrified = transmogPair.first; Item* transmogrifier = transmogPair.second; transmogrified->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, transmogrifier->GetEntry()); transmogrified->SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD, transmogrifier->GetAppearanceModId()); player->SetVisibleItemSlot(transmogrified->GetSlot(), transmogrified); transmogrified->SetNotRefundable(player); transmogrified->ClearSoulboundTradeable(player); transmogrifier->SetNotRefundable(player); transmogrifier->ClearSoulboundTradeable(player); if (transmogrifier->GetTemplate()->GetBonding() == BIND_WHEN_EQUIPED || transmogrifier->GetTemplate()->GetBonding() == BIND_WHEN_USE) transmogrifier->SetBinding(true); } for (auto& transmogVoirPair : transmogVoidItems) { Item* transmogrified = transmogVoirPair.first; VoidStorageItem* transmogrifier = transmogVoirPair.second.first; BonusData& bonus = transmogVoirPair.second.second; transmogrified->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, transmogrifier->ItemEntry); transmogrified->SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD, bonus.AppearanceModID); player->SetVisibleItemSlot(transmogrified->GetSlot(), transmogrified); transmogrified->SetNotRefundable(player); transmogrified->ClearSoulboundTradeable(player); } for (Item* item : resetAppearanceItems) { item->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, 0); item->SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD, 0); player->SetVisibleItemSlot(item->GetSlot(), item); } }