aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOvahlord <dreadkiller@gmx.de>2023-11-28 02:00:51 +0100
committerOvahlord <dreadkiller@gmx.de>2023-11-28 02:00:51 +0100
commit00c1f57c8bcd22bbf202f921d9670b1af9c3b3fd (patch)
tree05e305cea0fb7a8f0075056f69e32a4e542f4153 /src
parentbbb320f39013bb540d69a36fe7be72c1ac6ba9d3 (diff)
Core/Items: restore item random properties handling
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp14
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp4
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp2
-rw-r--r--src/server/game/Entities/Item/Item.cpp88
-rw-r--r--src/server/game/Entities/Item/Item.h2
-rw-r--r--src/server/game/Entities/Item/ItemEnchantmentMgr.cpp151
-rw-r--r--src/server/game/Entities/Item/ItemEnchantmentMgr.h31
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.h3
-rw-r--r--src/server/game/Entities/Player/Player.cpp94
-rw-r--r--src/server/game/Entities/Player/Player.h9
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp4
-rw-r--r--src/server/game/Guilds/GuildMgr.cpp2
-rw-r--r--src/server/game/Handlers/LootHandler.cpp2
-rw-r--r--src/server/game/Handlers/QuestHandler.cpp2
-rw-r--r--src/server/game/Handlers/VoidStorageHandler.cpp5
-rw-r--r--src/server/game/Loot/Loot.cpp3
-rw-r--r--src/server/game/Loot/Loot.h1
-rw-r--r--src/server/game/Loot/LootItemStorage.cpp13
-rw-r--r--src/server/game/Loot/LootItemStorage.h1
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
-rw-r--r--src/server/game/Spells/SpellInfo.cpp7
-rw-r--r--src/server/game/World/World.cpp3
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp6
23 files changed, 304 insertions, 145 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index b4a5d2793cd..358faecb9f5 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -24,7 +24,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
m_stmts.resize(MAX_CHARACTERDATABASE_STATEMENTS);
#define SelectItemInstanceContent "ii.guid, ii.itemEntry, ii.creatorGuid, ii.giftCreatorGuid, ii.count, ii.duration, ii.charges, ii.flags, ii.enchantments, " \
- "ii.durability, ii.playedTime, ii.text, ii.battlePetSpeciesId, ii.battlePetBreedData, ii.battlePetLevel, ii.battlePetDisplayId, ii.context, " \
+ "ii.durability, ii.playedTime, ii.text, ii.battlePetSpeciesId, ii.battlePetBreedData, ii.battlePetLevel, ii.battlePetDisplayId, ii.randomPropertiesId, ii.randomPropertiesSeed, ii.context, " \
"iit.itemModifiedAppearanceAllSpecs, iit.itemModifiedAppearanceSpec1, iit.itemModifiedAppearanceSpec2, iit.itemModifiedAppearanceSpec3, iit.itemModifiedAppearanceSpec4, iit.itemModifiedAppearanceSpec5, " \
"iit.spellItemEnchantmentAllSpecs, iit.spellItemEnchantmentSpec1, iit.spellItemEnchantmentSpec2, iit.spellItemEnchantmentSpec3, iit.spellItemEnchantmentSpec4, iit.spellItemEnchantmentSpec5, " \
"iit.secondaryItemModifiedAppearanceAllSpecs, iit.secondaryItemModifiedAppearanceSpec1, iit.secondaryItemModifiedAppearanceSpec2, iit.secondaryItemModifiedAppearanceSpec3, iit.secondaryItemModifiedAppearanceSpec4, iit.itemModifiedAppearanceSpec5, " \
@@ -190,8 +190,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_ITEM_BOP_TRADE, "DELETE FROM item_soulbound_trade_data WHERE itemGuid = ? LIMIT 1", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_ITEM_BOP_TRADE, "INSERT INTO item_soulbound_trade_data VALUES (?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_REP_INVENTORY_ITEM, "REPLACE INTO character_inventory (guid, bag, slot, item) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
- PrepareStatement(CHAR_REP_ITEM_INSTANCE, "REPLACE INTO item_instance (itemEntry, owner_guid, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, durability, playedTime, text, battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, context, guid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
- PrepareStatement(CHAR_UPD_ITEM_INSTANCE, "UPDATE item_instance SET itemEntry = ?, owner_guid = ?, creatorGuid = ?, giftCreatorGuid = ?, count = ?, duration = ?, charges = ?, flags = ?, enchantments = ?, durability = ?, playedTime = ?, text = ?, battlePetSpeciesId = ?, battlePetBreedData = ?, battlePetLevel = ?, battlePetDisplayId = ?, context = ? WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_REP_ITEM_INSTANCE, "REPLACE INTO item_instance (itemEntry, owner_guid, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, durability, playedTime, text, battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, randomPropertiesId, randomPropertiesSeed, context, guid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_UPD_ITEM_INSTANCE, "UPDATE item_instance SET itemEntry = ?, owner_guid = ?, creatorGuid = ?, giftCreatorGuid = ?, count = ?, duration = ?, charges = ?, flags = ?, enchantments = ?, durability = ?, playedTime = ?, text = ?, battlePetSpeciesId = ?, battlePetBreedData = ?, battlePetLevel = ?, battlePetDisplayId = ?, randomPropertiesId = ?, randomPropertiesSeed = ?, context = ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD, "UPDATE item_instance SET duration = ?, flags = ?, durability = ? 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);
@@ -625,8 +625,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_CHAR_TRAIT_CONFIGS_BY_CHAR, "DELETE FROM character_trait_config WHERE guid = ?", CONNECTION_ASYNC);
// Void Storage
- PrepareStatement(CHAR_SEL_CHAR_VOID_STORAGE, "SELECT itemId, itemEntry, slot, creatorGuid, fixedScalingLevel, context FROM character_void_storage WHERE playerGuid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_REP_CHAR_VOID_STORAGE_ITEM, "REPLACE INTO character_void_storage (itemId, playerGuid, itemEntry, slot, creatorGuid, fixedScalingLevel, context) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHAR_VOID_STORAGE, "SELECT itemId, itemEntry, slot, creatorGuid, fixedScalingLevel, randomPropertiesId, randomPropertiesSeed, context FROM character_void_storage WHERE playerGuid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_REP_CHAR_VOID_STORAGE_ITEM, "REPLACE INTO character_void_storage (itemId, playerGuid, itemEntry, slot, creatorGuid, fixedScalingLevel, randomPropertiesId, randomPropertiesSeed, context) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_VOID_STORAGE_ITEM_BY_CHAR_GUID, "DELETE FROM character_void_storage WHERE playerGuid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_VOID_STORAGE_ITEM_BY_SLOT, "DELETE FROM character_void_storage WHERE slot = ? AND playerGuid = ?", CONNECTION_ASYNC);
@@ -637,10 +637,10 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_CHAR_CUF_PROFILES, "DELETE FROM character_cuf_profiles WHERE guid = ?", CONNECTION_ASYNC);
// Items that hold loot or money
- PrepareStatement(CHAR_SEL_ITEMCONTAINER_ITEMS, "SELECT container_id, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, context FROM item_loot_items", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_ITEMCONTAINER_ITEMS, "SELECT container_id, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, random_properties_id, random_properties_seed, context FROM item_loot_items", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_ITEMCONTAINER_ITEMS, "DELETE FROM item_loot_items WHERE container_id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ITEMCONTAINER_ITEM, "DELETE FROM item_loot_items WHERE container_id = ? AND item_id = ? AND item_count = ? AND item_index = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_INS_ITEMCONTAINER_ITEMS, "INSERT INTO item_loot_items (container_id, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, context) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_ITEMCONTAINER_ITEMS, "INSERT INTO item_loot_items (container_id, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, random_properties_id, random_properties_seed, context) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_ITEMCONTAINER_MONEY, "SELECT container_id, money FROM item_loot_money", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_ITEMCONTAINER_MONEY, "DELETE FROM item_loot_money WHERE container_id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_ITEMCONTAINER_MONEY, "INSERT INTO item_loot_money (container_id, money) VALUES (?, ?)", CONNECTION_ASYNC);
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index 7e72ffdb8d7..0d149078279 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -525,12 +525,12 @@ void AuctionHouseMgr::LoadAuctions()
}
Item* item = NewItemOrBag(proto);
- if (!item->LoadFromDB(itemGuid, ObjectGuid::Create<HighGuid::Player>(fields[44].GetUInt64()), fields, itemEntry))
+ if (!item->LoadFromDB(itemGuid, ObjectGuid::Create<HighGuid::Player>(fields[46].GetUInt64()), fields, itemEntry))
{
delete item;
continue;
}
- uint32 auctionId = fields[45].GetUInt32();
+ uint32 auctionId = fields[47].GetUInt32();
itemsByAuction[auctionId].push_back(item);
++count;
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index 6b50a5cfc07..bae0ec127b6 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -770,6 +770,8 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul
LOAD_DB2(sItemModifiedAppearanceExtraStore);
LOAD_DB2(sItemNameDescriptionStore);
LOAD_DB2(sItemPriceBaseStore);
+ LOAD_DB2(sItemRandomPropertiesStore);
+ LOAD_DB2(sItemRandomSuffixStore);
LOAD_DB2(sItemSearchNameStore);
LOAD_DB2(sItemSetStore);
LOAD_DB2(sItemSetSpellStore);
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index be53397f52e..700c841b398 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -431,6 +431,8 @@ void Item::SaveToDB(CharacterDatabaseTransaction trans)
stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_BATTLE_PET_BREED_DATA));
stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_BATTLE_PET_LEVEL));
stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_BATTLE_PET_DISPLAY_ID));
+ stmt->setInt32(++index, m_itemData->RandomPropertiesID);
+ stmt->setInt32(++index, m_itemData->PropertySeed);
stmt->setUInt8(++index, uint8(m_itemData->Context));
stmt->setUInt64(++index, GetGUID().GetCounter());
@@ -662,47 +664,48 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
SetModifier(ITEM_MODIFIER_BATTLE_PET_LEVEL, fields[14].GetUInt16());
SetModifier(ITEM_MODIFIER_BATTLE_PET_DISPLAY_ID, fields[15].GetUInt32());
- SetContext(ItemContext(fields[16].GetUInt8()));
+ SetItemRandomProperties(ItemRandomProperties(fields[16].GetInt32(), fields[17].GetInt32()));
+ SetContext(ItemContext(fields[18].GetUInt8()));
// load charges after bonuses, they can add more item effects
std::vector<std::string_view> tokens = Trinity::Tokenize(fields[6].GetStringView(), ' ', false);
for (uint8 i = 0; i < m_itemData->SpellCharges.size() && i < _bonusData.EffectCount && i < tokens.size(); ++i)
SetSpellCharges(i, Trinity::StringTo<int32>(tokens[i]).value_or(0));
- SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS, fields[17].GetUInt32());
- SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_1, fields[18].GetUInt32());
- SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_2, fields[19].GetUInt32());
- SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_3, fields[20].GetUInt32());
- SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_4, fields[21].GetUInt32());
- SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_5, fields[22].GetUInt32());
-
- SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_ALL_SPECS, fields[23].GetUInt32());
- SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_1, fields[24].GetUInt32());
- SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_2, fields[25].GetUInt32());
- SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_3, fields[26].GetUInt32());
- SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_4, fields[27].GetUInt32());
- SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_5, fields[28].GetUInt32());
-
- SetModifier(ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_ALL_SPECS, fields[29].GetUInt32());
- SetModifier(ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_1, fields[30].GetUInt32());
- SetModifier(ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_2, fields[31].GetUInt32());
- SetModifier(ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_3, fields[32].GetUInt32());
- SetModifier(ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_4, fields[33].GetUInt32());
- SetModifier(ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_5, fields[34].GetUInt32());
+ SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS, fields[19].GetUInt32());
+ SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_1, fields[20].GetUInt32());
+ SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_2, fields[21].GetUInt32());
+ SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_3, fields[22].GetUInt32());
+ SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_4, fields[23].GetUInt32());
+ SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_5, fields[24].GetUInt32());
+
+ SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_ALL_SPECS, fields[25].GetUInt32());
+ SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_1, fields[26].GetUInt32());
+ SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_2, fields[27].GetUInt32());
+ SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_3, fields[28].GetUInt32());
+ SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_4, fields[29].GetUInt32());
+ SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_5, fields[30].GetUInt32());
+
+ SetModifier(ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_ALL_SPECS, fields[31].GetUInt32());
+ SetModifier(ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_1, fields[32].GetUInt32());
+ SetModifier(ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_2, fields[33].GetUInt32());
+ SetModifier(ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_3, fields[34].GetUInt32());
+ SetModifier(ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_4, fields[35].GetUInt32());
+ SetModifier(ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_5, fields[36].GetUInt32());
uint32 const gemFields = 3;
ItemDynamicFieldGems gemData[MAX_GEM_SOCKETS];
memset(gemData, 0, sizeof(gemData));
for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i)
{
- gemData[i].ItemId = fields[35 + i * gemFields].GetUInt32();
- std::vector<std::string_view> gemBonusListIDs = Trinity::Tokenize(fields[36 + i * gemFields].GetStringView(), ' ', false);
+ gemData[i].ItemId = fields[37 + i * gemFields].GetUInt32();
+ std::vector<std::string_view> gemBonusListIDs = Trinity::Tokenize(fields[38 + i * gemFields].GetStringView(), ' ', false);
uint32 b = 0;
for (std::string_view token : gemBonusListIDs)
if (Optional<uint16> bonusListID = Trinity::StringTo<uint16>(token))
gemData[i].BonusListIDs[b++] = *bonusListID;
- gemData[i].Context = fields[37 + i * gemFields].GetUInt8();
+ gemData[i].Context = fields[39 + i * gemFields].GetUInt8();
if (gemData[i].ItemId)
SetGem(i, &gemData[i]);
}
@@ -800,6 +803,43 @@ uint32 Item::GetSkill()
return proto->GetSkill();
}
+void Item::SetItemRandomProperties(ItemRandomProperties randomProperties)
+{
+ if (!randomProperties.RandomPropertiesID)
+ return;
+
+ if (randomProperties.RandomPropertiesID > 0)
+ {
+ ItemRandomPropertiesEntry const* randomPropertiesEntry = sItemRandomPropertiesStore.LookupEntry(randomProperties.RandomPropertiesID);
+ if (randomPropertiesEntry)
+ {
+ if (m_itemData->RandomPropertiesID != randomProperties.RandomPropertiesID)
+ {
+ SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::RandomPropertiesID), randomProperties.RandomPropertiesID);
+ SetState(ITEM_CHANGED, GetOwner());
+ }
+ for (uint32 i = PROP_ENCHANTMENT_SLOT_2; i < PROP_ENCHANTMENT_SLOT_2 + 3; ++i)
+ SetEnchantment(EnchantmentSlot(i), randomPropertiesEntry->Enchantment[i - PROP_ENCHANTMENT_SLOT_2], 0, 0);
+ }
+ }
+ else
+ {
+ ItemRandomSuffixEntry const* randomSuffixEntry = sItemRandomSuffixStore.LookupEntry(std::abs(randomProperties.RandomPropertiesID));
+ if (randomSuffixEntry)
+ {
+ if (m_itemData->RandomPropertiesID != randomProperties.RandomPropertiesID || !m_itemData->PropertySeed)
+ {
+ SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::RandomPropertiesID), randomProperties.RandomPropertiesID);
+ SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::PropertySeed), randomProperties.RandomPropertiesSeed);
+ SetState(ITEM_CHANGED, GetOwner());
+ }
+
+ for (uint32 i = PROP_ENCHANTMENT_SLOT_0; i < PROP_ENCHANTMENT_SLOT_0 + 3; ++i)
+ SetEnchantment(EnchantmentSlot(i), randomSuffixEntry->Enchantment[i - PROP_ENCHANTMENT_SLOT_0], 0, 0);
+ }
+ }
+}
+
void Item::SetState(ItemUpdateState state, Player* forplayer)
{
if (uState == ITEM_NEW && state == ITEM_REMOVED)
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index 3ddfc5a2c78..5b45452be49 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -221,6 +221,8 @@ class TC_GAME_API Item : public Object
uint32 GetSkill();
+ void SetItemRandomProperties(ItemRandomProperties randomProperties);
+
void SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint32 charges, ObjectGuid caster = ObjectGuid::Empty);
void SetEnchantmentDuration(EnchantmentSlot slot, uint32 duration, Player* owner);
void SetEnchantmentCharges(EnchantmentSlot slot, uint32 charges);
diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp
index e13ea59471b..3634f5c8ed4 100644
--- a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp
+++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp
@@ -26,64 +26,81 @@
#include <list>
#include <vector>
-namespace
+/*static*/ ItemEnchantmentMgr* ItemEnchantmentMgr::instance()
{
- struct RandomBonusListIds
- {
- std::vector<int32> BonusListIDs;
- std::vector<double> Chances;
- };
-
- std::unordered_map<uint32, RandomBonusListIds> _storage;
+ static ItemEnchantmentMgr instance;
+ return &instance;
}
-ItemRandomBonusListId GenerateItemRandomBonusListId(uint32 item_id)
+void ItemEnchantmentMgr::LoadRandomEnchantmentsTable()
{
- ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(item_id);
- if (!itemProto)
- return 0;
+ uint32 oldMSTime = getMSTime();
- // item must have one from this field values not null if it can have random enchantments
- if (!itemProto->RandomBonusListTemplateId)
- return 0;
+ _storage.clear();
+
+ // 0 1 2
+ QueryResult result = WorldDatabase.Query("SELECT Id, EnchantmentId, Chance FROM item_random_enchantment_template");
- auto tab = _storage.find(itemProto->RandomBonusListTemplateId);
- if (tab == _storage.end())
+ if (result)
{
- TC_LOG_ERROR("sql.sql", "Item RandomBonusListTemplateId id #{} used in `item_template_addon` but it does not have records in `item_random_bonus_list_template` table.", itemProto->RandomBonusListTemplateId);
- return 0;
- }
+ uint32 count = 0;
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 id = fields[0].GetUInt32();
+ uint32 enchantmentId = fields[1].GetUInt32();
+ float chance = fields[2].GetFloat();
+
+ if (!sItemRandomPropertiesStore.LookupEntry(enchantmentId) && !sItemRandomSuffixStore.LookupEntry(enchantmentId))
+ {
+ TC_LOG_ERROR("sql.sql", "ItemRandomProperties/ItemRandomSuffix Id {} used in `item_random_enchantment_template` by id {} doesn't have exist in its corresponding db2 file.", enchantmentId, id);
+ continue;
+ }
+
+ if (chance < 0.000001f || chance > 100.0f)
+ {
+ TC_LOG_ERROR("sql.sql", "Enchantment Id {} used in `item_random_enchantment_template` by id {} has invalid chance {}", enchantmentId, id, chance);
+ continue;
+ }
+
+ RandomEnchantmentData& ids = _storage[id];
+ ids.EnchantmentIDs.push_back(enchantmentId);
+ ids.Chances.push_back(chance);
- return *Trinity::Containers::SelectRandomWeightedContainerElement(tab->second.BonusListIDs, std::span(tab->second.Chances));
+ ++count;
+ } while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded {} Random item enchantment definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
+ }
+ else
+ TC_LOG_INFO("server.loading", ">> Loaded 0 Random item bonus list definitions. DB table `item_random_enchantment_template` is empty.");
}
-TC_GAME_API float GetRandomPropertyPoints(uint32 itemLevel, uint32 quality, uint32 inventoryType, uint32 subClass)
+static int32 GetRandomPropertyPoints(uint32 itemLevel, uint32 quality, uint32 inventoryType)
{
- uint32 propIndex;
+ uint32 propIndex = 0;
switch (inventoryType)
{
+ // Items of that type don`t have points
+ case INVTYPE_NON_EQUIP:
+ case INVTYPE_BAG:
+ case INVTYPE_TABARD:
+ case INVTYPE_AMMO:
+ case INVTYPE_QUIVER:
+ case INVTYPE_RELIC:
+ return 0;
+ // Select point coefficient
case INVTYPE_HEAD:
case INVTYPE_BODY:
case INVTYPE_CHEST:
case INVTYPE_LEGS:
- case INVTYPE_RANGED:
case INVTYPE_2HWEAPON:
case INVTYPE_ROBE:
- case INVTYPE_THROWN:
propIndex = 0;
break;
- case INVTYPE_RANGEDRIGHT:
- if (subClass == ITEM_SUBCLASS_WEAPON_WAND)
- propIndex = 3;
- else
- propIndex = 0;
- break;
- case INVTYPE_WEAPON:
- case INVTYPE_WEAPONMAINHAND:
- case INVTYPE_WEAPONOFFHAND:
- propIndex = 3;
- break;
case INVTYPE_SHOULDERS:
case INVTYPE_WAIST:
case INVTYPE_FEET:
@@ -99,7 +116,14 @@ TC_GAME_API float GetRandomPropertyPoints(uint32 itemLevel, uint32 quality, uint
case INVTYPE_HOLDABLE:
propIndex = 2;
break;
- case INVTYPE_RELIC:
+ case INVTYPE_WEAPON:
+ case INVTYPE_WEAPONMAINHAND:
+ case INVTYPE_WEAPONOFFHAND:
+ propIndex = 3;
+ break;
+ case INVTYPE_RANGED:
+ case INVTYPE_THROWN:
+ case INVTYPE_RANGEDRIGHT:
propIndex = 4;
break;
default:
@@ -125,3 +149,56 @@ TC_GAME_API float GetRandomPropertyPoints(uint32 itemLevel, uint32 quality, uint
return 0;
}
+
+ItemRandomProperties ItemEnchantmentMgr::GenerateRandomProperties(uint32 itemId)
+{
+ ItemRandomProperties properties;
+ ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(itemId);
+ if (!itemProto)
+ return properties;
+
+ if (!itemProto->GetRandomSelect() && !itemProto->GetRandomSuffixGroupID())
+ return properties;
+
+ if (uint16 randomSelect = itemProto->GetRandomSelect())
+ {
+ auto tab = _storage.find(randomSelect);
+ if (tab == _storage.end())
+ {
+ TC_LOG_ERROR("sql.sql", "Item RandomSelect Id {} used but it does not have records in `item_random_enchantment_template` table.", randomSelect);
+ return properties;
+ }
+
+ uint32 randomPropertiesId = *Trinity::Containers::SelectRandomWeightedContainerElement(tab->second.EnchantmentIDs, std::span(tab->second.Chances));
+ ItemRandomPropertiesEntry const* randomPropertiesEntry = sItemRandomPropertiesStore.LookupEntry(randomPropertiesId);
+ if (!randomPropertiesEntry)
+ {
+ TC_LOG_ERROR("sql.sql", "Enchantment Id {} used but it doesn't have records in 'ItemRandomProperties.db2'", randomPropertiesId);
+ return properties;
+ }
+
+ properties.RandomPropertiesID = static_cast<int32>(randomPropertiesEntry->ID);
+ }
+ else if (uint16 randomSuffix = itemProto->GetRandomSuffixGroupID())
+ {
+ auto tab = _storage.find(randomSuffix);
+ if (tab == _storage.end())
+ {
+ TC_LOG_ERROR("sql.sql", "Item RandomSuffixGroupID Id {} used but it does not have records in `item_random_enchantment_template` table.", randomSuffix);
+ return properties;
+ }
+
+ uint32 randomSuffixId = *Trinity::Containers::SelectRandomWeightedContainerElement(tab->second.EnchantmentIDs, std::span(tab->second.Chances));
+ ItemRandomSuffixEntry const* randomSuffixEntry = sItemRandomSuffixStore.LookupEntry(randomSuffixId);
+ if (!randomSuffixEntry)
+ {
+ TC_LOG_ERROR("sql.sql", "Enchantment id Id {} used but it doesn't have records in 'ItemRandomSuffixEntry.db2'", randomSuffixId);
+ return properties;
+ }
+
+ properties.RandomPropertiesID = -static_cast<int32>(randomSuffixEntry->ID);
+ properties.RandomPropertiesSeed = GetRandomPropertyPoints(itemProto->GetItemLevel(), itemProto->GetQuality(), itemProto->GetInventoryType());
+ }
+
+ return properties;
+}
diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.h b/src/server/game/Entities/Item/ItemEnchantmentMgr.h
index 05000adf6e2..6bfc43ab36f 100644
--- a/src/server/game/Entities/Item/ItemEnchantmentMgr.h
+++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.h
@@ -20,9 +20,34 @@
#include "Common.h"
-using ItemRandomBonusListId = uint32;
+struct ItemRandomProperties
+{
+ ItemRandomProperties(int32 randomPropertiesId = 0, int32 randomPropertiesSeed = 0) : RandomPropertiesID(randomPropertiesId), RandomPropertiesSeed(randomPropertiesSeed) { }
-TC_GAME_API ItemRandomBonusListId GenerateItemRandomBonusListId(uint32 item_id);
-TC_GAME_API float GetRandomPropertyPoints(uint32 itemLevel, uint32 quality, uint32 inventoryType, uint32 subclass);
+ int32 RandomPropertiesID = 0;
+ int32 RandomPropertiesSeed = 0;
+};
+
+
+struct RandomEnchantmentData
+{
+ std::vector<uint16> EnchantmentIDs;
+ std::vector<double> Chances;
+};
+
+
+class TC_GAME_API ItemEnchantmentMgr
+{
+public:
+ static ItemEnchantmentMgr* instance();
+
+ void LoadRandomEnchantmentsTable();
+ ItemRandomProperties GenerateRandomProperties(uint32 itemId);
+
+private:
+ std::unordered_map<uint32, RandomEnchantmentData> _storage;
+};
+
+#define sItemEnchantmentMgr ItemEnchantmentMgr::instance()
#endif
diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h
index 6f824208833..29eadab8fe7 100644
--- a/src/server/game/Entities/Item/ItemTemplate.h
+++ b/src/server/game/Entities/Item/ItemTemplate.h
@@ -811,6 +811,8 @@ struct TC_GAME_API ItemTemplate
int32 GetScalingStatValue() const { return BasicData->ScalingStatValue; }
uint16 GetMinDamage(uint8 index) const { return BasicData->MinDamage[index]; }
uint16 GetMaxDamage(uint8 index) const { return BasicData->MaxDamage[index]; }
+ uint16 GetRandomSuffixGroupID() const { return BasicData->ItemRandomSuffixGroupID; }
+ uint16 GetRandomSelect() const { return BasicData->RandomSelect; }
uint32 MaxDurability;
std::vector<ItemEffectEntry const*> Effects;
@@ -822,7 +824,6 @@ struct TC_GAME_API ItemTemplate
uint32 MaxMoneyLoot;
uint32 FlagsCu;
float SpellPPMRate;
- uint32 RandomBonusListTemplateId;
std::bitset<MAX_CLASSES * MAX_SPECIALIZATIONS> Specializations[3]; // one set for 1-40 level range and another for 41-109 and one for 110
uint32 ItemSpecClassMask;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 3d5ba089e49..a93c6444d3b 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -588,7 +588,7 @@ bool Player::StoreNewItemInBestSlots(uint32 itemId, uint32 amount, ItemContext c
InventoryResult msg = CanStoreNewItem(INVENTORY_SLOT_BAG_0, NULL_SLOT, sDest, itemId, amount);
if (msg == EQUIP_ERR_OK)
{
- StoreNewItem(sDest, itemId, true, GuidSet(), context);
+ StoreNewItem(sDest, itemId, true, sItemEnchantmentMgr->GenerateRandomProperties(itemId), GuidSet(), context);
return true; // stored
}
@@ -3934,7 +3934,7 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
do
{
Field* fields = resultItems->Fetch();
- uint64 mailId = fields[44].GetUInt64();
+ uint64 mailId = fields[46].GetUInt64();
if (Item* mailItem = _LoadMailedItem(playerguid, nullptr, mailId, nullptr, fields))
itemsByMail[mailId].push_back(mailItem);
@@ -11199,7 +11199,7 @@ InventoryResult Player::CanRollNeedForItem(ItemTemplate const* proto, Map const*
}
// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
-Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool update, GuidSet const& allowedLooters /*= GuidSet()*/, ItemContext context /*= ItemContext::NONE*/, bool addToCollection /*= true*/)
+Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool update, ItemRandomProperties randomProperties /*= ItemRandomProperties()*/, GuidSet const& allowedLooters /*= GuidSet()*/, ItemContext context /*= ItemContext::NONE*/, bool addToCollection /*= true*/)
{
uint32 count = 0;
for (ItemPosCountVec::const_iterator itr = pos.begin(); itr != pos.end(); ++itr)
@@ -11216,6 +11216,7 @@ Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool updat
UpdateCriteria(CriteriaType::AcquireItem, itemId, count);
item->SetFixedLevel(GetLevel());
+ item->SetItemRandomProperties(randomProperties);
if (allowedLooters.size() > 1 && item->GetTemplate()->GetMaxStackSize() == 1 && item->IsSoulBound())
{
@@ -13167,50 +13168,42 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
}
break;
case ITEM_ENCHANTMENT_TYPE_RESISTANCE:
- if (pEnchant->ScalingClass)
+ if (!enchant_amount)
{
- int32 scalingClass = pEnchant->ScalingClass;
- if ((*m_unitData->MinItemLevel || *m_unitData->MaxItemLevel) && pEnchant->ScalingClassRestricted)
- scalingClass = pEnchant->ScalingClassRestricted;
-
- uint8 minLevel = pEnchant->GetFlags().HasFlag(SpellItemEnchantmentFlags::ScaleAsAGem) ? 1 : 60;
- uint8 scalingLevel = GetLevel();
- uint8 maxLevel = uint8(pEnchant->MaxLevel ? pEnchant->MaxLevel : sSpellScalingGameTable.GetTableRowCount() - 1);
-
- if (minLevel > GetLevel())
- scalingLevel = minLevel;
- else if (maxLevel < GetLevel())
- scalingLevel = maxLevel;
-
- if (GtSpellScalingEntry const* spellScaling = sSpellScalingGameTable.GetRow(scalingLevel))
- enchant_amount = uint32(pEnchant->EffectScalingPoints[s] * GetSpellScalingColumnForClass(spellScaling, scalingClass));
+ ItemRandomSuffixEntry const* randomSuffixEntries = sItemRandomSuffixStore.LookupEntry(std::abs(item->m_itemData->RandomPropertiesID));
+ if (randomSuffixEntries)
+ {
+ for (int k = 0; k < MAX_ITEM_ENCHANTMENT_EFFECTS; ++k)
+ {
+ if (randomSuffixEntries->Enchantment[k] == enchant_id)
+ {
+ enchant_amount = uint32((static_cast<double>(randomSuffixEntries->AllocationPct[k]) * item->m_itemData->PropertySeed) / 10000);
+ break;
+ }
+ }
+ }
}
- enchant_amount = std::max(enchant_amount, 1u);
+
HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply);
break;
case ITEM_ENCHANTMENT_TYPE_STAT:
{
- if (pEnchant->ScalingClass)
+ if (!enchant_amount)
{
- int32 scalingClass = pEnchant->ScalingClass;
- if ((*m_unitData->MinItemLevel || *m_unitData->MaxItemLevel) && pEnchant->ScalingClassRestricted)
- scalingClass = pEnchant->ScalingClassRestricted;
-
- uint8 minLevel = pEnchant->GetFlags().HasFlag(SpellItemEnchantmentFlags::ScaleAsAGem) ? 1 : 60;
- uint8 scalingLevel = GetLevel();
- uint8 maxLevel = uint8(pEnchant->MaxLevel ? pEnchant->MaxLevel : sSpellScalingGameTable.GetTableRowCount() - 1);
-
- if (minLevel > GetLevel())
- scalingLevel = minLevel;
- else if (maxLevel < GetLevel())
- scalingLevel = maxLevel;
-
- if (GtSpellScalingEntry const* spellScaling = sSpellScalingGameTable.GetRow(scalingLevel))
- enchant_amount = uint32(pEnchant->EffectScalingPoints[s] * GetSpellScalingColumnForClass(spellScaling, scalingClass));
+ ItemRandomSuffixEntry const* randomSuffixEntry = sItemRandomSuffixStore.LookupEntry(std::abs(item->m_itemData->RandomPropertiesID));
+ if (randomSuffixEntry)
+ {
+ for (uint8 k = 0; k < MAX_ITEM_ENCHANTMENT_EFFECTS; ++k)
+ {
+ if (randomSuffixEntry->Enchantment[k] == enchant_id)
+ {
+ enchant_amount = uint32((static_cast<double>(randomSuffixEntry->AllocationPct[k]) * item->m_itemData->PropertySeed) / 10000);
+ break;
+ }
+ }
+ }
}
- enchant_amount = std::max(enchant_amount, 1u);
-
TC_LOG_DEBUG("entities.player.items", "Adding {} to stat nb {}", enchant_amount, enchant_spell_id);
switch (enchant_spell_id)
{
@@ -14603,7 +14596,7 @@ void Player::RewardQuestPackage(uint32 questPackageId, ItemContext context, uint
ItemPosCountVec dest;
if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemQuantity) == EQUIP_ERR_OK)
{
- Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, {}, context);
+ Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, sItemEnchantmentMgr->GenerateRandomProperties(questPackageItem->ItemID), {}, context);
SendNewItem(item, questPackageItem->ItemQuantity, true, false);
}
}
@@ -14622,7 +14615,7 @@ void Player::RewardQuestPackage(uint32 questPackageId, ItemContext context, uint
ItemPosCountVec dest;
if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemQuantity) == EQUIP_ERR_OK)
{
- Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, {}, context);
+ Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, sItemEnchantmentMgr->GenerateRandomProperties(questPackageItem->ItemID), {}, context);
SendNewItem(item, questPackageItem->ItemQuantity, true, false);
}
}
@@ -14682,7 +14675,7 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew
ItemPosCountVec dest;
if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, quest->RewardItemCount[i]) == EQUIP_ERR_OK)
{
- Item* item = StoreNewItem(dest, itemId, true, {}, ItemContext::Quest_Reward);
+ Item* item = StoreNewItem(dest, itemId, true, sItemEnchantmentMgr->GenerateRandomProperties(itemId), {}, ItemContext::Quest_Reward);
SendNewItem(item, quest->RewardItemCount[i], true, false);
}
else if (quest->IsDFQuest())
@@ -14727,7 +14720,7 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew
ItemPosCountVec dest;
if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, rewardId, quest->RewardChoiceItemCount[i]) == EQUIP_ERR_OK)
{
- Item* item = StoreNewItem(dest, rewardId, true, {}, ItemContext::Quest_Reward);
+ Item* item = StoreNewItem(dest, rewardId, true, sItemEnchantmentMgr->GenerateRandomProperties(rewardId), {}, ItemContext::Quest_Reward);
SendNewItem(item, quest->RewardChoiceItemCount[i], true, false);
}
}
@@ -18062,8 +18055,8 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
Field* fields = result->Fetch();
if (Item* item = _LoadItem(trans, zoneId, timeDiff, fields))
{
- ObjectGuid bagGuid = fields[44].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[44].GetUInt64()) : ObjectGuid::Empty;
- uint8 slot = fields[45].GetUInt8();
+ ObjectGuid bagGuid = fields[46].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[44].GetUInt64()) : ObjectGuid::Empty;
+ uint8 slot = fields[47].GetUInt8();
GetSession()->GetCollectionMgr()->CheckHeirloomUpgrades(item);
GetSession()->GetCollectionMgr()->AddItemAppearance(item);
@@ -18188,6 +18181,7 @@ void Player::_LoadVoidStorage(PreparedQueryResult result)
uint8 slot = fields[2].GetUInt8();
ObjectGuid creatorGuid = fields[3].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[3].GetUInt64()) : ObjectGuid::Empty;
uint32 fixedScalingLevel = fields[4].GetUInt32();
+ ItemRandomProperties randomProperties = ItemRandomProperties(fields[5].GetInt32(), fields[6].GetInt32());
ItemContext context = ItemContext(fields[5].GetUInt8());
if (!itemId)
{
@@ -18210,7 +18204,7 @@ void Player::_LoadVoidStorage(PreparedQueryResult result)
continue;
}
- _voidStorageItems[slot] = new VoidStorageItem(itemId, itemEntry, creatorGuid, fixedScalingLevel, context);
+ _voidStorageItems[slot] = new VoidStorageItem(itemId, itemEntry, creatorGuid, fixedScalingLevel, randomProperties, context);
WorldPackets::Item::ItemInstance voidInstance;
voidInstance.Initialize(_voidStorageItems[slot]);
@@ -19852,7 +19846,9 @@ void Player::_SaveVoidStorage(CharacterDatabaseTransaction trans)
stmt->setUInt8(3, i);
stmt->setUInt64(4, _voidStorageItems[i]->CreatorGuid.GetCounter());
stmt->setUInt32(5, _voidStorageItems[i]->FixedScalingLevel);
- stmt->setUInt8(6, AsUnderlyingType(_voidStorageItems[i]->Context));
+ stmt->setInt32(6, _voidStorageItems[i]->RandomProperties.RandomPropertiesID);
+ stmt->setInt32(7, _voidStorageItems[i]->RandomProperties.RandomPropertiesSeed);
+ stmt->setUInt8(8, AsUnderlyingType(_voidStorageItems[i]->Context));
}
trans->Append(stmt);
@@ -21987,7 +21983,7 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c
}
Item* it = bStore ?
- StoreNewItem(vDest, item, true, {}, ItemContext::Vendor, false) :
+ StoreNewItem(vDest, item, true, sItemEnchantmentMgr->GenerateRandomProperties(item), {}, ItemContext::Vendor, false) :
EquipNewItem(uiDest, item, ItemContext::Vendor, true);
if (it)
{
@@ -25520,7 +25516,7 @@ void Player::StoreLootItem(ObjectGuid lootWorldObjectGuid, uint8 lootSlot, Loot*
InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count);
if (msg == EQUIP_ERR_OK)
{
- Item* newitem = StoreNewItem(dest, item->itemid, true, item->GetAllowedLooters(), item->context);
+ Item* newitem = StoreNewItem(dest, item->itemid, true, sItemEnchantmentMgr->GenerateRandomProperties(item->itemid), item->GetAllowedLooters(), item->context);
if (ffaItem)
{
@@ -27367,7 +27363,7 @@ bool Player::AddItem(uint32 itemId, uint32 count)
return false;
}
- Item* item = StoreNewItem(dest, itemId, true);
+ Item* item = StoreNewItem(dest, itemId, true, sItemEnchantmentMgr->GenerateRandomProperties(itemId));
if (item)
SendNewItem(item, count, true, false);
else
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 976e52fbc93..b4a32eba905 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1006,15 +1006,16 @@ struct BGData
struct VoidStorageItem
{
VoidStorageItem() : ItemId(0), ItemEntry(0), FixedScalingLevel(0), Context(ItemContext::NONE) { }
- VoidStorageItem(uint64 id, uint32 entry, ObjectGuid const& creator, uint32 fixedScalingLevel, ItemContext context) :
- ItemId(id), ItemEntry(entry), CreatorGuid(creator), FixedScalingLevel(fixedScalingLevel), Context(context) { }
+ VoidStorageItem(uint64 id, uint32 entry, ObjectGuid const& creator, uint32 fixedScalingLevel, ItemRandomProperties randomProperties, ItemContext context) :
+ ItemId(id), ItemEntry(entry), CreatorGuid(creator), FixedScalingLevel(fixedScalingLevel), RandomProperties(randomProperties), Context(context) { }
VoidStorageItem(VoidStorageItem&& vsi) noexcept : ItemId(vsi.ItemId), ItemEntry(vsi.ItemEntry), CreatorGuid(vsi.CreatorGuid),
- FixedScalingLevel(vsi.FixedScalingLevel), Context(vsi.Context) { }
+ FixedScalingLevel(vsi.FixedScalingLevel), RandomProperties(vsi.RandomProperties), Context(vsi.Context) { }
uint64 ItemId;
uint32 ItemEntry;
ObjectGuid CreatorGuid;
uint32 FixedScalingLevel;
+ ItemRandomProperties RandomProperties;
ItemContext Context;
};
@@ -1365,7 +1366,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool HasItemTotemCategory(uint32 TotemCategory) const;
InventoryResult CanUseItem(ItemTemplate const* pItem, bool skipRequiredLevelCheck = false) const;
InventoryResult CanRollNeedForItem(ItemTemplate const* item, Map const* map, bool restrictOnlyLfg) const;
- Item* StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool update, GuidSet const& allowedLooters = GuidSet(),
+ Item* StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool update, ItemRandomProperties randomProperties = ItemRandomProperties(), GuidSet const& allowedLooters = GuidSet(),
ItemContext context = ItemContext::NONE, bool addToCollection = true);
Item* StoreItem(ItemPosCountVec const& pos, Item* pItem, bool update);
Item* EquipNewItem(uint16 pos, uint32 item, ItemContext context, bool update);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 1605dfc11cd..355f88be2c1 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -3248,7 +3248,6 @@ void ObjectMgr::LoadItemTemplates()
itemTemplate.MaxMoneyLoot = 0;
itemTemplate.FlagsCu = 0;
itemTemplate.SpellPPMRate = 0.0f;
- itemTemplate.RandomBonusListTemplateId = 0;
itemTemplate.ItemSpecClassMask = 0;
if (std::vector<ItemSpecOverrideEntry const*> const* itemSpecOverrides = sDB2Manager.GetItemSpecOverrides(sparse->ID))
@@ -3320,7 +3319,7 @@ void ObjectMgr::LoadItemTemplateAddon()
uint32 oldMSTime = getMSTime();
uint32 count = 0;
- QueryResult result = WorldDatabase.Query("SELECT Id, FlagsCu, FoodType, MinMoneyLoot, MaxMoneyLoot, SpellPPMChance, RandomBonusListTemplateId FROM item_template_addon");
+ QueryResult result = WorldDatabase.Query("SELECT Id, FlagsCu, FoodType, MinMoneyLoot, MaxMoneyLoot, SpellPPMChance FROM item_template_addon");
if (result)
{
do
@@ -3346,7 +3345,6 @@ void ObjectMgr::LoadItemTemplateAddon()
itemTemplate->MinMoneyLoot = minMoneyLoot;
itemTemplate->MaxMoneyLoot = maxMoneyLoot;
itemTemplate->SpellPPMRate = fields[5].GetFloat();
- itemTemplate->RandomBonusListTemplateId = fields[6].GetUInt32();
++count;
} while (result->NextRow());
}
diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp
index 7781fe83b85..6b2e939f2c6 100644
--- a/src/server/game/Guilds/GuildMgr.cpp
+++ b/src/server/game/Guilds/GuildMgr.cpp
@@ -431,7 +431,7 @@ void GuildMgr::LoadGuilds()
do
{
Field* fields = result->Fetch();
- uint64 guildId = fields[44].GetUInt64();
+ uint64 guildId = fields[46].GetUInt64();
if (Guild* guild = GetGuildById(guildId))
guild->LoadBankItemFromDB(fields);
diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp
index 45ac22bcef5..a6bbe5a38d8 100644
--- a/src/server/game/Handlers/LootHandler.cpp
+++ b/src/server/game/Handlers/LootHandler.cpp
@@ -462,7 +462,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPackets::Loot::MasterLootItem
}
// now move item from loot to target inventory
- Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.GetAllowedLooters(), item.context);
+ Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomProperties, item.GetAllowedLooters(), item.context);
aeResult.Add(newitem, item.count, loot->loot_type, loot->GetDungeonEncounterId());
// mark as looted
diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp
index a108fcc9fae..5cd6cb11557 100644
--- a/src/server/game/Handlers/QuestHandler.cpp
+++ b/src/server/game/Handlers/QuestHandler.cpp
@@ -834,7 +834,7 @@ void WorldSession::HandlePlayerChoiceResponse(WorldPackets::Quest::ChoiceRespons
ItemPosCountVec dest;
if (_player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.Id, item.Quantity) == EQUIP_ERR_OK)
{
- Item* newItem = _player->StoreNewItem(dest, item.Id, true, {}, ItemContext::Quest_Reward);
+ Item* newItem = _player->StoreNewItem(dest, item.Id, true, sItemEnchantmentMgr->GenerateRandomProperties(item.Id), {}, ItemContext::Quest_Reward);
_player->SendNewItem(newItem, item.Quantity, true, false);
}
}
diff --git a/src/server/game/Handlers/VoidStorageHandler.cpp b/src/server/game/Handlers/VoidStorageHandler.cpp
index d451b8a623e..24704d76c18 100644
--- a/src/server/game/Handlers/VoidStorageHandler.cpp
+++ b/src/server/game/Handlers/VoidStorageHandler.cpp
@@ -148,7 +148,8 @@ void WorldSession::HandleVoidStorageTransfer(WorldPackets::VoidStorage::VoidStor
continue;
}
- VoidStorageItem itemVS(sObjectMgr->GenerateVoidStorageItemId(), item->GetEntry(), item->GetCreator(), item->GetModifier(ITEM_MODIFIER_TIMEWALKER_LEVEL), item->GetContext());
+ VoidStorageItem itemVS(sObjectMgr->GenerateVoidStorageItemId(), item->GetEntry(), item->GetCreator(), item->GetModifier(ITEM_MODIFIER_TIMEWALKER_LEVEL),
+ ItemRandomProperties(item->m_itemData->RandomPropertiesID, item->m_itemData->PropertySeed), item->GetContext());
WorldPackets::VoidStorage::VoidItem voidItem;
voidItem.Guid = ObjectGuid::Create<HighGuid::Item>(itemVS.ItemId);
@@ -185,7 +186,7 @@ void WorldSession::HandleVoidStorageTransfer(WorldPackets::VoidStorage::VoidStor
return;
}
- Item* item = _player->StoreNewItem(dest, itemVS->ItemEntry, true, GuidSet(), itemVS->Context);
+ Item* item = _player->StoreNewItem(dest, itemVS->ItemEntry, true, itemVS->RandomProperties, GuidSet(), itemVS->Context);
item->SetCreator(itemVS->CreatorGuid);
item->SetBinding(true);
GetCollectionMgr()->AddItemAppearance(item);
diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp
index 2cc6f2b9017..02e8024221b 100644
--- a/src/server/game/Loot/Loot.cpp
+++ b/src/server/game/Loot/Loot.cpp
@@ -51,6 +51,7 @@ LootItem::LootItem(LootStoreItem const& li)
needs_quest = li.needs_quest;
+ randomProperties = sItemEnchantmentMgr->GenerateRandomProperties(itemid);
context = ItemContext::NONE;
count = 0;
is_looted = false;
@@ -885,7 +886,7 @@ bool Loot::AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast, bool
--unlootedCount;
- Item* pItem = player->StoreNewItem(dest, lootItem->itemid, true, GuidSet(), lootItem->context);
+ Item* pItem = player->StoreNewItem(dest, lootItem->itemid, true, lootItem->randomProperties, GuidSet(), lootItem->context);
player->SendNewItem(pItem, lootItem->count, false, createdByPlayer, broadcast);
player->ApplyItemLootedSpell(pItem, true);
}
diff --git a/src/server/game/Loot/Loot.h b/src/server/game/Loot/Loot.h
index f985ca71486..33bee4568c8 100644
--- a/src/server/game/Loot/Loot.h
+++ b/src/server/game/Loot/Loot.h
@@ -176,6 +176,7 @@ struct TC_GAME_API LootItem
{
uint32 itemid;
uint32 LootListId;
+ ItemRandomProperties randomProperties;
ItemContext context;
ConditionContainer conditions; // additional loot condition
GuidSet allowedGUIDs;
diff --git a/src/server/game/Loot/LootItemStorage.cpp b/src/server/game/Loot/LootItemStorage.cpp
index a580c3f3117..5953cd8a53d 100644
--- a/src/server/game/Loot/LootItemStorage.cpp
+++ b/src/server/game/Loot/LootItemStorage.cpp
@@ -35,7 +35,7 @@ namespace
StoredLootItem::StoredLootItem(LootItem const& lootItem) : ItemId(lootItem.itemid), Count(lootItem.count), ItemIndex(lootItem.LootListId), FollowRules(lootItem.follow_loot_rules),
FFA(lootItem.freeforall), Blocked(lootItem.is_blocked), Counted(lootItem.is_counted), UnderThreshold(lootItem.is_underthreshold),
-NeedsQuest(lootItem.needs_quest), Context(lootItem.context)
+NeedsQuest(lootItem.needs_quest), RandomProperties(lootItem.randomProperties), Context(lootItem.context)
{
}
@@ -79,7 +79,9 @@ void LootItemStorage::LoadStorageFromDB()
lootItem.is_counted = fields[7].GetBool();
lootItem.is_underthreshold = fields[8].GetBool();
lootItem.needs_quest = fields[9].GetBool();
- lootItem.context = ItemContext(fields[10].GetUInt8());
+ lootItem.randomProperties.RandomPropertiesID = fields[10].GetInt32();
+ lootItem.randomProperties.RandomPropertiesSeed = fields[11].GetInt32();
+ lootItem.context = ItemContext(fields[12].GetUInt8());
storedContainer.AddLootItem(lootItem, trans);
@@ -146,6 +148,7 @@ bool LootItemStorage::LoadStoredLoot(Item* item, Player* player)
li.is_counted = storedItemPair.second.Counted;
li.is_underthreshold = storedItemPair.second.UnderThreshold;
li.needs_quest = storedItemPair.second.NeedsQuest;
+ li.randomProperties = storedItemPair.second.RandomProperties;
li.context = storedItemPair.second.Context;
// Copy the extra loot conditions from the item in the loot template
@@ -276,7 +279,7 @@ void StoredLootContainer::AddLootItem(LootItem const& lootItem, CharacterDatabas
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_ITEMS);
- // container_id, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix
+ // container_id, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, random_properties_id, random_properties_seed, context
stmt->setUInt64(0, _containerId);
stmt->setUInt32(1, lootItem.itemid);
stmt->setUInt32(2, lootItem.count);
@@ -287,7 +290,9 @@ void StoredLootContainer::AddLootItem(LootItem const& lootItem, CharacterDatabas
stmt->setBool(7, lootItem.is_counted);
stmt->setBool(8, lootItem.is_underthreshold);
stmt->setBool(9, lootItem.needs_quest);
- stmt->setUInt8(10, AsUnderlyingType(lootItem.context));
+ stmt->setInt32(9, lootItem.randomProperties.RandomPropertiesID);
+ stmt->setInt32(10, lootItem.randomProperties.RandomPropertiesSeed);
+ stmt->setUInt8(11, AsUnderlyingType(lootItem.context));
trans->Append(stmt);
}
diff --git a/src/server/game/Loot/LootItemStorage.h b/src/server/game/Loot/LootItemStorage.h
index bd96cc90588..21bcfe6feec 100644
--- a/src/server/game/Loot/LootItemStorage.h
+++ b/src/server/game/Loot/LootItemStorage.h
@@ -45,6 +45,7 @@ struct StoredLootItem
bool Counted;
bool UnderThreshold;
bool NeedsQuest;
+ ItemRandomProperties RandomProperties;
ItemContext Context;
};
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index d6a7e320cd1..4984c56ab60 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -1365,7 +1365,7 @@ void Spell::DoCreateItem(uint32 itemId, ItemContext context /*= ItemContext::NON
if (num_to_add)
{
// create the new item and store it
- Item* pItem = player->StoreNewItem(dest, newitemid, true, GuidSet(), context);
+ Item* pItem = player->StoreNewItem(dest, newitemid, true, sItemEnchantmentMgr->GenerateRandomProperties(newitemid), GuidSet(), context);
// was it successful? return error if not
if (!pItem)
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 581578ebc10..eba12d8a794 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -550,7 +550,7 @@ int32 SpellEffectInfo::CalcValue(WorldObject const* caster /*= nullptr*/, int32
return int32(round(value));
}
-int32 SpellEffectInfo::CalcBaseValue(WorldObject const* caster, Unit const* target, uint32 itemId, int32 itemLevel) const
+int32 SpellEffectInfo::CalcBaseValue(WorldObject const* caster, Unit const* target, uint32 itemId, int32 /*itemLevel*/) const
{
if (Scaling.Coefficient != 0.0f)
{
@@ -575,6 +575,7 @@ int32 SpellEffectInfo::CalcBaseValue(WorldObject const* caster, Unit const* targ
if (!Scaling.Class)
return 0;
+ /*
uint32 effectiveItemLevel = itemLevel != -1 ? uint32(itemLevel) : 1u;
if (_spellInfo->Scaling.ScalesFromItemLevel || _spellInfo->HasAttribute(SPELL_ATTR11_SCALES_WITH_ITEM_LEVEL))
{
@@ -594,6 +595,7 @@ int32 SpellEffectInfo::CalcBaseValue(WorldObject const* caster, Unit const* targ
}
else
value = GetSpellScalingColumnForClass(sSpellScalingGameTable.GetRow(level), Scaling.Class);
+ */
}
value *= Scaling.Coefficient;
@@ -4250,12 +4252,15 @@ inline float CalcPPMItemLevelMod(SpellProcsPerMinuteModEntry const* mod, int32 i
if (itemLevel == mod->Param)
return 0.0f;
+ /*
float itemLevelPoints = GetRandomPropertyPoints(itemLevel, ITEM_QUALITY_RARE, INVTYPE_CHEST, 0);
float basePoints = GetRandomPropertyPoints(mod->Param, ITEM_QUALITY_RARE, INVTYPE_CHEST, 0);
if (itemLevelPoints == basePoints)
return 0.0f;
return ((itemLevelPoints / basePoints) - 1.0f) * mod->Coeff;
+ */
+ return 0;
}
float SpellInfo::CalcProcPPM(Unit* caster, int32 itemLevel) const
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index c24e120b13f..3bb2165bda1 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1963,6 +1963,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Disables"); // must be before loading quests and items
DisableMgr::LoadDisables();
+ TC_LOG_INFO("server.loading", "Loading Item Random Enchantments Table...");
+ sItemEnchantmentMgr->LoadRandomEnchantmentsTable();
+
TC_LOG_INFO("server.loading", "Loading Items..."); // must be after LoadRandomEnchantmentsTable and LoadPageTexts
sObjectMgr->LoadItemTemplates();
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 12b08a05c6d..3d1030eda32 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -1290,7 +1290,7 @@ public:
return false;
}
- Item* item = playerTarget->StoreNewItem(dest, itemId, true, GuidSet(), itemContext);
+ Item* item = playerTarget->StoreNewItem(dest, itemId, true, sItemEnchantmentMgr->GenerateRandomProperties(itemId), GuidSet(), itemContext);
// remove binding (let GM give it to another player later)
if (player == playerTarget)
@@ -1443,7 +1443,7 @@ public:
return false;
}
- Item* item = playerTarget->StoreNewItem(dest, itemId, true, GuidSet(), itemContext);
+ Item* item = playerTarget->StoreNewItem(dest, itemId, true, sItemEnchantmentMgr->GenerateRandomProperties(itemId), GuidSet(), itemContext);
// remove binding (let GM give it to another player later)
if (player == playerTarget)
@@ -1497,7 +1497,7 @@ public:
InventoryResult msg = playerTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemTemplatePair.first, 1);
if (msg == EQUIP_ERR_OK)
{
- Item* item = playerTarget->StoreNewItem(dest, itemTemplatePair.first, true, GuidSet(), itemContext);
+ Item* item = playerTarget->StoreNewItem(dest, itemTemplatePair.first, true, sItemEnchantmentMgr->GenerateRandomProperties(itemTemplatePair.first), GuidSet(), itemContext);
// remove binding (let GM give it to another player later)
if (player == playerTarget)