aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2016-07-10 14:41:18 +0200
committerShauren <shauren.trinity@gmail.com>2016-07-10 14:41:18 +0200
commit452cae0c0b343597c3e6721fd5aa57fd787a06c9 (patch)
tree6c736a54f8cc17fb1d0fe8abcc93b679d1c097e3 /src
parentee2abfba9102ca4acce334de00a0bca0ae5c624c (diff)
Core/Items: Fixed saving gem bonuses
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp4
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp19
-rw-r--r--src/server/game/Entities/Item/Item.cpp93
-rw-r--r--src/server/game/Entities/Item/Item.h13
-rw-r--r--src/server/game/Entities/Object/Object.h61
-rw-r--r--src/server/game/Entities/Player/Player.cpp25
-rw-r--r--src/server/game/Guilds/Guild.cpp40
-rw-r--r--src/server/game/Guilds/GuildMgr.cpp6
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp92
-rw-r--r--src/server/game/Handlers/TradeHandler.cpp19
-rw-r--r--src/server/game/Server/Packets/InspectPackets.cpp19
-rw-r--r--src/server/game/Server/Packets/ItemPackets.cpp14
-rw-r--r--src/server/game/Server/Packets/ItemPackets.h1
-rw-r--r--src/server/game/Server/Packets/MailPackets.cpp19
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;
}
}