diff options
author | Shauren <shauren.trinity@gmail.com> | 2016-07-10 14:41:18 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2016-07-10 14:41:18 +0200 |
commit | 452cae0c0b343597c3e6721fd5aa57fd787a06c9 (patch) | |
tree | 6c736a54f8cc17fb1d0fe8abcc93b679d1c097e3 /src | |
parent | ee2abfba9102ca4acce334de00a0bca0ae5c624c (diff) |
Core/Items: Fixed saving gem bonuses
Diffstat (limited to 'src')
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.cpp | 4 | ||||
-rw-r--r-- | src/server/game/AuctionHouse/AuctionHouseMgr.cpp | 19 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 93 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.h | 13 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.h | 61 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 25 | ||||
-rw-r--r-- | src/server/game/Guilds/Guild.cpp | 40 | ||||
-rw-r--r-- | src/server/game/Guilds/GuildMgr.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Handlers/ItemHandler.cpp | 92 | ||||
-rw-r--r-- | src/server/game/Handlers/TradeHandler.cpp | 19 | ||||
-rw-r--r-- | src/server/game/Server/Packets/InspectPackets.cpp | 19 | ||||
-rw-r--r-- | src/server/game/Server/Packets/ItemPackets.cpp | 14 | ||||
-rw-r--r-- | src/server/game/Server/Packets/ItemPackets.h | 1 | ||||
-rw-r--r-- | src/server/game/Server/Packets/MailPackets.cpp | 19 |
14 files changed, 283 insertions, 142 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index f88307db19c..5789bab01c4 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -26,7 +26,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() "ii.durability, ii.playedTime, ii.text, ii.upgradeId, ii.battlePetSpeciesId, ii.battlePetBreedData, ii.battlePetLevel, ii.battlePetDisplayId, ii.bonusListIDs, " \ "iit.itemModifiedAppearanceAllSpecs, iit.itemModifiedAppearanceSpec1, iit.itemModifiedAppearanceSpec2, iit.itemModifiedAppearanceSpec3, iit.itemModifiedAppearanceSpec4, " \ "iit.spellItemEnchantmentAllSpecs, iit.spellItemEnchantmentSpec1, iit.spellItemEnchantmentSpec2, iit.spellItemEnchantmentSpec3, iit.spellItemEnchantmentSpec4, " \ - "ig.gemItemId1, ig.gemItemId2, ig.gemItemId3" + "ig.gemItemId1, ig.gemBonuses1, ig.gemContext1, ig.gemItemId2, ig.gemBonuses2, ig.gemContext2, ig.gemItemId3, ig.gemBonuses3, ig.gemContext3" PrepareStatement(CHAR_DEL_QUEST_POOL_SAVE, "DELETE FROM pool_quest_save WHERE pool_id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_QUEST_POOL_SAVE, "INSERT INTO pool_quest_save (pool_id, quest_id) VALUES (?, ?)", CONNECTION_ASYNC); @@ -170,7 +170,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD, "UPDATE item_instance SET duration = ?, flags = ?, durability = ?, upgradeId = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE, "DELETE FROM item_instance WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER, "DELETE FROM item_instance WHERE owner_guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_ITEM_INSTANCE_GEMS, "INSERT INTO item_instance_gems (itemGuid, gemItemId1, gemItemId2, gemItemId3) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_ITEM_INSTANCE_GEMS, "INSERT INTO item_instance_gems (itemGuid, gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_GEMS, "DELETE FROM item_instance_gems WHERE itemGuid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_GEMS_BY_OWNER, "DELETE iig FROM item_instance_gems iig LEFT JOIN item_instance ii ON iig.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ITEM_INSTANCE_TRANSMOG, "INSERT INTO item_instance_transmog (itemGuid, itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4, " diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index 190ee4d49d8..bc764a33659 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -845,16 +845,17 @@ void AuctionEntry::BuildAuctionInfo(std::vector<WorldPackets::AuctionHouse::Auct auctionItem.Enchantments.emplace_back(item->GetEnchantmentId((EnchantmentSlot) i), item->GetEnchantmentDuration((EnchantmentSlot) i), item->GetEnchantmentCharges((EnchantmentSlot) i), i); } - for (std::size_t i = 0; i < item->GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).size(); ++i) + uint8 i = 0; + for (ItemDynamicFieldGems const& gemData : item->GetGems()) { - uint32 gemItemId = item->GetDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, i); - if (!gemItemId) - continue; - - WorldPackets::Item::ItemGemInstanceData gem; - gem.Slot = i; - gem.Item.ItemID = gemItemId; - auctionItem.Gems.push_back(gem); + if (gemData.ItemId) + { + WorldPackets::Item::ItemGemInstanceData gem; + gem.Slot = i; + gem.Item.Initialize(&gemData); + auctionItem.Gems.push_back(gem); + } + ++i; } items.emplace_back(auctionItem); diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 94d6c4ee19a..2372318ad2d 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -407,19 +407,42 @@ void Item::SaveToDB(SQLTransaction& trans) stmt->setUInt64(1, GetGUID().GetCounter()); trans->Append(stmt); } - if (!GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).empty()) - { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_GEMS); - stmt->setUInt64(0, GetGUID().GetCounter()); - trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_GEMS); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); + + if (GetGems().size()) + { stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_GEMS); stmt->setUInt64(0, GetGUID().GetCounter()); uint32 i = 0; - for (; i < MAX_GEM_SOCKETS && i < GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).size(); ++i) - stmt->setUInt32(1 + i, GetDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, i)); + for (ItemDynamicFieldGems const& gemData : GetGems()) + { + if (gemData.ItemId) + { + stmt->setUInt32(1 + i * MAX_GEM_SOCKETS, gemData.ItemId); + std::ostringstream gemBonusListIDs; + for (uint16 bonusListID : gemData.BonusListIDs) + if (bonusListID) + gemBonusListIDs << bonusListID << ' '; + stmt->setString(2 + i * MAX_GEM_SOCKETS, gemBonusListIDs.str()); + stmt->setUInt8(3 + i * MAX_GEM_SOCKETS, gemData.Context); + } + else + { + stmt->setUInt32(1 + i * MAX_GEM_SOCKETS, 0); + stmt->setString(2 + i * MAX_GEM_SOCKETS, ""); + stmt->setUInt8(3 + i * MAX_GEM_SOCKETS, 0); + } + ++i; + } for (; i < MAX_GEM_SOCKETS; ++i) - stmt->setUInt32(1 + i, 0); + { + stmt->setUInt32(1 + i * MAX_GEM_SOCKETS, 0); + stmt->setString(2 + i * MAX_GEM_SOCKETS, ""); + stmt->setUInt8(3 + i * MAX_GEM_SOCKETS, 0); + } trans->Append(stmt); } @@ -508,8 +531,8 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie // itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4, // 24 25 26 27 28 // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4, - // 29 30 31 - // gemItemId1, gemItemId2, gemItemId3 FROM item_instance + // 29 30 31 32 33 34 35 36 37 + // gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3 FROM item_instance // create item before any checks for store correct guid // and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB @@ -618,15 +641,20 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_3, fields[27].GetUInt32()); SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_4, fields[28].GetUInt32()); - uint32 gemItemIds[3] = { fields[29].GetUInt32(), fields[30].GetUInt32(), fields[31].GetUInt32() }; - if (gemItemIds[0] || gemItemIds[1] || gemItemIds[2]) + ItemDynamicFieldGems gemData[MAX_GEM_SOCKETS]; + memset(gemData, 0, sizeof(gemData)); + for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) { - // gem slots must be preserved, hence funky logic - AddDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, gemItemIds[0]); - if (gemItemIds[1] || gemItemIds[2]) - AddDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, gemItemIds[1]); - if (gemItemIds[2]) - AddDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, gemItemIds[2]); + gemData[i].ItemId = fields[29 + i * MAX_GEM_SOCKETS].GetUInt32(); + Tokenizer bonusListIDs(fields[30 + i * MAX_GEM_SOCKETS].GetString(), ' '); + uint32 b = 0; + for (char const* token : bonusListIDs) + if (uint32 bonusListID = atoul(token)) + gemData[i].BonusListIDs[b++] = bonusListID; + + gemData[i].Context = fields[31 + i * MAX_GEM_SOCKETS].GetUInt8(); + if (gemData[i].ItemId) + SetGem(i, &gemData[i]); } if (need_save) // normal item changed state set not work at loading @@ -1050,10 +1078,27 @@ void Item::ClearEnchantment(EnchantmentSlot slot) SetState(ITEM_CHANGED, GetOwner()); } +DynamicFieldStructuredView<ItemDynamicFieldGems> Item::GetGems() const +{ + return GetDynamicStructuredValues<ItemDynamicFieldGems>(ITEM_DYNAMIC_FIELD_GEMS); +} + +ItemDynamicFieldGems const* Item::GetGem(uint16 slot) const +{ + ASSERT(slot < MAX_GEM_SOCKETS); + return GetDynamicStructuredValue<ItemDynamicFieldGems>(ITEM_DYNAMIC_FIELD_GEMS, slot); +} + +void Item::SetGem(uint16 slot, ItemDynamicFieldGems const* gem) +{ + ASSERT(slot < MAX_GEM_SOCKETS); + SetDynamicStructuredValue(ITEM_DYNAMIC_FIELD_GEMS, slot, gem); +} + bool Item::GemsFitSockets() const { uint32 gemSlot = 0; - for (uint32 gemItemId : GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS)) + for (ItemDynamicFieldGems const& gemData : GetGems()) { uint8 SocketColor = GetTemplate()->GetSocketColor(gemSlot); if (!SocketColor) // no socket slot @@ -1061,7 +1106,7 @@ bool Item::GemsFitSockets() const uint32 GemColor = 0; - ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemItemId); + ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemData.ItemId); if (gemProto) { GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gemProto->GetGemProperties()); @@ -1077,17 +1122,17 @@ bool Item::GemsFitSockets() const uint8 Item::GetGemCountWithID(uint32 GemID) const { - return std::count_if(GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).begin(), GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).end(), [GemID](uint32 gemItemId) + return std::count_if(GetGems().begin(), GetGems().end(), [GemID](ItemDynamicFieldGems const& gemData) { - return gemItemId == GemID; + return gemData.ItemId == GemID; }); } uint8 Item::GetGemCountWithLimitCategory(uint32 limitCategory) const { - return std::count_if(GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).begin(), GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).end(), [limitCategory](uint32 gemItemId) + return std::count_if(GetGems().begin(), GetGems().end(), [limitCategory](ItemDynamicFieldGems const& gemData) { - ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemItemId); + ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemData.ItemId); if (!gemProto) return false; diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 26acb7d8ada..68d903f6a81 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -278,6 +278,16 @@ struct BonusData void AddBonus(uint32 type, int32 const (&values)[2]); }; +#pragma pack(push, 1) +struct ItemDynamicFieldGems +{ + uint32 ItemId; + uint16 BonusListIDs[16]; + uint8 Context; + uint8 Padding[3]; +}; +#pragma pack(pop) + class TC_GAME_API Item : public Object { public: @@ -373,6 +383,9 @@ class TC_GAME_API Item : public Object uint32 GetEnchantmentId(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_ID_OFFSET);} uint32 GetEnchantmentDuration(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET);} uint32 GetEnchantmentCharges(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_CHARGES_OFFSET);} + DynamicFieldStructuredView<ItemDynamicFieldGems> GetGems() const; + ItemDynamicFieldGems const* GetGem(uint16 slot) const; + void SetGem(uint16 slot, ItemDynamicFieldGems const* gem); std::string const& GetText() const { return m_text; } void SetText(std::string const& text) { m_text = text; } diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 3dc53538d23..e0aedc79c7f 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -92,6 +92,33 @@ class ZoneScript; typedef std::unordered_map<Player*, UpdateData> UpdateDataMapType; +// Helper class used to iterate object dynamic fields while interpreting them as a structure instead of raw int array +template<class T> +class DynamicFieldStructuredView +{ +public: + explicit DynamicFieldStructuredView(std::vector<uint32> const& data) : _data(data) { } + + T const* begin() const + { + return reinterpret_cast<T const*>(_data.data()); + } + + T const* end() const + { + return reinterpret_cast<T const*>(_data.data() + _data.size()); + } + + std::size_t size() const + { + using BlockCount = std::integral_constant<uint16, sizeof(T) / sizeof(uint32)>; + return _data.size() / BlockCount::value; + } + +private: + std::vector<uint32> const& _data; +}; + class TC_GAME_API Object { public: @@ -174,6 +201,40 @@ class TC_GAME_API Object void ClearDynamicValue(uint16 index); void SetDynamicValue(uint16 index, uint16 offset, uint32 value); + template<class T> + DynamicFieldStructuredView<T> GetDynamicStructuredValues(uint16 index) const + { + static_assert(std::is_pod<T>::value, "T used for Object::SetDynamicStructuredValue<T> is not a POD type"); + using BlockCount = std::integral_constant<uint16, sizeof(T) / sizeof(uint32)>; + ASSERT(index < _dynamicValuesCount || PrintIndexError(index, false)); + std::vector<uint32> const& values = _dynamicValues[index]; + ASSERT((values.size() % BlockCount::value) == 0, "Dynamic field value count must exactly fit into structure"); + return DynamicFieldStructuredView<T>(values); + } + + template<class T> + T const* GetDynamicStructuredValue(uint16 index, uint16 offset) const + { + static_assert(std::is_pod<T>::value, "T used for Object::SetDynamicStructuredValue<T> is not a POD type"); + using BlockCount = std::integral_constant<uint16, sizeof(T) / sizeof(uint32)>; + ASSERT(index < _dynamicValuesCount || PrintIndexError(index, false)); + std::vector<uint32> const& values = _dynamicValues[index]; + ASSERT((values.size() % BlockCount::value) == 0, "Dynamic field value count must exactly fit into structure"); + if (offset * BlockCount::value >= values.size()) + return nullptr; + return reinterpret_cast<T const*>(&values[offset * BlockCount::value]); + } + + template<class T> + void SetDynamicStructuredValue(uint16 index, uint16 offset, T const* value) + { + static_assert(std::is_pod<T>::value, "T used for Object::SetDynamicStructuredValue<T> is not a POD type"); + using BlockCount = std::integral_constant<uint16, sizeof(T) / sizeof(uint32)>; + SetDynamicValue(index, (offset + 1) * BlockCount::value - 1, 0); // reserve space + for (uint16 i = 0; i < BlockCount::value; ++i) + SetDynamicValue(index, offset * BlockCount::value + i, *(reinterpret_cast<uint32 const*>(value) + i)); + } + void ClearUpdateMask(bool remove); uint16 GetValuesCount() const { return m_valuesCount; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 2bf30369a5c..749aa969585 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -12821,9 +12821,10 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool } // Cogwheel gems dont have requirement data set in SpellItemEnchantment.dbc, but they do have it in Item-sparse.db2 - if (ItemTemplate const* gem = sObjectMgr->GetItemTemplate(item->GetDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, uint32(slot - SOCK_ENCHANTMENT_SLOT)))) - if (gem->GetRequiredSkill() && GetSkillValue(gem->GetRequiredSkill()) < gem->GetRequiredSkillRank()) - return; + if (ItemDynamicFieldGems const* gem = item->GetGem(uint16(slot - SOCK_ENCHANTMENT_SLOT))) + if (ItemTemplate const* gemTemplate = sObjectMgr->GetItemTemplate(gem->ItemId)) + if (gemTemplate->GetRequiredSkill() && GetSkillValue(gemTemplate->GetRequiredSkill()) < gemTemplate->GetRequiredSkillRank()) + return; } if (!item->IsBroken()) @@ -17339,8 +17340,8 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) // itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4, // 24 25 26 27 28 // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4, - // 29 30 31 32 33 - // gemItemId1, gemItemId2, gemItemId3, bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot + // 29 30 31 32 33 34 35 36 37 38 39 + // gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3, bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot //NOTE: the "order by `bag`" is important because it makes sure //the bagMap is filled before items in the bags are loaded //NOTE2: the "order by `slot`" is needed because mainhand weapons are (wrongly?) @@ -17362,8 +17363,8 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) Field* fields = result->Fetch(); if (Item* item = _LoadItem(trans, zoneId, timeDiff, fields)) { - ObjectGuid bagGuid = fields[32].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[32].GetUInt64()) : ObjectGuid::Empty; - uint8 slot = fields[33].GetUInt8(); + ObjectGuid bagGuid = fields[38].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[38].GetUInt64()) : ObjectGuid::Empty; + uint8 slot = fields[39].GetUInt8(); GetSession()->GetCollectionMgr()->CheckHeirloomUpgrades(item); GetSession()->GetCollectionMgr()->AddItemAppearance(item); @@ -17692,7 +17693,7 @@ void Player::_LoadMailedItems(Mail* mail) Item* item = NewItemOrBag(proto); - ObjectGuid ownerGuid = fields[32].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[32].GetUInt64()) : ObjectGuid::Empty; + ObjectGuid ownerGuid = fields[38].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[38].GetUInt64()) : ObjectGuid::Empty; if (!item->LoadFromDB(itemGuid, ownerGuid, fields, itemEntry)) { TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems: Item (GUID: " UI64FMTD ") in mail (%u) doesn't exist, deleted from mail.", itemGuid, mail->messageID); @@ -21641,9 +21642,9 @@ bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) Item* pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, i); if (pItem2 && !pItem2->IsBroken()) { - for (uint32 gemItemId : pItem2->GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS)) + for (ItemDynamicFieldGems const& gemData : pItem2->GetGems()) { - ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemItemId); + ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemData.ItemId); if (!gemProto) continue; @@ -24529,9 +24530,9 @@ InventoryResult Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limi return res; // check unique-equipped on gems - for (uint32 gemItemId : pItem->GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS)) + for (ItemDynamicFieldGems const& gemData : pItem->GetGems()) { - ItemTemplate const* pGem = sObjectMgr->GetItemTemplate(gemItemId); + ItemTemplate const* pGem = sObjectMgr->GetItemTemplate(gemData.ItemId); if (!pGem) continue; diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 2bd97bd7728..5140b74547b 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -2394,7 +2394,7 @@ void Guild::LoadBankTabFromDB(Field* fields) bool Guild::LoadBankItemFromDB(Field* fields) { - uint8 tabId = fields[33].GetUInt8(); + uint8 tabId = fields[39].GetUInt8(); if (tabId >= _GetPurchasedTabsSize()) { TC_LOG_ERROR("guild", "Invalid tab for item (GUID: %u, id: #%u) in guild bank, skipped.", @@ -3214,16 +3214,17 @@ void Guild::_SendBankContentUpdate(uint8 tabId, SlotIds slots) const if (tabItem) { - for (std::size_t i = 0; i < tabItem->GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).size(); ++i) + uint8 i = 0; + for (ItemDynamicFieldGems const& gemData : tabItem->GetGems()) { - uint32 gemItemId = tabItem->GetDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, i); - if (!gemItemId) - continue; - - WorldPackets::Item::ItemGemInstanceData gem; - gem.Slot = i; - gem.Item.ItemID = gemItemId; - itemInfo.SocketEnchant.push_back(gem); + if (gemData.ItemId) + { + WorldPackets::Item::ItemGemInstanceData gem; + gem.Slot = i; + gem.Item.Initialize(&gemData); + itemInfo.SocketEnchant.push_back(gem); + } + ++i; } } @@ -3297,16 +3298,17 @@ void Guild::SendBankList(WorldSession* session, uint8 tabId, bool fullUpdate) co itemInfo.OnUseEnchantmentID = 0/*int32(tabItem->GetItemSuffixFactor())*/; itemInfo.Flags = 0; - for (std::size_t i = 0; i < tabItem->GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).size(); ++i) + uint8 i = 0; + for (ItemDynamicFieldGems const& gemData : tabItem->GetGems()) { - uint32 gemItemId = tabItem->GetDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, i); - if (!gemItemId) - continue; - - WorldPackets::Item::ItemGemInstanceData gem; - gem.Slot = i; - gem.Item.ItemID = gemItemId; - itemInfo.SocketEnchant.push_back(gem); + if (gemData.ItemId) + { + WorldPackets::Item::ItemGemInstanceData gem; + gem.Slot = i; + gem.Item.Initialize(&gemData); + itemInfo.SocketEnchant.push_back(gem); + } + ++i; } itemInfo.Locked = false; diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp index 48216a2809a..bb65c6c00bd 100644 --- a/src/server/game/Guilds/GuildMgr.cpp +++ b/src/server/game/Guilds/GuildMgr.cpp @@ -409,8 +409,8 @@ void GuildMgr::LoadGuilds() // itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4, // 24 25 26 27 28 // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4, - // 29 30 31 32 33 - // gemItemId1, gemItemId2, gemItemId3, guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid + // 29 30 31 32 33 34 35 36 37 38 39 + // gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3, guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid PreparedQueryResult result = CharacterDatabase.Query(CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_BANK_ITEMS)); if (!result) @@ -423,7 +423,7 @@ void GuildMgr::LoadGuilds() do { Field* fields = result->Fetch(); - uint64 guildId = fields[32].GetUInt64(); + uint64 guildId = fields[38].GetUInt64(); if (Guild* guild = GetGuildById(guildId)) guild->LoadBankItemFromDB(fields); diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 91a8eee27e6..a4e35620bd2 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -872,22 +872,38 @@ void WorldSession::HandleSocketGems(WorldPackets::Item::SocketGems& socketGems) //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] = !socketGems.GemItem[i].IsEmpty() ? _player->GetItemByGuid(socketGems.GemItem[i]) : NULL; + 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); - 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()->GetGemProperties()) : NULL; + gemProperties[i] = sGemPropertiesStore.LookupEntry(gem->GetTemplate()->GetGemProperties()); + } + + oldGemData[i] = itemTarget->GetGem(i); + } // Find first prismatic socket - int32 firstPrismatic = 0; + uint32 firstPrismatic = 0; while (firstPrismatic < MAX_GEM_SOCKETS && itemTarget->GetSocketColor(firstPrismatic)) ++firstPrismatic; - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe + for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe { - if (!GemProps[i]) + if (!gemProperties[i]) continue; // tried to put gem in socket where no socket exists (take care about prismatic sockets) @@ -902,50 +918,42 @@ void WorldSession::HandleSocketGems(WorldPackets::Item::SocketGems& socketGems) } // Gem must match socket color - if (SocketColorToGemTypeMask[itemTarget->GetSocketColor(i)] != GemProps[i]->Type) + if (SocketColorToGemTypeMask[itemTarget->GetSocketColor(i)] != gemProperties[i]->Type) { // unless its red, blue, yellow or prismatic - if (!(SocketColorToGemTypeMask[itemTarget->GetSocketColor(i)] & SOCKET_COLOR_PRISMATIC) || !(GemProps[i]->Type & SOCKET_COLOR_PRISMATIC)) + if (!(SocketColorToGemTypeMask[itemTarget->GetSocketColor(i)] & SOCKET_COLOR_PRISMATIC) || !(gemProperties[i]->Type & SOCKET_COLOR_PRISMATIC)) return; } } - uint32 GemEnchants[MAX_GEM_SOCKETS]; - uint32 oldGemItemIds[MAX_GEM_SOCKETS]; - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get new and old enchantments - { - GemEnchants[i] = (GemProps[i]) ? GemProps[i]->EnchantID : 0; - oldGemItemIds[i] = itemTarget->GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).size() > i ? itemTarget->GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS)[i] : 0; - } - // check unique-equipped conditions - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) + for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) { - if (!Gems[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(); + ItemTemplate const* iGemProto = gems[i]->GetTemplate(); // unique item (for new and already placed bit removed enchantments if (iGemProto->GetFlags() & ITEM_FLAG_UNIQUE_EQUIPPED) { - for (int j = 0; j < MAX_GEM_SOCKETS; ++j) + for (uint32 j = 0; j < MAX_GEM_SOCKETS; ++j) { if (i == j) // skip self continue; - if (Gems[j]) + if (gems[j]) { - if (iGemProto->GetId() == Gems[j]->GetEntry()) + if (iGemProto->GetId() == gems[j]->GetEntry()) { _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); return; } } - else if (oldGemItemIds[j]) + else if (oldGemData[j]) { - if (iGemProto->GetId() == oldGemItemIds[j]) + if (iGemProto->GetId() == oldGemData[j]->ItemId) { _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); return; @@ -963,16 +971,16 @@ void WorldSession::HandleSocketGems(WorldPackets::Item::SocketGems& socketGems) // 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]) + if (gems[j]) { // new gem - if (iGemProto->GetItemLimitCategory() == Gems[j]->GetTemplate()->GetItemLimitCategory()) + if (iGemProto->GetItemLimitCategory() == gems[j]->GetTemplate()->GetItemLimitCategory()) ++limit_newcount; } - else if (oldGemItemIds[j]) + else if (oldGemData[j]) { // existing gem - if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(oldGemItemIds[j])) + if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(oldGemData[j]->ItemId)) if (iGemProto->GetItemLimitCategory() == jProto->GetItemLimitCategory()) ++limit_newcount; } @@ -989,7 +997,7 @@ void WorldSession::HandleSocketGems(WorldPackets::Item::SocketGems& socketGems) // 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))) + if (InventoryResult res = _player->CanEquipUniqueItem(gems[i], slot, std::max(limit_newcount, 0))) { _player->SendEquipError(res, itemTarget, NULL); return; @@ -1006,25 +1014,17 @@ void WorldSession::HandleSocketGems(WorldPackets::Item::SocketGems& socketGems) for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot) _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), false); - uint32 reqGemSlots = 0; - for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) - if (Gems[i]) - reqGemSlots = i + 1; - - while (itemTarget->GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).size() < reqGemSlots) - itemTarget->AddDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, 0); - - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) + for (uint16 i = 0; i < MAX_GEM_SOCKETS; ++i) { - if (Item* guidItem = _player->GetItemByGuid(socketGems.GemItem[i])) + if (gems[i]) { - itemTarget->SetDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, i, guidItem->GetEntry()); + itemTarget->SetGem(i, &gemData[i]); - if (GemEnchants[i]) - itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i], 0, 0, _player->GetGUID()); + 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(guidItem, gemCount, true); + _player->DestroyItemCount(gems[i], gemCount, true); } } diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index 7c672b86137..ae263301fc9 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -79,16 +79,17 @@ void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) tradeItem.Unwrapped->MaxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); tradeItem.Unwrapped->Durability = item->GetUInt32Value(ITEM_FIELD_DURABILITY); - for (std::size_t i = 0; i < item->GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).size(); ++i) + uint8 i = 0; + for (ItemDynamicFieldGems const& gemData : item->GetGems()) { - uint32 gemItemId = item->GetDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, i); - if (!gemItemId) - continue; - - WorldPackets::Item::ItemGemInstanceData gem; - gem.Slot = i; - gem.Item.ItemID = gemItemId; - tradeItem.Unwrapped->Gems.push_back(gem); + if (gemData.ItemId) + { + WorldPackets::Item::ItemGemInstanceData gem; + gem.Slot = i; + gem.Item.Initialize(&gemData); + tradeItem.Unwrapped->Gems.push_back(gem); + } + ++i; } } diff --git a/src/server/game/Server/Packets/InspectPackets.cpp b/src/server/game/Server/Packets/InspectPackets.cpp index fe81ac6c048..666f653d69e 100644 --- a/src/server/game/Server/Packets/InspectPackets.cpp +++ b/src/server/game/Server/Packets/InspectPackets.cpp @@ -71,16 +71,17 @@ WorldPackets::Inspect::InspectItemData::InspectItemData(::Item const* item, uint if (uint32 enchId = item->GetEnchantmentId(EnchantmentSlot(i))) Enchants.emplace_back(enchId, i); - for (std::size_t i = 0; i < item->GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).size(); ++i) + uint8 i = 0; + for (ItemDynamicFieldGems const& gemData : item->GetGems()) { - uint32 gemItemId = item->GetDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, i); - if (!gemItemId) - continue; - - WorldPackets::Item::ItemGemInstanceData gem; - gem.Slot = i; - gem.Item.ItemID = gemItemId; - Gems.push_back(gem); + if (gemData.ItemId) + { + WorldPackets::Item::ItemGemInstanceData gem; + gem.Slot = i; + gem.Item.Initialize(&gemData); + Gems.push_back(gem); + } + ++i; } } diff --git a/src/server/game/Server/Packets/ItemPackets.cpp b/src/server/game/Server/Packets/ItemPackets.cpp index c6609812af5..54bc120d178 100644 --- a/src/server/game/Server/Packets/ItemPackets.cpp +++ b/src/server/game/Server/Packets/ItemPackets.cpp @@ -281,6 +281,20 @@ void WorldPackets::Item::ItemInstance::Initialize(::Item const* item) } } +void WorldPackets::Item::ItemInstance::Initialize(::ItemDynamicFieldGems const* gem) +{ + ItemID = gem->ItemId; + + ItemBonusInstanceData bonus; + bonus.Context = gem->Context; + for (uint16 bonusListId : gem->BonusListIDs) + if (bonusListId) + bonus.BonusListIDs.push_back(bonusListId); + + if (bonus.Context || !bonus.BonusListIDs.empty()) + ItemBonus = bonus; +} + void WorldPackets::Item::ItemInstance::Initialize(::LootItem const& lootItem) { ItemID = lootItem.itemid; diff --git a/src/server/game/Server/Packets/ItemPackets.h b/src/server/game/Server/Packets/ItemPackets.h index aef6060b260..feb4f8f1120 100644 --- a/src/server/game/Server/Packets/ItemPackets.h +++ b/src/server/game/Server/Packets/ItemPackets.h @@ -40,6 +40,7 @@ namespace WorldPackets struct ItemInstance { void Initialize(::Item const* item); + void Initialize(::ItemDynamicFieldGems const* gem); void Initialize(::LootItem const& lootItem); void Initialize(::VoidStorageItem const* voidItem); diff --git a/src/server/game/Server/Packets/MailPackets.cpp b/src/server/game/Server/Packets/MailPackets.cpp index 12f48debe3d..f9bfaad578b 100644 --- a/src/server/game/Server/Packets/MailPackets.cpp +++ b/src/server/game/Server/Packets/MailPackets.cpp @@ -44,16 +44,17 @@ WorldPackets::Mail::MailAttachedItem::MailAttachedItem(::Item const* item, uint8 Enchants.push_back(enchant); } - for (std::size_t i = 0; i < item->GetDynamicValues(ITEM_DYNAMIC_FIELD_GEMS).size(); ++i) + uint8 i = 0; + for (ItemDynamicFieldGems const& gemData : item->GetGems()) { - uint32 gemItemId = item->GetDynamicValue(ITEM_DYNAMIC_FIELD_GEMS, i); - if (!gemItemId) - continue; - - Item::ItemGemInstanceData gem; - gem.Slot = i; - gem.Item.ItemID = gemItemId; - Gems.push_back(gem); + if (gemData.ItemId) + { + WorldPackets::Item::ItemGemInstanceData gem; + gem.Slot = i; + gem.Item.Initialize(&gemData); + Gems.push_back(gem); + } + ++i; } } |