diff options
author | Shauren <shauren.trinity@gmail.com> | 2016-12-26 21:21:28 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2016-12-26 21:21:28 +0100 |
commit | 87427321497aad5ba3c6dbc1b7f4838f255e052b (patch) | |
tree | a3bbb5512bb04d957448fa7686dd27a998b94568 /src | |
parent | 9f81cf445ff47507a9469d57808df231460793f1 (diff) |
Core/Items: Implemented bonus list as a possible result of RandomSuffix
Ref #18423
Diffstat (limited to 'src')
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.cpp | 14 | ||||
-rw-r--r-- | src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 179 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.h | 7 | ||||
-rw-r--r-- | src/server/game/Entities/Item/ItemEnchantmentMgr.cpp | 122 | ||||
-rw-r--r-- | src/server/game/Entities/Item/ItemEnchantmentMgr.h | 20 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 57 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 8 | ||||
-rw-r--r-- | src/server/game/Groups/Group.cpp | 10 | ||||
-rw-r--r-- | src/server/game/Groups/Group.h | 2 | ||||
-rw-r--r-- | src/server/game/Guilds/Guild.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Guilds/GuildMgr.cpp | 22 | ||||
-rw-r--r-- | src/server/game/Handlers/VoidStorageHandler.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.h | 4 | ||||
-rw-r--r-- | src/server/game/Server/Packets/ItemPackets.cpp | 8 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_misc.cpp | 2 |
16 files changed, 262 insertions, 202 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 1981ffbfcec..d6cce52b283 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -22,7 +22,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() if (!m_reconnecting) 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.randomPropertyId, " \ +#define SelectItemInstanceContent "ii.guid, ii.itemEntry, ii.creatorGuid, ii.giftCreatorGuid, ii.count, ii.duration, ii.charges, ii.flags, ii.enchantments, ii.randomPropertyType, ii.randomPropertyId, " \ "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, " \ @@ -167,8 +167,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, randomPropertyId, durability, playedTime, text, upgradeId, battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, bonusListIDs, guid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_ITEM_INSTANCE, "UPDATE item_instance SET itemEntry = ?, owner_guid = ?, creatorGuid = ?, giftCreatorGuid = ?, count = ?, duration = ?, charges = ?, flags = ?, enchantments = ?, randomPropertyId = ?, durability = ?, playedTime = ?, text = ?, upgradeId = ?, battlePetSpeciesId = ?, battlePetBreedData = ?, battlePetLevel = ?, battlePetDisplayId = ?, bonusListIDs = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_REP_ITEM_INSTANCE, "REPLACE INTO item_instance (itemEntry, owner_guid, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyType, randomPropertyId, durability, playedTime, text, upgradeId, battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, bonusListIDs, guid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_ITEM_INSTANCE, "UPDATE item_instance SET itemEntry = ?, owner_guid = ?, creatorGuid = ?, giftCreatorGuid = ?, count = ?, duration = ?, charges = ?, flags = ?, enchantments = ?, randomPropertyType = ?, randomPropertyId = ?, durability = ?, playedTime = ?, text = ?, upgradeId = ?, battlePetSpeciesId = ?, battlePetBreedData = ?, battlePetLevel = ?, battlePetDisplayId = ?, bonusListIDs = ? WHERE guid = ?", CONNECTION_ASYNC); 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); @@ -620,8 +620,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_CHAR_LIST_SLOT, "UPDATE characters SET slot = ? WHERE guid = ? AND account = ?", CONNECTION_ASYNC); // Void Storage - PrepareStatement(CHAR_SEL_CHAR_VOID_STORAGE, "SELECT itemId, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs 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, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHAR_VOID_STORAGE, "SELECT itemId, itemEntry, slot, creatorGuid, randomPropertyType, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs 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, randomPropertyType, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs) 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); @@ -638,10 +638,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_GUILD_FINDER_GUILD_SETTINGS, "DELETE FROM guild_finder_guild_settings WHERE guildId = ?", CONNECTION_ASYNC); // Items that hold loot or money - PrepareStatement(CHAR_SEL_ITEMCONTAINER_ITEMS, "SELECT item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix FROM item_loot_items WHERE container_id = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_ITEMCONTAINER_ITEMS, "SELECT item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_type, rnd_prop, rnd_suffix FROM item_loot_items WHERE container_id = ?", 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 = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_ITEMCONTAINER_ITEMS, "INSERT INTO item_loot_items (container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_ITEMCONTAINER_ITEMS, "INSERT INTO item_loot_items (container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_type, rnd_prop, rnd_suffix) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_ITEMCONTAINER_MONEY, "SELECT money FROM item_loot_money WHERE container_id = ?", 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/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp index 145b0709592..83d53144a7e 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp @@ -987,8 +987,7 @@ void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config) // Update the just created item so that if it needs random properties it has them. // Ex: Notched Shortsword of Stamina will only generate as a Notched Shortsword without this. - if (int32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemId)) - item->SetItemRandomProperties(randomPropertyId); + item->SetItemRandomProperties(Item::GenerateItemRandomPropertyId(itemId)); uint32 buyoutPrice; uint32 bidPrice = 0; diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index abc7e526f30..fc8ef4755f6 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -410,7 +410,8 @@ void Item::SaveToDB(SQLTransaction& trans) } stmt->setString(++index, ssEnchants.str()); - stmt->setInt16 (++index, GetItemRandomPropertyId()); + stmt->setUInt8(++index, uint8(GetItemRandomEnchantmentId().Type)); + stmt->setUInt32(++index, GetItemRandomEnchantmentId().Id); stmt->setUInt16(++index, GetUInt32Value(ITEM_FIELD_DURABILITY)); stmt->setUInt32(++index, GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME)); stmt->setString(++index, m_text); @@ -617,17 +618,17 @@ void Item::SaveToDB(SQLTransaction& trans) bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fields, uint32 entry) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 - // SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, - // 13 14 15 16 17 18 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + // SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyType, randomPropertyId, durability, playedTime, text, + // 14 15 16 17 18 19 // upgradeId, battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, bonusListIDs, - // 19 20 21 22 23 + // 20 21 22 23 24 // itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4, - // 24 25 26 27 28 + // 25 26 27 28 29 // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4, - // 29 30 31 32 33 34 35 36 37 38 39 40 + // 30 31 32 33 34 35 36 37 38 39 40 41 // gemItemId1, gemBonuses1, gemContext1, gemScalingLevel1, gemItemId2, gemBonuses2, gemContext2, gemScalingLevel2, gemItemId3, gemBonuses3, gemContext3, gemScalingLevel3 - // 41 42 + // 42 43 // fixedScalingLevel, artifactKnowledgeLevel FROM item_instance // create item before any checks for store correct guid @@ -684,12 +685,18 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie } _LoadIntoDataField(fields[8].GetString(), ITEM_FIELD_ENCHANTMENT, MAX_ENCHANTMENT_SLOT * MAX_ENCHANTMENT_OFFSET); - SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID, fields[9].GetInt16()); - // recalculate suffix factor - if (GetItemRandomPropertyId() < 0) + m_randomEnchantment.Type = ItemRandomEnchantmentType(fields[9].GetUInt8()); + m_randomEnchantment.Id = fields[10].GetUInt32(); + if (m_randomEnchantment.Type == ItemRandomEnchantmentType::Property) + SetUInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID, m_randomEnchantment.Id); + else if (m_randomEnchantment.Type == ItemRandomEnchantmentType::Suffix) + { + SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID, -int32(m_randomEnchantment.Id)); + // recalculate suffix factor UpdateItemSuffixFactor(); + } - uint32 durability = fields[10].GetUInt16(); + uint32 durability = fields[11].GetUInt16(); SetUInt32Value(ITEM_FIELD_DURABILITY, durability); // update max durability (and durability) if need SetUInt32Value(ITEM_FIELD_MAXDURABILITY, proto->MaxDurability); @@ -699,10 +706,10 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie need_save = true; } - SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, fields[11].GetUInt32()); - SetText(fields[12].GetString()); + SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, fields[12].GetUInt32()); + SetText(fields[13].GetString()); - uint32 upgradeId = fields[13].GetUInt32(); + uint32 upgradeId = fields[14].GetUInt32(); ItemUpgradeEntry const* rulesetUpgrade = sItemUpgradeStore.LookupEntry(sDB2Manager.GetRulesetItemUpgrade(entry)); ItemUpgradeEntry const* upgrade = sItemUpgradeStore.LookupEntry(upgradeId); if (!rulesetUpgrade || !upgrade || rulesetUpgrade->ItemUpgradePathID != upgrade->ItemUpgradePathID) @@ -718,49 +725,49 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie } SetModifier(ITEM_MODIFIER_UPGRADE_ID, upgradeId); - SetModifier(ITEM_MODIFIER_BATTLE_PET_SPECIES_ID, fields[14].GetUInt32()); - SetModifier(ITEM_MODIFIER_BATTLE_PET_BREED_DATA, fields[15].GetUInt32()); - SetModifier(ITEM_MODIFIER_BATTLE_PET_LEVEL, fields[16].GetUInt16()); - SetModifier(ITEM_MODIFIER_BATTLE_PET_DISPLAY_ID, fields[17].GetUInt32()); + SetModifier(ITEM_MODIFIER_BATTLE_PET_SPECIES_ID, fields[15].GetUInt32()); + SetModifier(ITEM_MODIFIER_BATTLE_PET_BREED_DATA, fields[16].GetUInt32()); + SetModifier(ITEM_MODIFIER_BATTLE_PET_LEVEL, fields[17].GetUInt16()); + SetModifier(ITEM_MODIFIER_BATTLE_PET_DISPLAY_ID, fields[18].GetUInt32()); - Tokenizer bonusListIDs(fields[18].GetString(), ' '); + Tokenizer bonusListIDs(fields[19].GetString(), ' '); for (char const* token : bonusListIDs) { uint32 bonusListID = atoul(token); AddBonuses(bonusListID); } - 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_ALL_SPECS, fields[20].GetUInt32()); + SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_1, fields[21].GetUInt32()); + SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_2, fields[22].GetUInt32()); + SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_3, fields[23].GetUInt32()); + SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_4, fields[24].GetUInt32()); - SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_ALL_SPECS, fields[24].GetUInt32()); - SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_1, fields[25].GetUInt32()); - SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_2, fields[26].GetUInt32()); - SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_3, fields[27].GetUInt32()); - SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_4, fields[28].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()); uint32 const gemFields = 4; ItemDynamicFieldGems gemData[MAX_GEM_SOCKETS]; memset(gemData, 0, sizeof(gemData)); for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i) { - gemData[i].ItemId = fields[29 + i * gemFields].GetUInt32(); - Tokenizer gemBonusListIDs(fields[30 + i * gemFields].GetString(), ' '); + gemData[i].ItemId = fields[30 + i * gemFields].GetUInt32(); + Tokenizer gemBonusListIDs(fields[31 + i * gemFields].GetString(), ' '); uint32 b = 0; for (char const* token : gemBonusListIDs) if (uint32 bonusListID = atoul(token)) gemData[i].BonusListIDs[b++] = bonusListID; - gemData[i].Context = fields[31 + i * gemFields].GetUInt8(); + gemData[i].Context = fields[32 + i * gemFields].GetUInt8(); if (gemData[i].ItemId) - SetGem(i, &gemData[i], fields[32 + i * gemFields].GetUInt32()); + SetGem(i, &gemData[i], fields[33 + i * gemFields].GetUInt32()); } - SetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL, fields[41].GetUInt32()); - SetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL, fields[42].GetUInt32()); + SetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL, fields[42].GetUInt32()); + SetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL, fields[43].GetUInt32()); if (need_save) // normal item changed state set not work at loading { @@ -876,82 +883,69 @@ uint32 Item::GetSkill() return proto->GetSkill(); } -int32 Item::GenerateItemRandomPropertyId(uint32 item_id) +ItemRandomEnchantmentId Item::GenerateItemRandomPropertyId(uint32 item_id) { ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(item_id); - if (!itemProto) - return 0; + return{}; // item must have one from this field values not null if it can have random enchantments - if ((!itemProto->GetRandomProperty()) && (!itemProto->GetRandomSuffix())) - return 0; + if (!itemProto->GetRandomProperty() && !itemProto->GetRandomSuffix()) + return{}; // item can have not null only one from field values - if ((itemProto->GetRandomProperty()) && (itemProto->GetRandomSuffix())) + if (itemProto->GetRandomProperty() && itemProto->GetRandomSuffix()) { TC_LOG_ERROR("sql.sql", "Item template %u have RandomProperty == %u and RandomSuffix == %u, but must have one from field =0", itemProto->GetId(), itemProto->GetRandomProperty(), itemProto->GetRandomSuffix()); - return 0; + return{}; } // RandomProperty case if (itemProto->GetRandomProperty()) - { - uint32 randomPropId = GetItemEnchantMod(itemProto->GetRandomProperty()); - if (!sItemRandomPropertiesStore.LookupEntry(randomPropId)) - { - TC_LOG_ERROR("sql.sql", "Enchantment id #%u used but it doesn't have records in 'ItemRandomProperties.dbc'", randomPropId); - return 0; - } - - return randomPropId; - } + return GetItemEnchantMod(itemProto->GetRandomProperty(), ItemRandomEnchantmentType::Property); // RandomSuffix case else - { - uint32 randomPropId = GetItemEnchantMod(itemProto->GetRandomSuffix()); - if (!sItemRandomSuffixStore.LookupEntry(randomPropId)) - { - TC_LOG_ERROR("sql.sql", "Enchantment id #%u used but it doesn't have records in sItemRandomSuffixStore.", randomPropId); - return 0; - } - - return -int32(randomPropId); - } + return GetItemEnchantMod(itemProto->GetRandomSuffix(), ItemRandomEnchantmentType::Suffix); } -void Item::SetItemRandomProperties(int32 randomPropId) +void Item::SetItemRandomProperties(ItemRandomEnchantmentId const& randomPropId) { - if (!randomPropId) + if (!randomPropId.Id) return; - if (randomPropId > 0) + switch (randomPropId.Type) { - if (ItemRandomPropertiesEntry const* item_rand = sItemRandomPropertiesStore.LookupEntry(randomPropId)) - { - if (GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID) != randomPropId) + case ItemRandomEnchantmentType::Property: + if (ItemRandomPropertiesEntry const* item_rand = sItemRandomPropertiesStore.LookupEntry(randomPropId.Id)) { - SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID, randomPropId); - SetState(ITEM_CHANGED, GetOwner()); + if (GetUInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID) != randomPropId.Id) + { + SetUInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID, randomPropId.Id); + SetState(ITEM_CHANGED, GetOwner()); + } + for (uint32 i = PROP_ENCHANTMENT_SLOT_0; i <= PROP_ENCHANTMENT_SLOT_4; ++i) + SetEnchantment(EnchantmentSlot(i), item_rand->Enchantment[i - PROP_ENCHANTMENT_SLOT_0], 0, 0); } - for (uint32 i = PROP_ENCHANTMENT_SLOT_1; i < PROP_ENCHANTMENT_SLOT_1 + 3; ++i) - SetEnchantment(EnchantmentSlot(i), item_rand->Enchantment[i - PROP_ENCHANTMENT_SLOT_1], 0, 0); - } - } - else - { - if (ItemRandomSuffixEntry const* item_rand = sItemRandomSuffixStore.LookupEntry(-randomPropId)) - { - if (GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID) != randomPropId || !GetItemSuffixFactor()) + break; + case ItemRandomEnchantmentType::Suffix: + if (ItemRandomSuffixEntry const* item_rand = sItemRandomSuffixStore.LookupEntry(randomPropId.Id)) { - SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID, randomPropId); - UpdateItemSuffixFactor(); - SetState(ITEM_CHANGED, GetOwner()); - } + if (GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID) != -int32(randomPropId.Id) || !GetItemSuffixFactor()) + { + SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID, -int32(randomPropId.Id)); + UpdateItemSuffixFactor(); + SetState(ITEM_CHANGED, GetOwner()); + } - for (uint32 i = PROP_ENCHANTMENT_SLOT_0; i <= PROP_ENCHANTMENT_SLOT_4; ++i) - SetEnchantment(EnchantmentSlot(i), item_rand->Enchantment[i - PROP_ENCHANTMENT_SLOT_0], 0, 0); - } + for (uint32 i = PROP_ENCHANTMENT_SLOT_0; i <= PROP_ENCHANTMENT_SLOT_4; ++i) + SetEnchantment(EnchantmentSlot(i), item_rand->Enchantment[i - PROP_ENCHANTMENT_SLOT_0], 0, 0); + } + break; + case ItemRandomEnchantmentType::BonusList: + AddBonuses(randomPropId.Id); + break; + default: + break; } } @@ -1412,7 +1406,7 @@ Item* Item::CloneItem(uint32 count, Player const* player) const newItem->SetUInt32Value(ITEM_FIELD_DURATION, GetUInt32Value(ITEM_FIELD_DURATION)); // player CAN be NULL in which case we must not update random properties because that accesses player's item update queue if (player) - newItem->SetItemRandomProperties(GetItemRandomPropertyId()); + newItem->SetItemRandomProperties(GetItemRandomEnchantmentId()); return newItem; } @@ -2048,8 +2042,9 @@ void Item::ItemContainerSaveLootToDB() stmt_items->setBool(6, _li->is_counted); stmt_items->setBool(7, _li->is_underthreshold); stmt_items->setBool(8, _li->needs_quest); - stmt_items->setInt32(9, _li->randomPropertyId); - stmt_items->setUInt32(10, _li->randomSuffix); + stmt_items->setUInt8(9, uint8(_li->randomPropertyId.Type)); + stmt_items->setUInt32(10, _li->randomPropertyId.Id); + stmt_items->setUInt32(11, _li->randomSuffix); trans->Append(stmt_items); } } @@ -2107,8 +2102,8 @@ bool Item::ItemContainerLoadLootFromDB() loot_item.canSave = true; loot_item.is_underthreshold = fields[6].GetBool(); loot_item.needs_quest = fields[7].GetBool(); - loot_item.randomPropertyId = fields[8].GetInt32(); - loot_item.randomSuffix = fields[9].GetUInt32(); + loot_item.randomPropertyId = { ItemRandomEnchantmentType(fields[8].GetUInt8()), fields[9].GetUInt32() }; + loot_item.randomSuffix = fields[10].GetUInt32(); // Copy the extra loot conditions from the item in the loot template lt->CopyConditions(&loot_item); diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 6fdc8e212b4..bef82a76013 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -22,6 +22,7 @@ #include "Common.h" #include "Object.h" #include "LootMgr.h" +#include "ItemEnchantmentMgr.h" #include "ItemTemplate.h" #include "DatabaseEnv.h" @@ -395,9 +396,10 @@ class TC_GAME_API Item : public Object // RandomPropertyId (signed but stored as unsigned) int32 GetItemRandomPropertyId() const { return GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID); } uint32 GetItemSuffixFactor() const { return GetUInt32Value(ITEM_FIELD_PROPERTY_SEED); } - void SetItemRandomProperties(int32 randomPropId); + void SetItemRandomProperties(ItemRandomEnchantmentId const& randomPropId); void UpdateItemSuffixFactor(); - static int32 GenerateItemRandomPropertyId(uint32 item_id); + static ItemRandomEnchantmentId GenerateItemRandomPropertyId(uint32 item_id); + ItemRandomEnchantmentId GetItemRandomEnchantmentId() const { return m_randomEnchantment; } 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); @@ -528,6 +530,7 @@ class TC_GAME_API Item : public Object uint32 m_paidMoney; uint32 m_paidExtendedCost; GuidSet allowedGUIDs; + ItemRandomEnchantmentId m_randomEnchantment; // store separately to easily find which bonus list is the one randomly given for stat rerolling ObjectGuid m_childItem; std::unordered_map<uint32, uint16> m_artifactPowerIdToIndex; std::array<uint32, MAX_ITEM_PROTO_SOCKETS> m_gemScalingLevels; diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp index ac9000ded5e..f2723a97981 100644 --- a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp +++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp @@ -17,6 +17,7 @@ */ #include "ItemEnchantmentMgr.h" +#include "Containers.h" #include "DatabaseEnv.h" #include "Log.h" #include "ObjectMgr.h" @@ -28,29 +29,41 @@ struct EnchStoreItem { + ItemRandomEnchantmentType type; uint32 ench; float chance; EnchStoreItem() - : ench(0), chance(0) { } + : type(ItemRandomEnchantmentType::Property), ench(0), chance(0) { } - EnchStoreItem(uint32 _ench, float _chance) - : ench(_ench), chance(_chance) { } + EnchStoreItem(ItemRandomEnchantmentType _type, uint32 _ench, float _chance) + : type(_type), ench(_ench), chance(_chance) { } }; typedef std::vector<EnchStoreItem> EnchStoreList; -typedef std::unordered_map<uint32, EnchStoreList> EnchantmentStore; -static EnchantmentStore RandomItemEnch; +class EnchantmentStore +{ + std::unordered_map<uint32, EnchStoreList> _data[2]; + +public: + std::unordered_map<uint32, EnchStoreList>& operator[](ItemRandomEnchantmentType type) + { + ASSERT(type != ItemRandomEnchantmentType::BonusList, "Random bonus lists do not have their own storage, use Suffix for them"); + return _data[uint8(type)]; + } + +} static RandomItemEnch; void LoadRandomEnchantmentsTable() { uint32 oldMSTime = getMSTime(); - RandomItemEnch.clear(); // for reload case + RandomItemEnch[ItemRandomEnchantmentType::Property].clear(); + RandomItemEnch[ItemRandomEnchantmentType::Suffix].clear(); - // 0 1 2 - QueryResult result = WorldDatabase.Query("SELECT entry, ench, chance FROM item_enchantment_template"); + // 0 1 2 3 + QueryResult result = WorldDatabase.Query("SELECT entry, type, ench, chance FROM item_enchantment_template"); if (result) { @@ -61,11 +74,56 @@ void LoadRandomEnchantmentsTable() Field* fields = result->Fetch(); uint32 entry = fields[0].GetUInt32(); - uint32 ench = fields[1].GetUInt32(); - float chance = fields[2].GetFloat(); - - if (chance > 0.000001f && chance <= 100.0f) - RandomItemEnch[entry].push_back(EnchStoreItem(ench, chance)); + ItemRandomEnchantmentType type = ItemRandomEnchantmentType(fields[1].GetUInt8()); + uint32 ench = fields[2].GetUInt32(); + float chance = fields[3].GetFloat(); + + switch (type) + { + case ItemRandomEnchantmentType::Property: + if (!sItemRandomPropertiesStore.LookupEntry(ench)) + { + TC_LOG_ERROR("sql.sql", "Property %u used in `item_enchantment_template` by entry %u doesn't have exist in ItemRandomProperties.db2", ench, entry); + continue; + } + break; + case ItemRandomEnchantmentType::Suffix: + if (!sItemRandomSuffixStore.LookupEntry(ench)) + { + TC_LOG_ERROR("sql.sql", "Suffix %u used in `item_enchantment_template` by entry %u doesn't have exist in ItemRandomSuffix.db2", ench, entry); + continue; + } + break; + case ItemRandomEnchantmentType::BonusList: + if (!sDB2Manager.GetItemBonusList(ench)) + { + TC_LOG_ERROR("sql.sql", "Bonus list %u used in `item_enchantment_template` by entry %u doesn't have exist in ItemBonus.db2", ench, entry); + continue; + } + break; + default: + TC_LOG_ERROR("sql.sql", "Invalid random enchantment type specified in `item_enchantment_template` table for `entry` %u `ench` %u", entry, ench); + break; + } + + if (chance < 0.000001f || chance > 100.0f) + { + TC_LOG_ERROR("sql.sql", "Random item enchantment for entry %u type %u ench %u has invalid chance %f", entry, uint32(type), ench, chance); + continue; + } + + switch (type) + { + case ItemRandomEnchantmentType::Property: + RandomItemEnch[ItemRandomEnchantmentType::Property][entry].emplace_back(type, ench, chance); + break; + case ItemRandomEnchantmentType::Suffix: + case ItemRandomEnchantmentType::BonusList: // random bonus lists use RandomSuffix field in Item-sparse.db2 + RandomItemEnch[ItemRandomEnchantmentType::Suffix][entry].emplace_back(type, ench, chance); + break; + default: + break; + } ++count; } while (result->NextRow()); @@ -76,45 +134,27 @@ void LoadRandomEnchantmentsTable() TC_LOG_ERROR("server.loading", ">> Loaded 0 Item Enchantment definitions. DB table `item_enchantment_template` is empty."); } -uint32 GetItemEnchantMod(int32 entry) +ItemRandomEnchantmentId GetItemEnchantMod(int32 entry, ItemRandomEnchantmentType type) { if (!entry) - return 0; + return{}; if (entry == -1) - return 0; + return{}; - EnchantmentStore::const_iterator tab = RandomItemEnch.find(entry); - if (tab == RandomItemEnch.end()) + auto tab = RandomItemEnch[type].find(entry); + if (tab == RandomItemEnch[type].end()) { TC_LOG_ERROR("sql.sql", "Item RandomProperty / RandomSuffix id #%u used in `item_template` but it does not have records in `item_enchantment_template` table.", entry); - return 0; + return{}; } - double dRoll = rand_chance(); - float fCount = 0; - - for (EnchStoreList::const_iterator ench_iter = tab->second.begin(); ench_iter != tab->second.end(); ++ench_iter) + auto selectedItr = Trinity::Containers::SelectRandomWeightedContainerElement(tab->second, [](EnchStoreItem const& enchant) { - fCount += ench_iter->chance; - - if (fCount > dRoll) - return ench_iter->ench; - } + return enchant.chance; + }); - //we could get here only if sum of all enchantment chances is lower than 100% - dRoll = (irand(0, (int)floor(fCount * 100) + 1)) / 100; - fCount = 0; - - for (EnchStoreList::const_iterator ench_iter = tab->second.begin(); ench_iter != tab->second.end(); ++ench_iter) - { - fCount += ench_iter->chance; - - if (fCount > dRoll) - return ench_iter->ench; - } - - return 0; + return{ selectedItr->type, selectedItr->ench }; } uint32 GenerateEnchSuffixFactor(uint32 item_id) diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.h b/src/server/game/Entities/Item/ItemEnchantmentMgr.h index ec84b13dec5..9ef98545505 100644 --- a/src/server/game/Entities/Item/ItemEnchantmentMgr.h +++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.h @@ -21,9 +21,25 @@ #include "Common.h" +enum class ItemRandomEnchantmentType : uint8 +{ + Property = 0, + Suffix = 1, + BonusList = 2 +}; + +struct ItemRandomEnchantmentId +{ + ItemRandomEnchantmentId() = default; + ItemRandomEnchantmentId(ItemRandomEnchantmentType type, uint32 id) : Type(type), Id(id) { } + + ItemRandomEnchantmentType Type = ItemRandomEnchantmentType::Property; + uint32 Id = 0; +}; + TC_GAME_API void LoadRandomEnchantmentsTable(); -TC_GAME_API uint32 GetItemEnchantMod(int32 entry); +TC_GAME_API ItemRandomEnchantmentId GetItemEnchantMod(int32 entry, ItemRandomEnchantmentType type); TC_GAME_API uint32 GenerateEnchSuffixFactor(uint32 item_id); TC_GAME_API uint32 GetRandomPropertyPoints(uint32 itemLevel, uint32 quality, uint32 inventoryType, uint32 subclass); -#endif +#endif diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 5b8302dc794..77e2870a24e 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -11421,7 +11421,7 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje } // 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, int32 randomPropertyId /*= 0*/, GuidSet const& allowedLooters /*= GuidSet()*/, std::vector<int32> const& bonusListIDs /*= std::vector<int32>()*/, bool addToCollection /*= true*/) +Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool update, ItemRandomEnchantmentId const& randomPropertyId /*= {}*/, GuidSet const& allowedLooters /*= GuidSet()*/, std::vector<int32> const& bonusListIDs /*= std::vector<int32>()*/, bool addToCollection /*= true*/) { uint32 count = 0; for (ItemPosCountVec::const_iterator itr = pos.begin(); itr != pos.end(); ++itr) @@ -11434,8 +11434,7 @@ Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool updat UpdateCriteria(CRITERIA_TYPE_RECEIVE_EPIC_ITEM, itemId, count); UpdateCriteria(CRITERIA_TYPE_OWN_ITEM, itemId, 1); - if (randomPropertyId) - item->SetItemRandomProperties(randomPropertyId); + item->SetItemRandomProperties(randomPropertyId); if (uint32 upgradeID = sDB2Manager.GetRulesetItemUpgrade(itemId)) item->SetModifier(ITEM_MODIFIER_UPGRADE_ID, upgradeID); @@ -11473,7 +11472,7 @@ Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool updat { ItemPosCountVec childDest; CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, childDest, childTemplate, count, false, nullptr, NULL_BAG, NULL_SLOT); - if (Item* childItem = StoreNewItem(childDest, childTemplate->GetId(), update, 0, {}, {}, addToCollection)) + if (Item* childItem = StoreNewItem(childDest, childTemplate->GetId(), update, {}, {}, {}, addToCollection)) { childItem->SetGuidValue(ITEM_FIELD_CREATOR, item->GetGUID()); childItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD); @@ -18002,18 +18001,20 @@ void Player::LoadCorpse(PreparedQueryResult result) void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult artifactsResult, uint32 timeDiff) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 - // SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, - // 13 14 15 16 17 18 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + // SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyType, randomPropertyId, durability, playedTime, text, + // 14 15 16 17 18 19 // upgradeId, battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, bonusListIDs, - // 19 20 21 22 23 + // 20 21 22 23 24 // itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4, - // 24 25 26 27 28 + // 25 26 27 28 29 // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4, - // 29 30 31 32 33 34 35 36 37 38 39 40 + // 30 31 32 33 34 35 36 37 38 39 40 41 // gemItemId1, gemBonuses1, gemContext1, gemScalingLevel1, gemItemId2, gemBonuses2, gemContext2, gemScalingLevel2, gemItemId3, gemBonuses3, gemContext3, gemScalingLevel3 - // 41 42 43 44 - // fixedScalingLevel, artifactKnowledgeLevel, bag, slot + // 42 43 + // fixedScalingLevel, artifactKnowledgeLevel + // 44 45 + // bag, slot // FROM character_inventory ci // JOIN item_instance ii ON ci.item = ii.guid // LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid @@ -18075,8 +18076,8 @@ void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult arti if (item->GetTemplate()->GetArtifactID() && artifactDataItr != artifactData.end()) item->LoadArtifactData(std::get<0>(artifactDataItr->second), std::get<1>(artifactDataItr->second), std::get<2>(artifactDataItr->second)); - ObjectGuid bagGuid = fields[43].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[43].GetUInt64()) : ObjectGuid::Empty; - uint8 slot = fields[44].GetUInt8(); + ObjectGuid bagGuid = fields[44].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[44].GetUInt64()) : ObjectGuid::Empty; + uint8 slot = fields[45].GetUInt8(); GetSession()->GetCollectionMgr()->CheckHeirloomUpgrades(item); GetSession()->GetCollectionMgr()->AddItemAppearance(item); @@ -18210,13 +18211,13 @@ void Player::_LoadVoidStorage(PreparedQueryResult result) uint32 itemEntry = fields[1].GetUInt32(); uint8 slot = fields[2].GetUInt8(); ObjectGuid creatorGuid = fields[3].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[3].GetUInt64()) : ObjectGuid::Empty; - uint32 randomProperty = fields[4].GetUInt32(); - uint32 suffixFactor = fields[5].GetUInt32(); - uint32 upgradeId = fields[6].GetUInt32(); - uint32 fixedScalingLevel = fields[7].GetUInt32(); - uint32 artifactKnowledgeLevel = fields[8].GetUInt32(); + ItemRandomEnchantmentId randomProperty(ItemRandomEnchantmentType(fields[4].GetUInt8()), fields[5].GetUInt32()); + uint32 suffixFactor = fields[6].GetUInt32(); + uint32 upgradeId = fields[7].GetUInt32(); + uint32 fixedScalingLevel = fields[8].GetUInt32(); + uint32 artifactKnowledgeLevel = fields[9].GetUInt32(); std::vector<uint32> bonusListIDs; - Tokenizer bonusListIdTokens(fields[9].GetString(), ' '); + Tokenizer bonusListIdTokens(fields[10].GetString(), ' '); for (char const* token : bonusListIdTokens) bonusListIDs.push_back(atoul(token)); @@ -18417,7 +18418,7 @@ void Player::_LoadMailedItems(Mail* mail) Item* item = NewItemOrBag(proto); - ObjectGuid ownerGuid = fields[43].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[43].GetUInt64()) : ObjectGuid::Empty; + ObjectGuid ownerGuid = fields[44].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[44].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); @@ -19955,22 +19956,22 @@ void Player::_SaveVoidStorage(SQLTransaction& trans) stmt->setUInt32(2, _voidStorageItems[i]->ItemEntry); stmt->setUInt8(3, i); stmt->setUInt64(4, _voidStorageItems[i]->CreatorGuid.GetCounter()); - stmt->setUInt32(5, _voidStorageItems[i]->ItemRandomPropertyId); - stmt->setUInt32(6, _voidStorageItems[i]->ItemSuffixFactor); - stmt->setUInt32(7, _voidStorageItems[i]->ItemUpgradeId); - stmt->setUInt32(8, _voidStorageItems[i]->FixedScalingLevel); - stmt->setUInt32(9, _voidStorageItems[i]->ArtifactKnowledgeLevel); + stmt->setUInt8(5, uint8(_voidStorageItems[i]->ItemRandomPropertyId.Type)); + stmt->setUInt32(6, _voidStorageItems[i]->ItemRandomPropertyId.Id); + stmt->setUInt32(7, _voidStorageItems[i]->ItemSuffixFactor); + stmt->setUInt32(8, _voidStorageItems[i]->ItemUpgradeId); + stmt->setUInt32(9, _voidStorageItems[i]->FixedScalingLevel); + stmt->setUInt32(10, _voidStorageItems[i]->ArtifactKnowledgeLevel); std::ostringstream bonusListIDs; for (int32 bonusListID : _voidStorageItems[i]->BonusListIDs) bonusListIDs << bonusListID << ' '; - stmt->setString(10, bonusListIDs.str()); + stmt->setString(11, bonusListIDs.str()); } trans->Append(stmt); } } - void Player::_SaveCUFProfiles(SQLTransaction& trans) { PreparedStatement* stmt; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index a9d12310683..ee23fb76cdc 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1132,8 +1132,8 @@ struct BGData struct VoidStorageItem { - VoidStorageItem() : ItemId(0), ItemEntry(0), ItemRandomPropertyId(0), ItemSuffixFactor(0), ItemUpgradeId(0), FixedScalingLevel(0), ArtifactKnowledgeLevel(0) { } - VoidStorageItem(uint64 id, uint32 entry, ObjectGuid const& creator, uint32 randomPropertyId, uint32 suffixFactor, + VoidStorageItem() : ItemId(0), ItemEntry(0), ItemRandomPropertyId(), ItemSuffixFactor(0), ItemUpgradeId(0), FixedScalingLevel(0), ArtifactKnowledgeLevel(0) { } + VoidStorageItem(uint64 id, uint32 entry, ObjectGuid const& creator, ItemRandomEnchantmentId randomPropertyId, uint32 suffixFactor, uint32 upgradeId, uint32 fixedScalingLevel, uint32 artifactKnowledgeLevel, std::vector<uint32> const& bonuses) : ItemId(id), ItemEntry(entry), CreatorGuid(creator), ItemRandomPropertyId(randomPropertyId), ItemSuffixFactor(suffixFactor), ItemUpgradeId(upgradeId), FixedScalingLevel(fixedScalingLevel), ArtifactKnowledgeLevel(artifactKnowledgeLevel) @@ -1147,7 +1147,7 @@ struct VoidStorageItem uint64 ItemId; uint32 ItemEntry; ObjectGuid CreatorGuid; - uint32 ItemRandomPropertyId; + ItemRandomEnchantmentId ItemRandomPropertyId; uint32 ItemSuffixFactor; uint32 ItemUpgradeId; uint32 FixedScalingLevel; @@ -1384,7 +1384,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> bool HasItemTotemCategory(uint32 TotemCategory) const; InventoryResult CanUseItem(ItemTemplate const* pItem) const; InventoryResult CanRollForItemInLFG(ItemTemplate const* item, WorldObject const* lootedObject) const; - Item* StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool update, int32 randomPropertyId = 0, GuidSet const& allowedLooters = GuidSet(), std::vector<int32> const& bonusListIDs = std::vector<int32>(), bool addToCollection = true); + Item* StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool update, ItemRandomEnchantmentId const& randomPropertyId = {}, GuidSet const& allowedLooters = GuidSet(), std::vector<int32> const& bonusListIDs = std::vector<int32>(), bool addToCollection = true); Item* StoreItem(ItemPosCountVec const& pos, Item* pItem, bool update); Item* EquipNewItem(uint16 pos, uint32 item, bool update); Item* EquipItem(uint16 pos, Item* pItem, bool update); diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 479bd6d2da9..d855776fa3a 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -853,7 +853,7 @@ void Group::SendLootStartRoll(uint32 countDown, uint32 mapid, const Roll &r) data << uint32(r.itemSlot); // itemslot data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for data << uint32(r.itemRandomSuffix); // randomSuffix - data << uint32(r.itemRandomPropId); // item random property ID + data << uint32(r.itemRandomPropId.Id); // item random property ID data << uint32(r.itemCount); // items in stack data << uint32(countDown); // the countdown time to choose "need" or "greed" data << uint8(r.rollVoteMask); // roll type mask @@ -881,7 +881,7 @@ void Group::SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, data << uint32(r.itemSlot); // itemslot data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for data << uint32(r.itemRandomSuffix); // randomSuffix - data << uint32(r.itemRandomPropId); // item random property ID + data << uint32(r.itemRandomPropId.Id); // item random property ID data << uint32(r.itemCount); // items in stack data << uint32(countDown); // the countdown time to choose "need" or "greed" uint8 voteMask = r.rollVoteMask; @@ -901,7 +901,7 @@ void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rol data << targetGuid; data << uint32(roll.itemid); // the itemEntryId for the item that shall be rolled for data << uint32(roll.itemRandomSuffix); // randomSuffix - data << uint32(roll.itemRandomPropId); // Item random property ID + data << uint32(roll.itemRandomPropId.Id); // Item random property ID data << uint32(rollNumber); // 0: "Need for: [item name]" > 127: "you passed on: [item name]" Roll number data << uint8(rollType); // 0: "Need for: [item name]" 0: "You have selected need for [item name] 1: need roll 2: greed roll data << uint8(0); // 1: "You automatically passed on: %s because you cannot loot that item." - Possibly used in need befor greed @@ -924,7 +924,7 @@ void Group::SendLootRollWon(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 data << uint32(roll.itemSlot); // slot data << uint32(roll.itemid); // the itemEntryId for the item that shall be rolled for data << uint32(roll.itemRandomSuffix); // randomSuffix - data << uint32(roll.itemRandomPropId); // Item random property + data << uint32(roll.itemRandomPropId.Id); // Item random property data << targetGuid; // guid of the player who won. data << uint32(rollNumber); // rollnumber realted to SMSG_LOOT_ROLL data << uint8(rollType); // rollType related to SMSG_LOOT_ROLL @@ -946,7 +946,7 @@ void Group::SendLootAllPassed(Roll const& roll) data << roll.itemGUID; // Guid of the item rolled data << uint32(roll.itemSlot); // Item loot slot data << uint32(roll.itemid); // The itemEntryId for the item that shall be rolled for - data << uint32(roll.itemRandomPropId); // Item random property ID + data << uint32(roll.itemRandomPropId.Id); // Item random property ID data << uint32(roll.itemRandomSuffix); // Item random suffix ID for (Roll::PlayerVote::const_iterator itr = roll.playerVote.begin(); itr != roll.playerVote.end(); ++itr) diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 093d0d3d215..bf29b8f8a50 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -162,7 +162,7 @@ class Roll : public LootValidatorRef ObjectGuid itemGUID; uint32 itemid; - int32 itemRandomPropId; + ItemRandomEnchantmentId itemRandomPropId; uint32 itemRandomSuffix; uint8 itemCount; typedef std::map<ObjectGuid, RollVote> PlayerVote; diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 60f6d6acc9f..4848f75b4bd 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -368,7 +368,7 @@ void Guild::BankTab::LoadFromDB(Field* fields) bool Guild::BankTab::LoadItemFromDB(Field* fields) { - uint8 slotId = fields[45].GetUInt8(); + uint8 slotId = fields[46].GetUInt8(); ObjectGuid::LowType itemGuid = fields[0].GetUInt64(); uint32 itemEntry = fields[1].GetUInt32(); if (slotId >= GUILD_BANK_MAX_SLOTS) @@ -2399,7 +2399,7 @@ void Guild::LoadBankTabFromDB(Field* fields) bool Guild::LoadBankItemFromDB(Field* fields) { - uint8 tabId = fields[44].GetUInt8(); + uint8 tabId = fields[45].GetUInt8(); if (tabId >= _GetPurchasedTabsSize()) { TC_LOG_ERROR("guild", "Invalid tab for item (GUID: %u, id: #%u) in guild bank, skipped.", diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp index 151429ebb9b..292ec374257 100644 --- a/src/server/game/Guilds/GuildMgr.cpp +++ b/src/server/game/Guilds/GuildMgr.cpp @@ -401,17 +401,19 @@ void GuildMgr::LoadGuilds() // Delete orphan guild bank items CharacterDatabase.DirectExecute("DELETE gbi FROM guild_bank_item gbi LEFT JOIN guild g ON gbi.guildId = g.guildId WHERE g.guildId IS NULL"); - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 - // SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, upgradeId, - // 14 15 16 17 18 - // battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, bonusListIDs, - // 19 20 21 22 23 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + // SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyType, randomPropertyId, durability, playedTime, text, + // 14 15 16 17 18 19 + // upgradeId, battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, bonusListIDs, + // 20 21 22 23 24 // itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4, - // 24 25 26 27 28 + // 25 26 27 28 29 // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4, - // 29 30 31 32 33 34 35 36 37 38 39 - // gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3, fixedScalingLevel, artifactKnowledgeLevel, - // 40 41 42 + // 30 31 32 33 34 35 36 37 38 39 40 41 + // gemItemId1, gemBonuses1, gemContext1, gemScalingLevel1, gemItemId2, gemBonuses2, gemContext2, gemScalingLevel2, gemItemId3, gemBonuses3, gemContext3, gemScalingLevel3 + // 42 43 + // fixedScalingLevel, artifactKnowledgeLevel + // 44 45 46 // 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)); @@ -425,7 +427,7 @@ void GuildMgr::LoadGuilds() do { Field* fields = result->Fetch(); - uint64 guildId = fields[43].GetUInt64(); + uint64 guildId = fields[44].GetUInt64(); if (Guild* guild = GetGuildById(guildId)) guild->LoadBankItemFromDB(fields); diff --git a/src/server/game/Handlers/VoidStorageHandler.cpp b/src/server/game/Handlers/VoidStorageHandler.cpp index ee4d43dff08..cf3ef7abcbc 100644 --- a/src/server/game/Handlers/VoidStorageHandler.cpp +++ b/src/server/game/Handlers/VoidStorageHandler.cpp @@ -155,7 +155,7 @@ void WorldSession::HandleVoidStorageTransfer(WorldPackets::VoidStorage::VoidStor } VoidStorageItem itemVS(sObjectMgr->GenerateVoidStorageItemId(), item->GetEntry(), item->GetGuidValue(ITEM_FIELD_CREATOR), - item->GetItemRandomPropertyId(), item->GetItemSuffixFactor(), item->GetModifier(ITEM_MODIFIER_UPGRADE_ID), + item->GetItemRandomEnchantmentId(), item->GetItemSuffixFactor(), item->GetModifier(ITEM_MODIFIER_UPGRADE_ID), item->GetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL), item->GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL), item->GetDynamicValues(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS)); diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index 4fea6967ef4..b7d3ba2123b 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -155,7 +155,7 @@ struct TC_GAME_API LootItem { uint32 itemid; uint32 randomSuffix; - int32 randomPropertyId; + ItemRandomEnchantmentId randomPropertyId; int32 upgradeId; std::vector<int32> BonusListIDs; ConditionContainer conditions; // additional loot condition @@ -175,7 +175,7 @@ struct TC_GAME_API LootItem explicit LootItem(LootStoreItem const& li); // Empty constructor for creating an empty LootItem to be filled in with DB data - LootItem() : itemid(0), randomSuffix(0), randomPropertyId(0), upgradeId(0), count(0), is_looted(false), is_blocked(false), + LootItem() : itemid(0), randomSuffix(0), randomPropertyId(), upgradeId(0), count(0), is_looted(false), is_blocked(false), freeforall(false), is_underthreshold(false), is_counted(false), needs_quest(false), follow_loot_rules(false), canSave(true){ }; diff --git a/src/server/game/Server/Packets/ItemPackets.cpp b/src/server/game/Server/Packets/ItemPackets.cpp index 1311a32a460..a689bf2f627 100644 --- a/src/server/game/Server/Packets/ItemPackets.cpp +++ b/src/server/game/Server/Packets/ItemPackets.cpp @@ -308,7 +308,9 @@ void WorldPackets::Item::ItemInstance::Initialize(::LootItem const& lootItem) { ItemID = lootItem.itemid; RandomPropertiesSeed = lootItem.randomSuffix; - RandomPropertiesID = lootItem.randomPropertyId; + if (lootItem.randomPropertyId.Type != ItemRandomEnchantmentType::BonusList) + RandomPropertiesID = lootItem.randomPropertyId.Id; + if (!lootItem.BonusListIDs.empty()) { ItemBonus = boost::in_place(); @@ -326,8 +328,10 @@ void WorldPackets::Item::ItemInstance::Initialize(::LootItem const& lootItem) void WorldPackets::Item::ItemInstance::Initialize(::VoidStorageItem const* voidItem) { ItemID = voidItem->ItemEntry; - RandomPropertiesID = voidItem->ItemRandomPropertyId; RandomPropertiesSeed = voidItem->ItemSuffixFactor; + if (voidItem->ItemRandomPropertyId.Type != ItemRandomEnchantmentType::BonusList) + RandomPropertiesID = voidItem->ItemRandomPropertyId.Id; + if (voidItem->ItemUpgradeId || voidItem->FixedScalingLevel || voidItem->ArtifactKnowledgeLevel) { Modifications = boost::in_place(); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 1f82000dc4d..6e6a7b6ca87 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1364,7 +1364,7 @@ public: InventoryResult msg = playerTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itr->second.GetId(), 1); if (msg == EQUIP_ERR_OK) { - Item* item = playerTarget->StoreNewItem(dest, itr->second.GetId(), true, 0, GuidSet(), bonusListIDs); + Item* item = playerTarget->StoreNewItem(dest, itr->second.GetId(), true, {}, GuidSet(), bonusListIDs); // remove binding (let GM give it to another player later) if (player == playerTarget) |