diff options
28 files changed, 556 insertions, 443 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 29f14fa7b39..dff9589e540 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -2213,6 +2213,10 @@ CREATE TABLE `item_instance` ( `durability` smallint(5) unsigned NOT NULL DEFAULT '0', `playedTime` int(10) unsigned NOT NULL DEFAULT '0', `text` text, + `transmogrification` int(10) unsigned NOT NULL DEFAULT '0', + `upgradeId` int(10) unsigned NOT NULL DEFAULT '0', + `enchantIllusion` int(10) unsigned NOT NULL DEFAULT '0', + `bonusListIDs` text, PRIMARY KEY (`guid`), KEY `idx_owner_guid` (`owner_guid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Item System'; diff --git a/sql/updates/characters/2014_12_23_00_characters.sql b/sql/updates/characters/2014_12_23_00_characters.sql new file mode 100644 index 00000000000..d72d71a3e7b --- /dev/null +++ b/sql/updates/characters/2014_12_23_00_characters.sql @@ -0,0 +1,9 @@ +ALTER TABLE `item_instance` + ADD `transmogrification` int(10) unsigned not null default '0' AFTER `text`, + ADD `upgradeId` int(10) unsigned not null default '0' AFTER `transmogrification`, + ADD `enchantIllusion` int(10) unsigned not null default '0' AFTER `upgradeId`, + ADD `bonusListIDs` text AFTER `enchantIllusion`; + +UPDATE `item_instance` SET `transmogrification`=SUBSTRING_INDEX(SUBSTRING_INDEX(`enchantments`, ' ', 27 + 1), ' ', -1); +UPDATE `item_instance` SET `enchantments`=SUBSTRING_INDEX(`enchantments`, ' ', 45); -- trim the field to 15 enchantments +UPDATE `item_instance` SET `enchantments`=CONCAT(SUBSTRING_INDEX(`enchantments`, ' ', 24), ' ', SUBSTRING_INDEX(`enchantments`, ' ', -15)); diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index bdbf1e5c29e..7ff032ca080 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -291,8 +291,8 @@ void AuctionHouseMgr::LoadAuctionItems() { Field* fields = result->Fetch(); - ObjectGuid::LowType item_guid = fields[11].GetUInt64(); - uint32 itemEntry = fields[12].GetUInt32(); + ObjectGuid::LowType item_guid = fields[15].GetUInt64(); + uint32 itemEntry = fields[16].GetUInt32(); ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry); if (!proto) @@ -563,7 +563,7 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player if (quality != 0xffffffff && proto->GetQuality() != quality) continue; - if (levelmin != 0 && (proto->GetRequiredLevel() < levelmin || (levelmax != 0 && proto->GetRequiredLevel() > levelmax))) + if (levelmin != 0 && (proto->GetBaseRequiredLevel() < levelmin || (levelmax != 0 && proto->GetBaseRequiredLevel() > levelmax))) continue; if (usable != 0 && player->CanUseItem(item) != EQUIP_ERR_OK) diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp index 70d88fd397c..36d78ba389c 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp @@ -272,10 +272,10 @@ bool AuctionBotSeller::Initialize() if (prototype->GetBaseItemLevel() > value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_REQ_LEVEL)) - if (prototype->GetRequiredLevel() < value) + if (prototype->GetBaseRequiredLevel() < value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_REQ_LEVEL)) - if (prototype->GetRequiredLevel() > value) + if (prototype->GetBaseRequiredLevel() > value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_SKILL_RANK)) if (prototype->GetRequiredSkillRank() < value) @@ -290,10 +290,10 @@ bool AuctionBotSeller::Initialize() case ITEM_CLASS_PROJECTILE: { if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_REQ_LEVEL)) - if (prototype->GetRequiredLevel() < value) + if (prototype->GetBaseRequiredLevel() < value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_REQ_LEVEL)) - if (prototype->GetRequiredLevel() > value) + if (prototype->GetBaseRequiredLevel() > value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_SKILL_RANK)) if (prototype->GetRequiredSkillRank() < value) @@ -307,10 +307,10 @@ bool AuctionBotSeller::Initialize() if (prototype->GetSubClass() == ITEM_SUBCLASS_JUNK_MOUNT) { if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_REQ_LEVEL)) - if (prototype->GetRequiredLevel() < value) + if (prototype->GetBaseRequiredLevel() < value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MAX_REQ_LEVEL)) - if (prototype->GetRequiredLevel() > value) + if (prototype->GetBaseRequiredLevel() > value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_SKILL_RANK)) if (prototype->GetRequiredSkillRank() < value) @@ -334,16 +334,16 @@ bool AuctionBotSeller::Initialize() case ITEM_CLASS_GLYPH: { if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MIN_REQ_LEVEL)) - if (prototype->GetRequiredLevel() < value) + if (prototype->GetBaseRequiredLevel() < value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MAX_REQ_LEVEL)) - if (prototype->GetRequiredLevel() > value) + if (prototype->GetBaseRequiredLevel() > value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MIN_ITEM_LEVEL)) - if (prototype->GetRequiredLevel() < value) + if (prototype->GetBaseRequiredLevel() < value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MAX_ITEM_LEVEL)) - if (prototype->GetRequiredLevel() > value) + if (prototype->GetBaseRequiredLevel() > value) continue; break; } diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index e6b3e8947c0..39e5d443871 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -21,14 +21,20 @@ #include "Common.h" #include "Log.h" #include "World.h" +#include <functional> +std::map<uint32 /*curveID*/, std::map<uint32/*index*/, CurvePointEntry const*, std::greater<uint32>>> HeirloomCurvePoints; +DB2Storage<CurvePointEntry> sCurvePointStore(CurvePointEntryfmt); DB2Storage<HolidaysEntry> sHolidaysStore(HolidaysEntryfmt); DB2Storage<ItemEntry> sItemStore(Itemfmt); DB2Storage<ItemAppearanceEntry> sItemAppearanceStore(ItemAppearanceEntryfmt); -ItemDisplayIDMap sItemDisplayIDMap; +std::unordered_map<uint32 /*itemId | appearanceMod << 24*/, uint32> ItemDisplayMap; +DB2Storage<ItemBonusEntry> sItemBonusStore(ItemBonusEntryfmt); +std::unordered_map<uint32 /*bonusListId*/, std::vector<ItemBonusEntry const*>> ItemBonusLists; DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore(ItemCurrencyCostfmt); DB2Storage<ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt); DB2Storage<ItemEffectEntry> sItemEffectStore(ItemEffectEntryfmt); +DB2Storage<ItemModifiedAppearanceEntry> sItemModifiedAppearanceStore(ItemModifiedAppearanceEntryfmt); DB2Storage<ItemSparseEntry> sItemSparseStore(ItemSparsefmt); DB2Storage<KeyChainEntry> sKeyChainStore(KeyChainfmt); DB2Storage<OverrideSpellDataEntry> sOverrideSpellDataStore(OverrideSpellDataEntryfmt); @@ -122,13 +128,16 @@ void LoadDB2Stores(std::string const& dataPath) DB2StoreProblemList bad_db2_files; uint32 availableDb2Locales = 0xFF; + LoadDB2(availableDb2Locales, bad_db2_files, sCurvePointStore, db2Path, "CurvePoint.db2"); LoadDB2(availableDb2Locales, bad_db2_files, sHolidaysStore, db2Path, "Holidays.db2"); LoadDB2(availableDb2Locales, bad_db2_files, sItemStore, db2Path, "Item.db2"); LoadDB2(availableDb2Locales, bad_db2_files, sItemAppearanceStore, db2Path, "ItemAppearance.db2"); + LoadDB2(availableDb2Locales, bad_db2_files, sItemBonusStore, db2Path, "ItemBonus.db2"); LoadDB2(availableDb2Locales, bad_db2_files, sItemCurrencyCostStore, db2Path, "ItemCurrencyCost.db2"); - LoadDB2(availableDb2Locales, bad_db2_files, sItemSparseStore, db2Path, "Item-sparse.db2"); LoadDB2(availableDb2Locales, bad_db2_files, sItemExtendedCostStore, db2Path, "ItemExtendedCost.db2"); LoadDB2(availableDb2Locales, bad_db2_files, sItemEffectStore, db2Path, "ItemEffect.db2"); + LoadDB2(availableDb2Locales, bad_db2_files, sItemModifiedAppearanceStore, db2Path, "ItemModifiedAppearance.db2"); + LoadDB2(availableDb2Locales, bad_db2_files, sItemSparseStore, db2Path, "Item-sparse.db2"); LoadDB2(availableDb2Locales, bad_db2_files, sKeyChainStore, db2Path, "KeyChain.db2"); LoadDB2(availableDb2Locales, bad_db2_files, sOverrideSpellDataStore, db2Path, "OverrideSpellData.db2"); LoadDB2(availableDb2Locales, bad_db2_files, sPhaseGroupStore, db2Path, "PhaseXPhaseGroup.db2"); @@ -144,6 +153,27 @@ void LoadDB2Stores(std::string const& dataPath) LoadDB2(availableDb2Locales, bad_db2_files, sTaxiPathStore, db2Path, "TaxiPath.db2"); LoadDB2(availableDb2Locales, bad_db2_files, sTaxiPathNodeStore, db2Path, "TaxiPathNode.db2"); + for (uint32 i = 0; i < sItemBonusStore.GetNumRows(); ++i) + if (ItemBonusEntry const* bonus = sItemBonusStore.LookupEntry(i)) + ItemBonusLists[bonus->BonusListID].push_back(bonus); + + for (uint32 i = 0; i < sItemModifiedAppearanceStore.GetNumRows(); ++i) + if (ItemModifiedAppearanceEntry const* appearanceMod = sItemModifiedAppearanceStore.LookupEntry(i)) + if (ItemAppearanceEntry const* appearance = sItemAppearanceStore.LookupEntry(appearanceMod->AppearanceID)) + ItemDisplayMap[appearanceMod->ItemID | (appearanceMod->AppearanceModID << 24)] = appearance->DisplayID; + + { + std::set<uint32> scalingCurves; + for (uint32 i = 0; i < sScalingStatDistributionStore.GetNumRows(); ++i) + if (ScalingStatDistributionEntry const* ssd = sScalingStatDistributionStore.LookupEntry(i)) + scalingCurves.insert(ssd->ItemLevelCurveID); + + for (uint32 i = 0; i < sCurvePointStore.GetNumRows(); ++i) + if (CurvePointEntry const* curvePoint = sCurvePointStore.LookupEntry(i)) + if (scalingCurves.count(curvePoint->CurveID)) + HeirloomCurvePoints[curvePoint->CurveID][curvePoint->Index] = curvePoint; + } + for (uint32 i = 0; i < sSpellPowerStore.GetNumRows(); ++i) if (SpellPowerEntry const* power = sSpellPowerStore.LookupEntry(i)) sSpellPowerBySpellIDStore[power->SpellID] = power; @@ -276,6 +306,51 @@ DB2StorageBase const* GetDB2Storage(uint32 type) return NULL; } +uint32 GetHeirloomItemLevel(uint32 curveId, uint32 level) +{ + // Assuming linear item level scaling for heirlooms + auto itr = HeirloomCurvePoints.find(curveId); + if (itr == HeirloomCurvePoints.end()) + return 0; + + auto it2 = itr->second.begin(); // Highest scaling point + if (level >= it2->second->X) + return it2->second->Y; + + auto previousItr = it2++; + for (; it2 != itr->second.end(); ++it2, ++previousItr) + if (level >= it2->second->X) + return uint32((previousItr->second->Y - it2->second->Y) / (previousItr->second->X - it2->second->X) * (float(level) - it2->second->X) + it2->second->Y); + + return uint32(previousItr->second->Y); // Lowest scaling point +} + +uint32 GetItemDisplayId(uint32 itemId, uint32 appearanceModId) +{ + auto itr = ItemDisplayMap.find(itemId | (appearanceModId << 24)); + if (itr != ItemDisplayMap.end()) + return itr->second; + + // Fall back to unmodified appearance + if (appearanceModId) + { + itr = ItemDisplayMap.find(itemId); + if (itr != ItemDisplayMap.end()) + return itr->second; + } + + return 0; +} + +std::vector<ItemBonusEntry const*> GetItemBonuses(uint32 bonusListId) +{ + auto itr = ItemBonusLists.find(bonusListId); + if (itr != ItemBonusLists.end()) + return itr->second; + + return std::vector<ItemBonusEntry const*>(); +} + std::set<uint32> const& GetPhasesForGroup(uint32 group) { return sPhasesByGroup[group]; diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 1d3869e7c74..20ff43a9bd4 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -25,7 +25,6 @@ extern DB2Storage<HolidaysEntry> sHolidaysStore; extern DB2Storage<ItemEntry> sItemStore; -extern DB2Storage<ItemAppearanceEntry> sItemAppearanceStore; extern DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore; extern DB2Storage<ItemExtendedCostEntry> sItemExtendedCostStore; extern DB2Storage<ItemEffectEntry> sItemEffectStore; @@ -57,6 +56,9 @@ void LoadDB2Stores(std::string const& dataPath); DB2StorageBase const* GetDB2Storage(uint32 type); +uint32 GetHeirloomItemLevel(uint32 curveId, uint32 level); +uint32 GetItemDisplayId(uint32 itemId, uint32 appearanceModId); +std::vector<ItemBonusEntry const*> GetItemBonuses(uint32 bonusListId); std::set<uint32> const& GetPhasesForGroup(uint32 group); #endif diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 351b9eff8ed..5942f8a425a 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -31,6 +31,15 @@ #define MAX_ITEM_PROTO_SOCKETS 3 #define MAX_ITEM_PROTO_STATS 10 +struct CurvePointEntry +{ + uint32 ID; // 0 + uint32 CurveID; // 1 + uint32 Index; // 2 + float X; // 3 + float Y; // 4 +}; + struct HolidaysEntry { uint32 ID; // 0 @@ -67,6 +76,15 @@ struct ItemAppearanceEntry uint32 IconFileDataID; // 2 }; +struct ItemBonusEntry +{ + uint32 ID; // 0 + uint32 BonusListID; // 1 + uint32 Type; // 2 + int32 Value[2]; // 3-4 + uint32 Index; // 5 +}; + struct ItemCurrencyCostEntry { //uint32 ID; // 0 @@ -107,6 +125,16 @@ struct ItemExtendedCostEntry uint32 RequiredAchievement; }; +struct ItemModifiedAppearanceEntry +{ + uint32 ID; // 0 + uint32 ItemID; // 1 + uint32 AppearanceModID; // 2 + uint32 AppearanceID; // 3 + uint32 IconFileDataID; // 4 + uint32 Index; // 5 +}; + struct ItemSparseEntry { uint32 ID; // 0 @@ -342,8 +370,6 @@ struct TaxiPathNodeEntry #pragma pack(pop) -typedef std::map<uint32, uint32> ItemDisplayIDMap; - typedef std::map<uint32, SpellPowerEntry const*> SpellPowerBySpellIDMap; struct TaxiPathBySourceAndDestination diff --git a/src/server/game/DataStores/DB2fmt.h b/src/server/game/DataStores/DB2fmt.h index b6175e1a5b0..087c1dfd588 100644 --- a/src/server/game/DataStores/DB2fmt.h +++ b/src/server/game/DataStores/DB2fmt.h @@ -18,14 +18,17 @@ #ifndef TRINITY_DB2SFRM_H #define TRINITY_DB2SFRM_H -char const HolidaysEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix"; -char const Itemfmt[]="niiiiiiii"; -char const ItemAppearanceEntryfmt[]="nii"; -char const ItemCurrencyCostfmt[]="xn"; -char const ItemSparsefmt[]="niiiiffiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffffffffffiiifisssssiiiiiiiiiiiiiiiiiiifiiifiii"; -char const ItemExtendedCostEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii"; -char const ItemEffectEntryfmt[]="niiiiiiii"; -char const KeyChainfmt[]="nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; +char const CurvePointEntryfmt[] = "niiff"; +char const HolidaysEntryfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix"; +char const Itemfmt[] = "niiiiiiii"; +char const ItemAppearanceEntryfmt[] = "nii"; +char const ItemBonusEntryfmt[] = "niiiii"; +char const ItemCurrencyCostfmt[] = "xn"; +char const ItemExtendedCostEntryfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiii"; +char const ItemEffectEntryfmt[] = "niiiiiiii"; +char const ItemModifiedAppearanceEntryfmt[] = "niiiii"; +char const ItemSparsefmt[] = "niiiiffiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffffffffffiiifisssssiiiiiiiiiiiiiiiiiiifiiifiii"; +char const KeyChainfmt[] = "nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; char const OverrideSpellDataEntryfmt[] = "niiiiiiiiiixx"; char const PhaseGroupEntryfmt[] = "nii"; char const SpellAuraRestrictionsEntryfmt[] = "diiiiiiii"; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index b1e4cda483e..9aefb440d98 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -444,6 +444,18 @@ enum ItemExtendedCostFlags ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_5 = 0x20, }; +enum ItemBonusType +{ + ITEM_BONUS_ITEM_LEVEL = 1, + ITEM_BONUS_STAT = 2, + ITEM_BONUS_QUALITY = 3, + ITEM_BONUS_DESCRIPTION = 4, + ITEM_BONUS_SUFFIX = 5, + ITEM_BONUS_SOCKET = 6, + ITEM_BONUS_APPEARANCE = 7, + ITEM_BONUS_REQUIRED_LEVEL = 8, +}; + enum ItemLimitCategoryMode { ITEM_LIMIT_CATEGORY_MODE_HAVE = 0, // limit applied to amount items in inventory/bank diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 0b1b1aa068e..b801fd7b3f3 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -113,6 +113,7 @@ GameTable <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore(GtChanceT GameTable <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore(GtChanceToMeleeCritfmt); GameTable <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore(GtChanceToSpellCritBasefmt); GameTable <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore(GtChanceToSpellCritfmt); +GameTable <GtItemSocketCostPerLevelEntry> sGtItemSocketCostPerLevelStore(GtItemSocketCostPerLevelfmt); GameTable <GtNPCManaCostScalerEntry> sGtNPCManaCostScalerStore(GtNPCManaCostScalerfmt); GameTable <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore(GtOCTClassCombatRatingScalarfmt); GameTable <GtOCTRegenHPEntry> sGtOCTRegenHPStore(GtOCTRegenHPfmt); @@ -177,7 +178,6 @@ DBCStorage <QuestXPEntry> sQuestXPStore(QuestXPfmt); DBCStorage <QuestFactionRewEntry> sQuestFactionRewardStore(QuestFactionRewardfmt); DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore(RandomPropertiesPointsfmt); DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore(ScalingStatDistributionfmt); -DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore(ScalingStatValuesfmt); DBCStorage <SkillLineEntry> sSkillLineStore(SkillLinefmt); DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore(SkillLineAbilityfmt); @@ -527,9 +527,7 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sRandomPropertiesPointsStore, dbcPath, "RandPropPoints.dbc");//19116 - // TODO: 6.x item stat scaling requires major changes - //LoadDBC(availableDbcLocales, bad_dbc_files, sScalingStatDistributionStore, dbcPath, "ScalingStatDistribution.dbc"); - //LoadDBC(availableDbcLocales, bad_dbc_files, sScalingStatValuesStore, dbcPath, "ScalingStatValues.dbc");//19116 + LoadDBC(availableDbcLocales, bad_dbc_files, sScalingStatDistributionStore, dbcPath, "ScalingStatDistribution.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sSkillLineStore, dbcPath, "SkillLine.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sSkillLineAbilityStore, dbcPath, "SkillLineAbility.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sSkillRaceClassInfoStore, dbcPath, "SkillRaceClassInfo.dbc");//19116 @@ -723,19 +721,20 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sWorldMapOverlayStore, dbcPath, "WorldMapOverlay.dbc");//15595 LoadDBC(availableDbcLocales, bad_dbc_files, sWorldSafeLocsStore, dbcPath, "WorldSafeLocs.dbc"); // 19116 - LoadGameTable(bad_dbc_files, "BarberShopCostBase", sGtBarberShopCostBaseStore, dbcPath, "gtBarberShopCostBase.dbc");//15595 - LoadGameTable(bad_dbc_files, "CombatRatings", sGtCombatRatingsStore, dbcPath, "gtCombatRatings.dbc");//15595 - LoadGameTable(bad_dbc_files, "ChanceToMeleeCritBase", sGtChanceToMeleeCritBaseStore, dbcPath, "gtChanceToMeleeCritBase.dbc");//15595 - LoadGameTable(bad_dbc_files, "ChanceToMeleeCrit", sGtChanceToMeleeCritStore, dbcPath, "gtChanceToMeleeCrit.dbc");//15595 - LoadGameTable(bad_dbc_files, "ChanceToSpellCritBase", sGtChanceToSpellCritBaseStore, dbcPath, "gtChanceToSpellCritBase.dbc");//15595 - LoadGameTable(bad_dbc_files, "ChanceToSpellCrit", sGtChanceToSpellCritStore, dbcPath, "gtChanceToSpellCrit.dbc");//15595 - LoadGameTable(bad_dbc_files, "NPCManaCostScaler", sGtNPCManaCostScalerStore, dbcPath, "gtNPCManaCostScaler.dbc"); - LoadGameTable(bad_dbc_files, "OCTClassCombatRatingScalar", sGtOCTClassCombatRatingScalarStore, dbcPath, "gtOCTClassCombatRatingScalar.dbc");//15595 - LoadGameTable(bad_dbc_files, "OCTHPPerStamina", sGtOCTHpPerStaminaStore, dbcPath, "gtOCTHpPerStamina.dbc");//15595 - LoadGameTable(bad_dbc_files, "RegenMPPerSpt", sGtRegenMPPerSptStore, dbcPath, "gtRegenMPPerSpt.dbc");//15595 - LoadGameTable(bad_dbc_files, "SpellScaling", sGtSpellScalingStore, dbcPath, "gtSpellScaling.dbc");//15595 - LoadGameTable(bad_dbc_files, "OCTBaseHPByClass", sGtOCTBaseHPByClassStore, dbcPath, "gtOCTBaseHPByClass.dbc");//15595 - LoadGameTable(bad_dbc_files, "OCTBaseMPByClass", sGtOCTBaseMPByClassStore, dbcPath, "gtOCTBaseMPByClass.dbc");//15595 + LoadGameTable(bad_dbc_files, "BarberShopCostBase", sGtBarberShopCostBaseStore, dbcPath, "gtBarberShopCostBase.dbc");//19342 + LoadGameTable(bad_dbc_files, "CombatRatings", sGtCombatRatingsStore, dbcPath, "gtCombatRatings.dbc");//19342 + LoadGameTable(bad_dbc_files, "ChanceToMeleeCritBase", sGtChanceToMeleeCritBaseStore, dbcPath, "gtChanceToMeleeCritBase.dbc");//19342 + LoadGameTable(bad_dbc_files, "ChanceToMeleeCrit", sGtChanceToMeleeCritStore, dbcPath, "gtChanceToMeleeCrit.dbc");//19342 + LoadGameTable(bad_dbc_files, "ChanceToSpellCritBase", sGtChanceToSpellCritBaseStore, dbcPath, "gtChanceToSpellCritBase.dbc");//19342 + LoadGameTable(bad_dbc_files, "ChanceToSpellCrit", sGtChanceToSpellCritStore, dbcPath, "gtChanceToSpellCrit.dbc");//19342 + LoadGameTable(bad_dbc_files, "ItemSocketCostPerLevel", sGtItemSocketCostPerLevelStore, dbcPath, "gtItemSocketCostPerLevel.dbc");//19342 + LoadGameTable(bad_dbc_files, "NPCManaCostScaler", sGtNPCManaCostScalerStore, dbcPath, "gtNPCManaCostScaler.dbc");//19342 + LoadGameTable(bad_dbc_files, "OCTClassCombatRatingScalar", sGtOCTClassCombatRatingScalarStore, dbcPath, "gtOCTClassCombatRatingScalar.dbc");//19342 + LoadGameTable(bad_dbc_files, "OCTHPPerStamina", sGtOCTHpPerStaminaStore, dbcPath, "gtOCTHpPerStamina.dbc");//19342 + LoadGameTable(bad_dbc_files, "RegenMPPerSpt", sGtRegenMPPerSptStore, dbcPath, "gtRegenMPPerSpt.dbc");//19342 + LoadGameTable(bad_dbc_files, "SpellScaling", sGtSpellScalingStore, dbcPath, "gtSpellScaling.dbc");//19342 + LoadGameTable(bad_dbc_files, "OCTBaseHPByClass", sGtOCTBaseHPByClassStore, dbcPath, "gtOCTBaseHPByClass.dbc");//19342 + LoadGameTable(bad_dbc_files, "OCTBaseMPByClass", sGtOCTBaseMPByClassStore, dbcPath, "gtOCTBaseMPByClass.dbc");//19342 // error checks if (bad_dbc_files.size() >= DBCFileCount) @@ -1051,159 +1050,6 @@ uint32 GetPowerIndexByClass(uint32 powerType, uint32 classId) return PowersByClass[classId][powerType]; } -uint32 ScalingStatValuesEntry::GetStatMultiplier(uint32 inventoryType) const -{ - if (inventoryType < MAX_INVTYPE) - { - switch (inventoryType) - { - case INVTYPE_NON_EQUIP: - case INVTYPE_BODY: - case INVTYPE_BAG: - case INVTYPE_TABARD: - case INVTYPE_AMMO: - case INVTYPE_QUIVER: - return 0; - case INVTYPE_HEAD: - case INVTYPE_CHEST: - case INVTYPE_LEGS: - case INVTYPE_2HWEAPON: - case INVTYPE_ROBE: - return StatMultiplier[0]; - case INVTYPE_SHOULDERS: - case INVTYPE_WAIST: - case INVTYPE_FEET: - case INVTYPE_HANDS: - case INVTYPE_TRINKET: - return StatMultiplier[1]; - case INVTYPE_NECK: - case INVTYPE_WRISTS: - case INVTYPE_FINGER: - case INVTYPE_SHIELD: - case INVTYPE_CLOAK: - case INVTYPE_HOLDABLE: - return StatMultiplier[2]; - case INVTYPE_RANGED: - case INVTYPE_THROWN: - case INVTYPE_RANGEDRIGHT: - case INVTYPE_RELIC: - return StatMultiplier[3]; - case INVTYPE_WEAPON: - case INVTYPE_WEAPONMAINHAND: - case INVTYPE_WEAPONOFFHAND: - return StatMultiplier[4]; - default: - break; - } - } - return 0; -} - -uint32 ScalingStatValuesEntry::GetArmor(uint32 inventoryType, uint32 armorType) const -{ - if (inventoryType <= INVTYPE_ROBE && armorType < 4) - { - switch (inventoryType) - { - case INVTYPE_NON_EQUIP: - case INVTYPE_NECK: - case INVTYPE_BODY: - case INVTYPE_FINGER: - case INVTYPE_TRINKET: - case INVTYPE_WEAPON: - case INVTYPE_RANGED: - case INVTYPE_2HWEAPON: - case INVTYPE_BAG: - case INVTYPE_TABARD: - break; - case INVTYPE_SHOULDERS: - return Armor[0][armorType]; - case INVTYPE_CHEST: - case INVTYPE_ROBE: - return Armor[1][armorType]; - case INVTYPE_HEAD: - return Armor[2][armorType]; - case INVTYPE_LEGS: - return Armor[3][armorType]; - case INVTYPE_FEET: - return Armor[4][armorType]; - case INVTYPE_WAIST: - return Armor[5][armorType]; - case INVTYPE_HANDS: - return Armor[6][armorType]; - case INVTYPE_WRISTS: - return Armor[7][armorType]; - case INVTYPE_CLOAK: - return ArmorBack; - case INVTYPE_SHIELD: - return ArmorShield; - default: - break; - } - } - return 0; -} - -uint32 ScalingStatValuesEntry::GetDPSAndDamageMultiplier(uint32 subClass, bool isCasterWeapon, float* damageMultiplier) const -{ - if (!isCasterWeapon) - { - switch (subClass) - { - case ITEM_SUBCLASS_WEAPON_AXE: - case ITEM_SUBCLASS_WEAPON_MACE: - case ITEM_SUBCLASS_WEAPON_SWORD: - case ITEM_SUBCLASS_WEAPON_DAGGER: - case ITEM_SUBCLASS_WEAPON_THROWN: - *damageMultiplier = 0.3f; - return DPSMod[0]; - case ITEM_SUBCLASS_WEAPON_AXE2: - case ITEM_SUBCLASS_WEAPON_MACE2: - case ITEM_SUBCLASS_WEAPON_POLEARM: - case ITEM_SUBCLASS_WEAPON_SWORD2: - case ITEM_SUBCLASS_WEAPON_STAFF: - case ITEM_SUBCLASS_WEAPON_FISHING_POLE: - *damageMultiplier = 0.2f; - return DPSMod[1]; - case ITEM_SUBCLASS_WEAPON_BOW: - case ITEM_SUBCLASS_WEAPON_GUN: - case ITEM_SUBCLASS_WEAPON_CROSSBOW: - *damageMultiplier = 0.3f; - return DPSMod[4]; - case ITEM_SUBCLASS_WEAPON_Obsolete: - case ITEM_SUBCLASS_WEAPON_EXOTIC: - case ITEM_SUBCLASS_WEAPON_EXOTIC2: - case ITEM_SUBCLASS_WEAPON_FIST_WEAPON: - case ITEM_SUBCLASS_WEAPON_MISCELLANEOUS: - case ITEM_SUBCLASS_WEAPON_SPEAR: - case ITEM_SUBCLASS_WEAPON_WAND: - break; - } - } - else - { - if (subClass <= ITEM_SUBCLASS_WEAPON_WAND) - { - uint32 mask = 1 << subClass; - // two-handed weapons - if (mask & 0x562) - { - *damageMultiplier = 0.2f; - return DPSMod[3]; - } - - if (mask & (1 << ITEM_SUBCLASS_WEAPON_WAND)) - { - *damageMultiplier = 0.3f; - return DPSMod[5]; - } - } - *damageMultiplier = 0.3f; - return DPSMod[2]; - } - return 0; -} - /// Returns LFGDungeonEntry for a specific map and difficulty. Will return first found entry if multiple dungeons use the same map (such as Scarlet Monastery) LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty) { diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 249f2495df0..0c25e359483 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -176,6 +176,7 @@ extern GameTable <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore; extern GameTable <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore; extern GameTable <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore; extern GameTable <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore; +extern GameTable <GtItemSocketCostPerLevelEntry> sGtItemSocketCostPerLevelStore; extern GameTable <GtNPCManaCostScalerEntry> sGtNPCManaCostScalerStore; extern GameTable <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore; extern GameTable <gtOCTHpPerStaminaEntry> sGtOCTHpPerStaminaStore; @@ -229,7 +230,6 @@ extern DBCStorage <QuestXPEntry> sQuestXPStore; extern DBCStorage <QuestFactionRewEntry> sQuestFactionRewardStore; extern DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore; extern DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore; -extern DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore; extern DBCStorage <SkillLineEntry> sSkillLineStore; extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore; extern DBCStorage <SkillTiersEntry> sSkillTiersStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index f67dfaa3b00..a03f6370c62 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1165,6 +1165,11 @@ struct GtChanceToSpellCritBaseEntry float base; }; +struct GtItemSocketCostPerLevelEntry +{ + float ratio; +}; + struct GtNPCManaCostScalerEntry { float ratio; @@ -1650,26 +1655,9 @@ struct RandomPropertiesPointsEntry struct ScalingStatDistributionEntry { uint32 ID; // 0 - int32 StatID[10]; // 1-10 - uint32 Modifier[10]; // 11-20 - //uint32 MinLevel; // 21 - uint32 MaxLevel; // 22 m_maxlevel -}; - -struct ScalingStatValuesEntry -{ - uint32 ID; // 0 - uint32 CharLevel; // 1 - uint32 DPSMod[6]; // 2-7 DPS mod for level - uint32 SpellPower; // 8 spell power for level - uint32 StatMultiplier[5]; // 9-13 Multiplier for ScalingStatDistribution - uint32 Armor[8][4]; // 14-46 Armor for level - uint32 ArmorBack; // 47 - uint32 ArmorShield; // 48 - - uint32 GetStatMultiplier(uint32 inventoryType) const; - uint32 GetArmor(uint32 inventoryType, uint32 armorType) const; - uint32 GetDPSAndDamageMultiplier(uint32 subClass, bool isCasterWeapon, float* damageMultiplier) const; + uint32 MinLevel; // 1 + uint32 MaxLevel; // 2 m_maxlevel + uint32 ItemLevelCurveID; // 3 }; //struct SkillLineCategoryEntry{ diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index ce82494d408..852af09fdb2 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -70,6 +70,7 @@ char const GtChanceToMeleeCritBasefmt[] = "xf"; char const GtChanceToMeleeCritfmt[] = "xf"; char const GtChanceToSpellCritBasefmt[] = "xf"; char const GtChanceToSpellCritfmt[] = "xf"; +char const GtItemSocketCostPerLevelfmt[] = "xf"; char const GtNPCManaCostScalerfmt[] = "xf"; char const GtOCTClassCombatRatingScalarfmt[] = "df"; char const GtOCTRegenHPfmt[] = "f"; @@ -117,8 +118,7 @@ char const QuestXPfmt[] = "niiiiiiiiii"; char const PowerDisplayfmt[] = "nixXXX"; char const PvPDifficultyfmt[] = "diiii"; char const RandomPropertiesPointsfmt[] = "niiiiiiiiiiiiiii"; -char const ScalingStatDistributionfmt[] = "niiiiiiiiiiiiiiiiiiiixi"; -char const ScalingStatValuesfmt[] = "iniiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"; +char const ScalingStatDistributionfmt[] = "niii"; char const SkillLinefmt[] = "nisxixixx"; char const SkillLineAbilityfmt[] = "niiiiiiiiiiii"; char const SkillRaceClassInfofmt[] = "diiiixxi"; diff --git a/src/server/game/Entities/Item/Container/Bag.cpp b/src/server/game/Entities/Item/Container/Bag.cpp index 6642bd05e34..8956c8372be 100644 --- a/src/server/game/Entities/Item/Container/Bag.cpp +++ b/src/server/game/Entities/Item/Container/Bag.cpp @@ -79,6 +79,8 @@ bool Bag::Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owner Object::_Create(ObjectGuid::Create<HighGuid::Item>(guidlow)); + _bonusData.Initialize(itemProto); + SetEntry(itemid); SetObjectScale(1.0f); diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 01e7285d741..2fb5774be29 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -261,6 +261,8 @@ Item::Item() m_paidMoney = 0; m_paidExtendedCost = 0; + + memset(_modifiers, 0, sizeof(_modifiers)); } bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owner) @@ -280,6 +282,7 @@ bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owne if (!itemProto) return false; + _bonusData.Initialize(itemProto); SetUInt32Value(ITEM_FIELD_STACK_COUNT, 1); SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability); SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability); @@ -360,6 +363,15 @@ void Item::SaveToDB(SQLTransaction& trans) stmt->setUInt16(++index, GetUInt32Value(ITEM_FIELD_DURABILITY)); stmt->setUInt32(++index, GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME)); stmt->setString(++index, m_text); + stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID) | (GetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD) << 24)); + stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_UPGRADE_ID)); + stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION)); + + std::ostringstream bonusListIDs; + for (uint32 bonusListID : GetDynamicValues(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS)) + bonusListIDs << bonusListID << ' '; + stmt->setString(++index, bonusListIDs.str()); + stmt->setUInt64(++index, GetGUID().GetCounter()); trans->Append(stmt); @@ -408,8 +420,8 @@ void Item::SaveToDB(SQLTransaction& trans) bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fields, uint32 entry) { - // 0 1 2 3 4 5 6 7 8 9 10 - //result = CharacterDatabase.PQuery("SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text FROM item_instance WHERE guid = '%u'", guid); + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + //result = CharacterDatabase.PQuery("SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, bonusListIDs FROM item_instance WHERE guid = '%u'", guid); // create item before any checks for store correct guid // and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB @@ -423,13 +435,17 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi if (!proto) return false; + _bonusData.Initialize(proto); + // set owner (not if item is only loaded for gbank/auction/mail if (!owner_guid.IsEmpty()) SetOwnerGUID(owner_guid); bool need_save = false; // need explicit save data at load fixes - SetGuidValue(ITEM_FIELD_CREATOR, ObjectGuid::Create<HighGuid::Player>(fields[0].GetUInt64())); - SetGuidValue(ITEM_FIELD_GIFTCREATOR, ObjectGuid::Create<HighGuid::Player>(fields[1].GetUInt64())); + if (uint64 creator = fields[0].GetUInt64()) + SetGuidValue(ITEM_FIELD_CREATOR, ObjectGuid::Create<HighGuid::Player>(creator)); + if (uint64 giftCreator = fields[1].GetUInt64()) + SetGuidValue(ITEM_FIELD_GIFTCREATOR, ObjectGuid::Create<HighGuid::Player>(giftCreator)); SetCount(fields[2].GetUInt32()); uint32 duration = fields[3].GetUInt32(); @@ -474,6 +490,24 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, fields[9].GetUInt32()); SetText(fields[10].GetString()); + if (uint32 transmogEntry = fields[11].GetUInt32()) + { + SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD, (transmogEntry >> 24) & 0xFF); + SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, transmogEntry & 0xFFFFFF); + } + SetModifier(ITEM_MODIFIER_UPGRADE_ID, fields[12].GetUInt32()); + SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION, fields[13].GetUInt32()); + + Tokenizer bonusListIDs(fields[14].GetString(), ' '); + for (char const* token : bonusListIDs) + { + uint32 bonusListID = atoul(token); + std::vector<ItemBonusEntry const*> bonuses = GetItemBonuses(bonusListID); + AddDynamicValue(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS, bonusListID); + for (ItemBonusEntry const* bonus : bonuses) + _bonusData.AddBonus(bonus->Type, bonus->Value); + } + if (need_save) // normal item changed state set not work at loading { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD); @@ -769,9 +803,6 @@ bool Item::HasEnchantRequiredSkill(const Player* player) const // Check all enchants for required skill for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot) { - if (enchant_slot > PRISMATIC_ENCHANTMENT_SLOT && enchant_slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id - continue; - if (uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot))) if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id)) if (enchantEntry->RequiredSkillID && player->GetSkillValue(enchantEntry->RequiredSkillID) < enchantEntry->RequiredSkillRank) @@ -788,9 +819,6 @@ uint32 Item::GetEnchantRequiredLevel() const // Check all enchants for required level for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot) { - if (enchant_slot > PRISMATIC_ENCHANTMENT_SLOT && enchant_slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id - continue; - if (uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot))) if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id)) if (enchantEntry->MinLevel > level) @@ -804,15 +832,10 @@ bool Item::IsBoundByEnchant() const { // Check all enchants for soulbound for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot) - { - if (enchant_slot > PRISMATIC_ENCHANTMENT_SLOT && enchant_slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id - continue; - if (uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot))) if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id)) if (enchantEntry->Flags & ENCHANTMENT_CAN_SOULBOUND) return true; - } return false; } @@ -1102,6 +1125,66 @@ void Item::BuildUpdate(UpdateDataMapType& data_map) ClearUpdateMask(false); } +void Item::BuildDynamicValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const +{ + if (!target) + return; + + ByteBuffer fieldBuffer; + UpdateMask updateMask; + updateMask.SetCount(_dynamicValuesCount); + + uint32* flags = nullptr; + uint32 visibleFlag = GetDynamicUpdateFieldData(target, flags); + + for (uint16 index = 0; index < _dynamicValuesCount; ++index) + { + ByteBuffer buffer; + std::vector<uint32> const& values = _dynamicValues[index]; + if (_fieldNotifyFlags & flags[index] || + ((updateType == UPDATETYPE_VALUES ? _dynamicChangesMask.GetBit(index) : !values.empty()) && (flags[index] & visibleFlag))) + { + updateMask.SetBit(index); + + UpdateMask arrayMask; + if (index != ITEM_DYNAMIC_FIELD_MODIFIERS) + { + arrayMask.SetCount(values.size()); + for (std::size_t v = 0; v < values.size(); ++v) + { + if (updateType != UPDATETYPE_VALUES || _dynamicChangesArrayMask[index].GetBit(v)) + { + arrayMask.SetBit(v); + buffer << uint32(values[v]); + } + } + } + else + { + uint32 count = 0; + arrayMask.SetCount(MAX_ITEM_MODIFIERS); + for (uint32 v = 0; v < MAX_ITEM_MODIFIERS; ++v) + { + if (uint32 modifier = _modifiers[v]) + { + arrayMask.SetBit(count++); + buffer << uint32(modifier); + } + } + + } + + fieldBuffer << uint8(arrayMask.GetBlockCount()); + arrayMask.AppendToPacket(&fieldBuffer); + fieldBuffer.append(buffer); + } + } + + *data << uint8(updateMask.GetBlockCount()); + updateMask.AppendToPacket(data); + data->append(fieldBuffer); +} + void Item::SaveRefundDataToDB() { SQLTransaction trans = CharacterDatabase.BeginTransaction(); @@ -1651,3 +1734,126 @@ void Item::ItemContainerDeleteLootMoneyAndLootItemsFromDB() ItemContainerDeleteLootMoneyFromDB(); ItemContainerDeleteLootItemsFromDB(); } + +uint32 Item::GetItemLevel() const +{ + if (Player const* owner = GetOwner()) + if (ScalingStatDistributionEntry const* ssd = sScalingStatDistributionStore.LookupEntry(GetTemplate()->GetScalingStatDistribution())) + if (uint32 heirloomIlvl = GetHeirloomItemLevel(ssd->ItemLevelCurveID, owner->getLevel())) + return heirloomIlvl + _bonusData.ItemLevel; + + return GetTemplate()->GetBaseItemLevel() + _bonusData.ItemLevel; +} + +int32 Item::GetItemStatValue(uint32 index) const +{ + ASSERT(index < MAX_ITEM_PROTO_STATS); + if (uint32 randomPropPoints = GetRandomPropertyPoints(GetItemLevel(), GetQuality(), GetTemplate()->GetInventoryType(), GetTemplate()->GetSubClass())) + { + float statValue = float(_bonusData.ItemStatAllocation[index] * randomPropPoints) * 0.0001f; + if (GtItemSocketCostPerLevelEntry const* gtCost = sGtItemSocketCostPerLevelStore.EvaluateTable(GetItemLevel() - 1, 0)) + statValue -= float(int32(_bonusData.ItemStatSocketCostMultiplier[index] * gtCost->ratio)); + + return int32(std::floor(statValue + 0.5f)); + } + + return _bonusData.ItemStatValue[index]; +} + +uint32 Item::GetDisplayId() const +{ + if (uint32 transmogrification = GetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID)) + return GetItemDisplayId(transmogrification, GetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD)); + + return GetItemDisplayId(GetEntry(), GetAppearanceModId()); +} + +void Item::SetModifier(ItemModifier modifier, uint32 value) +{ + _modifiers[modifier] = value; + ApplyModFlag(ITEM_FIELD_MODIFIERS_MASK, 1 << (modifier - 1), value != 0); +} + +uint32 Item::GetVisibleEntry() const +{ + if (uint32 transmogrification = GetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID)) + return transmogrification; + + return GetEntry(); +} + +uint32 Item::GetVisibleAppearanceModId() const +{ + if (uint32 transmogMod = GetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD)) + return transmogMod; + + return GetAppearanceModId(); +} + +void BonusData::Initialize(ItemTemplate const* proto) +{ + Quality = proto->GetQuality(); + ItemLevel = 0; + RequiredLevel = proto->GetBaseRequiredLevel(); + for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) + ItemStatType[i] = proto->GetItemStatType(i); + + for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) + ItemStatValue[i] = proto->GetItemStatValue(i); + + for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) + ItemStatAllocation[i] = proto->GetItemStatAllocation(i); + + for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) + ItemStatSocketCostMultiplier[i] = proto->GetItemStatSocketCostMultiplier(i); + + for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i) + SocketColor[i] = proto->GetSocketColor(i); + + AppearanceModID = 0; +} + +void BonusData::AddBonus(uint32 type, int32 const (&values)[2]) +{ + switch (type) + { + case ITEM_BONUS_ITEM_LEVEL: + ItemLevel += values[0]; + break; + case ITEM_BONUS_STAT: + { + uint32 statIndex = 0; + for (statIndex = 0; statIndex < MAX_ITEM_PROTO_STATS; ++statIndex) + if (ItemStatType[statIndex] == values[0]) + break; + + if (statIndex < MAX_ITEM_PROTO_SOCKETS) + ItemStatAllocation[statIndex] += values[1]; + break; + } + case ITEM_BONUS_QUALITY: + if (Quality < values[0]) + Quality = values[0]; + break; + case ITEM_BONUS_SOCKET: + { + uint32 socketCount = values[0]; + for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS && socketCount; ++i) + { + if (!SocketColor[i]) + { + SocketColor[i] = values[1]; + --socketCount; + } + } + break; + } + case ITEM_BONUS_APPEARANCE: + if (AppearanceModID < values[0]) + AppearanceModID = values[0]; + break; + case ITEM_BONUS_REQUIRED_LEVEL: + RequiredLevel += values[0]; + break; + } +} diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index bf2d48d902a..2f3ec4c1b1a 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -166,16 +166,16 @@ enum EnchantmentSlot SOCK_ENCHANTMENT_SLOT_3 = 4, BONUS_ENCHANTMENT_SLOT = 5, PRISMATIC_ENCHANTMENT_SLOT = 6, // added at apply special permanent enchantment - //TODO: 7, - TRANSMOGRIFY_ENCHANTMENT_SLOT = 9, - MAX_INSPECTED_ENCHANTMENT_SLOT = 10, - - PROP_ENCHANTMENT_SLOT_0 = 10, // used with RandomSuffix - PROP_ENCHANTMENT_SLOT_1 = 11, // used with RandomSuffix - PROP_ENCHANTMENT_SLOT_2 = 12, // used with RandomSuffix and RandomProperty - PROP_ENCHANTMENT_SLOT_3 = 13, // used with RandomProperty - PROP_ENCHANTMENT_SLOT_4 = 14, // used with RandomProperty - MAX_ENCHANTMENT_SLOT = 15 + USE_ENCHANTMENT_SLOT = 7, + + MAX_INSPECTED_ENCHANTMENT_SLOT = 8, + + PROP_ENCHANTMENT_SLOT_0 = 8, // used with RandomSuffix + PROP_ENCHANTMENT_SLOT_1 = 9, // used with RandomSuffix + PROP_ENCHANTMENT_SLOT_2 = 10, // used with RandomSuffix and RandomProperty + PROP_ENCHANTMENT_SLOT_3 = 11, // used with RandomProperty + PROP_ENCHANTMENT_SLOT_4 = 12, // used with RandomProperty + MAX_ENCHANTMENT_SLOT = 13 }; #define MAX_VISIBLE_ITEM_OFFSET 2 // 2 fields per visible item (entry+enchantment) @@ -207,10 +207,36 @@ enum ItemUpdateState ITEM_REMOVED = 3 }; +enum ItemModifier +{ + ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD = 1, + ITEM_MODIFIER_TRANSMOG_ITEM_ID = 2, + ITEM_MODIFIER_UPGRADE_ID = 3, + ITEM_MODIFIER_ENCHANT_ILLUSION = 8, + + MAX_ITEM_MODIFIERS +}; + #define MAX_ITEM_SPELLS 5 bool ItemCanGoIntoBag(ItemTemplate const* proto, ItemTemplate const* pBagProto); +struct BonusData +{ + uint32 Quality; + int32 ItemLevel; + int32 RequiredLevel; + int32 ItemStatType[MAX_ITEM_PROTO_STATS]; + int32 ItemStatValue[MAX_ITEM_PROTO_STATS]; + int32 ItemStatAllocation[MAX_ITEM_PROTO_STATS]; + float ItemStatSocketCostMultiplier[MAX_ITEM_PROTO_STATS]; + uint32 SocketColor[MAX_ITEM_PROTO_SOCKETS]; + uint32 AppearanceModID; + + void Initialize(ItemTemplate const* proto); + void AddBonus(uint32 type, int32 const (&values)[2]); +}; + class Item : public Object { public: @@ -337,8 +363,16 @@ class Item : public Object bool IsVellum() const { return GetTemplate()->IsVellum(); } bool IsConjuredConsumable() const { return GetTemplate()->IsConjuredConsumable(); } bool IsRangedWeapon() const { return GetTemplate()->IsRangedWeapon(); } - uint32 GetItemLevel() const { return GetTemplate()->GetItemLevel(GetDynamicValues(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS)); } - uint32 GetDisplayId() const { return GetTemplate()->GetDisplayId(GetDynamicValues(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS)); } + uint32 GetQuality() const { return _bonusData.Quality; } + uint32 GetItemLevel() const; + int32 GetRequiredLevel() const { return _bonusData.RequiredLevel; } + int32 GetItemStatType(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_STATS); return _bonusData.ItemStatType[index]; } + int32 GetItemStatValue(uint32 index) const; + SocketColor GetSocketColor(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_SOCKETS); return SocketColor(_bonusData.SocketColor[index]); } + uint32 GetAppearanceModId() const { return _bonusData.AppearanceModID; } + uint32 GetArmor() const { return GetTemplate()->GetArmor(GetItemLevel()); } + void GetDamage(float& minDamage, float& maxDamage) const { GetTemplate()->GetDamage(GetItemLevel(), minDamage, maxDamage); } + uint32 GetDisplayId() const; // Item Refund system void SetNotRefundable(Player* owner, bool changestate = true, SQLTransaction* trans = NULL); @@ -360,6 +394,7 @@ class Item : public Object bool CheckSoulboundTradeExpire(); void BuildUpdate(UpdateDataMapType&) override; + void BuildDynamicValuesUpdate(uint8 updatetype, ByteBuffer* data, Player* target) const override; uint32 GetScriptId() const { return GetTemplate()->ScriptId; } @@ -369,15 +404,17 @@ class Item : public Object static uint32 GetSpecialPrice(ItemTemplate const* proto, uint32 minimumPrice = 10000); uint32 GetSpecialPrice(uint32 minimumPrice = 10000) const { return Item::GetSpecialPrice(GetTemplate(), minimumPrice); } - uint32 GetVisibleEntry() const - { - if (uint32 transmogrification = GetEnchantmentId(TRANSMOGRIFY_ENCHANTMENT_SLOT)) - return transmogrification; - return GetEntry(); - } + uint32 GetVisibleEntry() const; + uint32 GetVisibleAppearanceModId() const; static uint32 GetSellPrice(ItemTemplate const* proto, bool& success); + uint32 GetModifier(ItemModifier modifier) const { return _modifiers[modifier]; } + void SetModifier(ItemModifier modifier, uint32 value); + + protected: + BonusData _bonusData; + private: std::string m_text; uint8 m_slot; @@ -390,5 +427,6 @@ class Item : public Object uint32 m_paidMoney; uint32 m_paidExtendedCost; GuidSet allowedGUIDs; + uint32 _modifiers[MAX_ITEM_MODIFIERS]; }; #endif diff --git a/src/server/game/Entities/Item/ItemTemplate.cpp b/src/server/game/Entities/Item/ItemTemplate.cpp index bbcdde214c1..8a55b2cc886 100644 --- a/src/server/game/Entities/Item/ItemTemplate.cpp +++ b/src/server/game/Entities/Item/ItemTemplate.cpp @@ -34,17 +34,6 @@ char const* ItemTemplate::GetDefaultLocaleName() const return ExtendedData->Name->Str[sWorld->GetDefaultDbcLocale()]; } -uint32 ItemTemplate::GetItemLevel(std::vector<uint32> const& bonuses) const -{ - uint32 baseItemLevel = ExtendedData->ItemLevel; - return baseItemLevel; -} - -uint32 ItemTemplate::GetDisplayId(std::vector<uint32> const& bonusListIDs) const -{ - return 0; -} - uint32 ItemTemplate::GetArmor(uint32 itemLevel) const { uint32 quality = GetQuality() != ITEM_QUALITY_HEIRLOOM ? GetQuality() : ITEM_QUALITY_RARE; diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index e44c1e99d42..9a35182885e 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -608,7 +608,7 @@ struct ItemTemplate int32 GetAllowableClass() const { return ExtendedData->AllowableClass; } int32 GetAllowableRace() const { return ExtendedData->AllowableRace; } uint32 GetBaseItemLevel() const { return ExtendedData->ItemLevel; } - int32 GetRequiredLevel() const { return ExtendedData->RequiredLevel; } + int32 GetBaseRequiredLevel() const { return ExtendedData->RequiredLevel; } uint32 GetRequiredSkill() const { return ExtendedData->RequiredSkill; } uint32 GetRequiredSkillRank() const { return ExtendedData->RequiredSkillRank; } uint32 GetRequiredSpell() const { return ExtendedData->RequiredSpell; } @@ -699,8 +699,6 @@ struct ItemTemplate } char const* GetDefaultLocaleName() const; - uint32 GetItemLevel(std::vector<uint32> const& bonusListIDs) const; - uint32 GetDisplayId(std::vector<uint32> const& bonusListIDs) const; uint32 GetArmor(uint32 itemLevel) const; void GetDamage(uint32 itemLevel, float& minDamage, float& maxDamage) const; }; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 45ab3c84bb5..86dba7e2148 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4504,8 +4504,8 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe do { Field* itemFields = resultItems->Fetch(); - ObjectGuid::LowType item_guidlow = itemFields[11].GetUInt64(); - uint32 item_template = itemFields[12].GetUInt32(); + ObjectGuid::LowType item_guidlow = itemFields[15].GetUInt64(); + uint32 item_template = itemFields[16].GetUInt32(); ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(item_template); if (!itemProto) @@ -7787,55 +7787,33 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply) uint8 attacktype = Player::GetAttackBySlot(slot); - if (proto->GetSocketColor(0)) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items + if (item->GetSocketColor(0)) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items CorrectMetaGemEnchants(slot, apply); if (attacktype < MAX_ATTACK) _ApplyWeaponDependentAuraMods(item, WeaponAttackType(attacktype), apply); - _ApplyItemBonuses(proto, slot, apply); + _ApplyItemBonuses(item, slot, apply); ApplyItemEquipSpell(item, apply); ApplyEnchantment(item, apply); TC_LOG_DEBUG("entities.player.items", "_ApplyItemMods complete."); } -void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply, bool only_level_scale /*= false*/) +void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply) { + ItemTemplate const* proto = item->GetTemplate(); if (slot >= INVENTORY_SLOT_BAG_END || !proto) return; - ScalingStatDistributionEntry const* ssd = proto->GetScalingStatDistribution() ? sScalingStatDistributionStore.LookupEntry(proto->GetScalingStatDistribution()) : NULL; - if (only_level_scale && !ssd) - return; - // req. check at equip, but allow use for extended range if range limit max level, set proper level - uint32 ssd_level = getLevel(); - if (ssd && ssd_level > ssd->MaxLevel) - ssd_level = ssd->MaxLevel; - - ScalingStatValuesEntry const* ssv = ssd ? sScalingStatValuesStore.LookupEntry(ssd_level) : NULL; - if (only_level_scale && !ssv) - return; - for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) { - uint32 statType = 0; - int32 val = 0; - // If set ScalingStatDistribution need get stats and values from it - if (ssd && ssv) - { - if (ssd->StatID[i] < 0) - continue; - statType = ssd->StatID[i]; - val = (ssv->GetStatMultiplier(proto->GetInventoryType()) * ssd->Modifier[i]) / 10000; - } - else - { - statType = proto->GetItemStatType(i); - val = proto->GetItemStatValue(i); - } + int32 statType = item->GetItemStatType(i); + if (statType == -1) + continue; + int32 val = item->GetItemStatValue(i); if (val == 0) continue; @@ -8001,19 +7979,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply } } - // Apply Spell Power from ScalingStatValue if set - if (ssv && proto->GetFlags2() & ITEM_FLAGS_EXTRA_CASTER_WEAPON) - if (int32 spellbonus = int32(ssv->SpellPower)) - ApplySpellPowerBonus(spellbonus, apply); - - // If set ScalingStatValue armor get it or use item armor - uint32 armor = proto->GetBaseArmor(); - if (ssv && proto->GetClass() == ITEM_CLASS_ARMOR) - armor = ssv->GetArmor(proto->GetInventoryType(), proto->GetSubClass() - 1); - else if (armor && proto->GetArmorDamageModifier()) - armor -= uint32(proto->GetArmorDamageModifier()); - - if (armor) + if (uint32 armor = item->GetArmor()) { UnitModifierType modType = TOTAL_VALUE; if (proto->GetClass() == ITEM_CLASS_ARMOR) @@ -8029,12 +7995,14 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply break; } } + HandleStatModifier(UNIT_MOD_ARMOR, modType, float(armor), apply); } - // Add armor bonus from ArmorDamageModifier if > 0 + /* if (proto->GetArmorDamageModifier() > 0) HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(proto->GetArmorDamageModifier()), apply); + */ WeaponAttackType attType = BASE_ATTACK; @@ -8050,11 +8018,12 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply } if (CanUseAttackType(attType)) - _ApplyWeaponDamage(slot, proto, ssv, apply); + _ApplyWeaponDamage(slot, item, apply); } -void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingStatValuesEntry const* ssv, bool apply) +void Player::_ApplyWeaponDamage(uint8 slot, Item* item, bool apply) { + ItemTemplate const* proto = item->GetTemplate(); WeaponAttackType attType = BASE_ATTACK; float damage = 0.0f; @@ -8072,20 +8041,6 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt float minDamage, maxDamage; proto->GetBaseDamage(minDamage, maxDamage); - // If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage - int32 extraDPS = 0; - if (ssv) - { - float damageMultiplier = 0.0f; - extraDPS = ssv->GetDPSAndDamageMultiplier(proto->GetSubClass(), (proto->GetFlags2() & ITEM_FLAGS_EXTRA_CASTER_WEAPON) != 0, &damageMultiplier); - if (extraDPS) - { - float average = extraDPS * proto->GetDelay() / 1000.0f; - minDamage = (1.0f - damageMultiplier) * average; - maxDamage = (1.0f + damageMultiplier) * average; - } - } - if (minDamage > 0) { damage = apply ? minDamage : BASE_MINDAMAGE; @@ -8364,9 +8319,6 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 // item combat enchantments for (uint8 e_slot = 0; e_slot < MAX_ENCHANTMENT_SLOT; ++e_slot) { - if (e_slot > PRISMATIC_ENCHANTMENT_SLOT && e_slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id - continue; - uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(e_slot)); SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); if (!pEnchant) @@ -8488,9 +8440,6 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 // Item enchantments spells cast at use for (uint8 e_slot = 0; e_slot < MAX_ENCHANTMENT_SLOT; ++e_slot) { - if (e_slot > PRISMATIC_ENCHANTMENT_SLOT && e_slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id - continue; - uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(e_slot)); SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); if (!pEnchant) @@ -8548,15 +8497,12 @@ void Player::_RemoveAllItemMods() { if (m_items[i]->IsBroken() || !CanUseAttackType(GetAttackBySlot(i))) continue; - ItemTemplate const* proto = m_items[i]->GetTemplate(); - if (!proto) - continue; uint32 attacktype = Player::GetAttackBySlot(i); if (attacktype < MAX_ATTACK) _ApplyWeaponDependentAuraMods(m_items[i], WeaponAttackType(attacktype), false); - _ApplyItemBonuses(proto, i, false); + _ApplyItemBonuses(m_items[i], i, false); } } @@ -8574,15 +8520,11 @@ void Player::_ApplyAllItemMods() if (m_items[i]->IsBroken() || !CanUseAttackType(GetAttackBySlot(i))) continue; - ItemTemplate const* proto = m_items[i]->GetTemplate(); - if (!proto) - continue; - uint32 attacktype = Player::GetAttackBySlot(i); if (attacktype < MAX_ATTACK) _ApplyWeaponDependentAuraMods(m_items[i], WeaponAttackType(attacktype), true); - _ApplyItemBonuses(proto, i, true); + _ApplyItemBonuses(m_items[i], i, true); } } @@ -8618,11 +8560,7 @@ void Player::_ApplyAllLevelScaleItemMods(bool apply) if (m_items[i]->IsBroken() || !CanUseAttackType(GetAttackBySlot(i))) continue; - ItemTemplate const* proto = m_items[i]->GetTemplate(); - if (!proto) - continue; - - _ApplyItemBonuses(proto, i, apply, true); + _ApplyItemBonuses(m_items[i], i, apply); } } } @@ -9989,7 +9927,7 @@ uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const if (skipItem && skipItem->GetTemplate()->GetGemProperties()) for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i) if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (pItem != skipItem && pItem->GetTemplate()->GetSocketColor(0)) + if (pItem != skipItem && pItem->GetSocketColor(0)) count += pItem->GetGemCountWithID(item); if (inBankAlso) @@ -10007,7 +9945,7 @@ uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const if (skipItem && skipItem->GetTemplate()->GetGemProperties()) for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; ++i) if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (pItem != skipItem && pItem->GetTemplate()->GetSocketColor(0)) + if (pItem != skipItem && pItem->GetSocketColor(0)) count += pItem->GetGemCountWithID(item); } @@ -10344,7 +10282,7 @@ bool Player::HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_ continue; Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i); - if (pItem && pItem->GetTemplate()->GetSocketColor(0)) + if (pItem && pItem->GetSocketColor(0)) { tempcount += pItem->GetGemCountWithID(item); if (tempcount >= count) @@ -10379,7 +10317,7 @@ bool Player::HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 return true; } - if (pProto->GetSocketColor(0) || pItem->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)) + if (pItem->GetSocketColor(0) || pItem->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)) { tempcount += pItem->GetGemCountWithLimitCategory(limitCategory); if (tempcount >= count) @@ -11604,7 +11542,7 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const if (proto->GetRequiredSpell() != 0 && !HasSpell(proto->GetRequiredSpell())) return EQUIP_ERR_PROFICIENCY_NEEDED; - if (getLevel() < proto->GetRequiredLevel()) + if (getLevel() < proto->GetBaseRequiredLevel()) return EQUIP_ERR_CANT_EQUIP_LEVEL_I; // If World Event is not active, prevent using event dependant items @@ -12013,8 +11951,8 @@ void Player::SetVisibleItemSlot(uint8 slot, Item* pItem) if (pItem) { SetUInt32Value(PLAYER_VISIBLE_ITEM + VISIBLE_ITEM_ENTRY_OFFSET + (slot * 3), pItem->GetVisibleEntry()); - SetUInt16Value(PLAYER_VISIBLE_ITEM + VISIBLE_ITEM_ENCHANTMENT_OFFSET + (slot * 3), 0, pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); - SetUInt16Value(PLAYER_VISIBLE_ITEM + VISIBLE_ITEM_ENCHANTMENT_OFFSET + (slot * 3), 1, pItem->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)); + SetUInt16Value(PLAYER_VISIBLE_ITEM + VISIBLE_ITEM_ENCHANTMENT_OFFSET + (slot * 3), 0, pItem->GetVisibleAppearanceModId()); + SetUInt16Value(PLAYER_VISIBLE_ITEM + VISIBLE_ITEM_ENCHANTMENT_OFFSET + (slot * 3), 1, pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); } else { @@ -13094,9 +13032,8 @@ void Player::SendEquipError(InventoryResult msg, Item* pItem, Item* pItem2, uint error.itemGUID1 = pItem ? pItem->GetGUID() : ObjectGuid::Empty; error.itemGUID2 = pItem2 ? pItem2->GetGUID() : ObjectGuid::Empty; - ItemTemplate const* proto = pItem ? pItem->GetTemplate() : sObjectMgr->GetItemTemplate(itemid); - error.level = uint32(proto ? proto->GetRequiredLevel() : 0); - + error.level = uint32(pItem ? pItem->GetRequiredLevel() : 0); + GetSession()->SendPacket(error.Write()); } @@ -13231,9 +13168,6 @@ void Player::AddEnchantmentDurations(Item* item) { for (int x = 0; x < MAX_ENCHANTMENT_SLOT; ++x) { - if (x > PRISMATIC_ENCHANTMENT_SLOT && x < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id - continue; - if (!item->GetEnchantmentId(EnchantmentSlot(x))) continue; @@ -13342,9 +13276,6 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool if (slot >= MAX_ENCHANTMENT_SLOT) return; - if (slot == TRANSMOGRIFY_ENCHANTMENT_SLOT) - return; - uint32 enchant_id = item->GetEnchantmentId(slot); if (!enchant_id) return; @@ -13370,7 +13301,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool // If we're dealing with a gem inside a prismatic socket we need to check the prismatic socket requirements // rather than the gem requirements itself. If the socket has no color it is a prismatic socket. if ((slot == SOCK_ENCHANTMENT_SLOT || slot == SOCK_ENCHANTMENT_SLOT_2 || slot == SOCK_ENCHANTMENT_SLOT_3) - && !item->GetTemplate()->GetSocketColor(slot - SOCK_ENCHANTMENT_SLOT)) + && !item->GetSocketColor(slot - SOCK_ENCHANTMENT_SLOT)) { // Check if the requirements for the prismatic socket are met before applying the gem stats SpellItemEnchantmentEntry const* pPrismaticEnchant = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)); @@ -13717,9 +13648,6 @@ void Player::UpdateSkillEnchantments(uint16 skill_id, uint16 curr_value, uint16 { for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot) { - if (slot > PRISMATIC_ENCHANTMENT_SLOT && slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id - continue; - uint32 ench_id = m_items[i]->GetEnchantmentId(EnchantmentSlot(slot)); if (!ench_id) continue; @@ -13740,7 +13668,7 @@ void Player::UpdateSkillEnchantments(uint16 skill_id, uint16 curr_value, uint16 // If we're dealing with a gem inside a prismatic socket we need to check the prismatic socket requirements // rather than the gem requirements itself. If the socket has no color it is a prismatic socket. if ((slot == SOCK_ENCHANTMENT_SLOT || slot == SOCK_ENCHANTMENT_SLOT_2 || slot == SOCK_ENCHANTMENT_SLOT_3) - && !m_items[i]->GetTemplate()->GetSocketColor(slot - SOCK_ENCHANTMENT_SLOT)) + && !m_items[i]->GetSocketColor(slot - SOCK_ENCHANTMENT_SLOT)) { SpellItemEnchantmentEntry const* pPrismaticEnchant = sSpellItemEnchantmentStore.LookupEntry(m_items[i]->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)); @@ -17596,7 +17524,8 @@ void Player::LoadCorpse() void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) { - //QueryResult* result = CharacterDatabase.PQuery("SELECT data, text, bag, slot, item, item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag, slot", GetGUIDLow()); + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 + //SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, bonusListIDs, bag, slot, item, itemEntry FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot //NOTE: the "order by `bag`" is important because it makes sure //the bagMap is filled before items in the bags are loaded //NOTE2: the "order by `slot`" is needed because mainhand weapons are (wrongly?) @@ -17618,8 +17547,8 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) Field* fields = result->Fetch(); if (Item* item = _LoadItem(trans, zoneId, timeDiff, fields)) { - ObjectGuid bagGuid = fields[11].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[11].GetUInt64()) : ObjectGuid::Empty; - uint8 slot = fields[12].GetUInt8(); + ObjectGuid bagGuid = fields[14].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[15].GetUInt64()) : ObjectGuid::Empty; + uint8 slot = fields[16].GetUInt8(); uint8 err = EQUIP_ERR_OK; // Item is not in bag @@ -17775,8 +17704,8 @@ void Player::_LoadVoidStorage(PreparedQueryResult result) Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, Field* fields) { Item* item = NULL; - ObjectGuid::LowType itemGuid = fields[13].GetUInt64(); - uint32 itemEntry = fields[14].GetUInt32(); + ObjectGuid::LowType itemGuid = fields[17].GetUInt64(); + uint32 itemEntry = fields[18].GetUInt32(); if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry)) { bool remove = false; @@ -17866,7 +17795,7 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F GameEventMgr::ActiveEvents const& activeEventsList = sGameEventMgr->GetActiveEventList(); for (GameEventMgr::ActiveEvents::const_iterator itr = activeEventsList.begin(); itr != activeEventsList.end(); ++itr) { - if (uint32(events[*itr].holiday_id) == proto->GetHolidayID()) + if (events[*itr].holiday_id == proto->GetHolidayID()) { remove = false; break; @@ -17913,8 +17842,8 @@ void Player::_LoadMailedItems(Mail* mail) { Field* fields = result->Fetch(); - ObjectGuid::LowType itemGuid = fields[11].GetUInt64(); - uint32 itemTemplate = fields[12].GetUInt32(); + ObjectGuid::LowType itemGuid = fields[15].GetUInt64(); + uint32 itemTemplate = fields[16].GetUInt32(); mail->AddItem(itemGuid, itemTemplate); @@ -17936,7 +17865,7 @@ void Player::_LoadMailedItems(Mail* mail) Item* item = NewItemOrBag(proto); - if (!item->LoadFromDB(itemGuid, ObjectGuid::Create<HighGuid::Player>(fields[13].GetUInt64()), fields, itemTemplate)) + if (!item->LoadFromDB(itemGuid, ObjectGuid::Create<HighGuid::Player>(fields[17].GetUInt64()), fields, itemTemplate)) { TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems - Item in mail (%u) doesn't exist !!!! - item guid: " UI64FMTD ", deleted from mail", mail->messageID, itemGuid); @@ -18908,18 +18837,22 @@ void Player::SaveToDB(bool create /*=false*/) ss.str(""); // cache equipment... - for (uint32 i = 0; i < EQUIPMENT_SLOT_END * 3; ++i) - ss << GetUInt32Value(PLAYER_VISIBLE_ITEM + i) << ' '; - - // ...and bags for enum opcode - for (uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + for (uint32 i = 0; i < INVENTORY_SLOT_BAG_END; ++i) { if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - ss << item->GetEntry(); + { + ss << item->GetTemplate()->GetInventoryType() << ' ' << item->GetDisplayId() << ' '; + if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT))) + ss << enchant->ItemVisual; + else + ss << '0'; + + ss << ' '; + } else - ss << '0'; - ss << " 0 0 "; + ss << "0 0 0 "; } + stmt->setString(index++, ss.str()); ss.str(""); @@ -19037,17 +18970,20 @@ void Player::SaveToDB(bool create /*=false*/) ss.str(""); // cache equipment... - for (uint32 i = 0; i < EQUIPMENT_SLOT_END * 3; ++i) - ss << GetUInt32Value(PLAYER_VISIBLE_ITEM + i) << ' '; - - // ...and bags for enum opcode - for (uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + for (uint32 i = 0; i < INVENTORY_SLOT_BAG_END; ++i) { if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - ss << item->GetEntry(); + { + ss << item->GetTemplate()->GetInventoryType() << ' ' << item->GetDisplayId() << ' '; + if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT))) + ss << enchant->ItemVisual; + else + ss << '0'; + + ss << ' '; + } else - ss << '0'; - ss << " 0 0 "; + ss << "0 0 0 "; } stmt->setString(index++, ss.str()); @@ -22168,7 +22104,7 @@ void Player::CorrectMetaGemEnchants(uint8 exceptslot, bool apply) Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, slot); - if (!pItem || !pItem->GetTemplate()->GetSocketColor(0)) + if (!pItem || !pItem->GetSocketColor(0)) continue; for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) @@ -22210,7 +22146,7 @@ void Player::ToggleMetaGemsActive(uint8 exceptslot, bool apply) Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, slot); - if (!pItem || !pItem->GetTemplate()->GetSocketColor(0)) //if item has no sockets or no item is equipped go to next item + if (!pItem || !pItem->GetSocketColor(0)) //if item has no sockets or no item is equipped go to next item continue; //cycle all (gem)enchants @@ -24939,7 +24875,7 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) --loot->unlootedCount; if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item->itemid)) - if (proto->GetQuality() > ITEM_QUALITY_EPIC || (proto->GetQuality() == ITEM_QUALITY_EPIC && proto->GetBaseItemLevel() >= MinNewsItemLevel[sWorld->getIntConfig(CONFIG_EXPANSION)])) + if (newitem->GetQuality() > ITEM_QUALITY_EPIC || (newitem->GetQuality() == ITEM_QUALITY_EPIC && newitem->GetItemLevel() >= MinNewsItemLevel[sWorld->getIntConfig(CONFIG_EXPANSION)])) if (Guild* guild = GetGuild()) guild->AddGuildNews(GUILD_NEWS_ITEM_LOOTED, GetGUID(), 0, item->itemid); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 8f16ef54864..cfcc3a09fc0 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2242,8 +2242,8 @@ class Player : public Unit, public GridObject<Player> void _RemoveAllItemMods(); void _ApplyAllItemMods(); void _ApplyAllLevelScaleItemMods(bool apply); - void _ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply, bool only_level_scale = false); - void _ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingStatValuesEntry const* ssv, bool apply); + void _ApplyItemBonuses(Item* item, uint8 slot, bool apply); + void _ApplyWeaponDamage(uint8 slot, Item* item, bool apply); bool EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot); void ToggleMetaGemsActive(uint8 exceptslot, bool apply); void CorrectMetaGemEnchants(uint8 slot, bool apply); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index bbd11c830c9..f9c532d23dd 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -2381,12 +2381,12 @@ void FillDisenchantFields(uint32* disenchantID, uint32* requiredDisenchantSkill, { if (disenchant->ID == 60 || disenchant->ID == 61) // epic item disenchant ilvl range 66-99 (classic) { - if (itemTemplate.GetRequiredLevel() > 60 || itemTemplate.GetRequiredSkillRank() > 300) + if (itemTemplate.GetBaseRequiredLevel() > 60 || itemTemplate.GetRequiredSkillRank() > 300) continue; // skip to epic item disenchant ilvl range 90-199 (TBC) } else if (disenchant->ID == 66 || disenchant->ID == 67) // epic item disenchant ilvl range 90-199 (TBC) { - if (itemTemplate.GetRequiredLevel() <= 60 || (itemTemplate.GetRequiredSkill() && itemTemplate.GetRequiredSkillRank() <= 300)) + if (itemTemplate.GetBaseRequiredLevel() <= 60 || (itemTemplate.GetRequiredSkill() && itemTemplate.GetRequiredSkillRank() <= 300)) continue; } diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 229d724974e..4bfeed3ef23 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -41,7 +41,7 @@ void WorldSession::HandleSplitItemOpcode(WorldPackets::Item::SplitItem& splitIte } //TC_LOG_DEBUG("network", "WORLD: CMSG_SPLIT_ITEM"); - + TC_LOG_DEBUG("network", "STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u, count = %u", splitItem.srcbag, splitItem.srcslot, splitItem.dstbag, splitItem.dstslot, splitItem.count); uint16 src = ((splitItem.srcbag << 8) | splitItem.srcslot); @@ -77,7 +77,7 @@ void WorldSession::HandleSwapInvItemOpcode(WorldPackets::Item::SwapInvItem& swap } //TC_LOG_DEBUG("network", "WORLD: CMSG_SWAP_INV_ITEM"); - + TC_LOG_DEBUG("network", "STORAGE: receive srcslot = %u, dstslot = %u", swapInvItem.srcslot, swapInvItem.dstslot); // prevent attempt swap same item to current position generated by client at special checting sequence @@ -188,7 +188,7 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem& } //TC_LOG_DEBUG("network", "WORLD: CMSG_AUTOEQUIP_ITEM"); - + TC_LOG_DEBUG("network", "STORAGE: receive srcbag = %u, srcslot = %u", autoEquipItem.srcbag, autoEquipItem.srcslot); Item* pSrcItem = _player->GetItemByPos(autoEquipItem.srcbag, autoEquipItem.srcslot); @@ -1087,19 +1087,19 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData) } // tried to put normal gem in meta socket - if (itemProto->GetSocketColor(i) == SOCKET_COLOR_META && GemProps[i]->Type != SOCKET_COLOR_META) + if (itemTarget->GetSocketColor(i) == SOCKET_COLOR_META && GemProps[i]->Type != SOCKET_COLOR_META) return; // tried to put meta gem in normal socket - if (itemProto->GetSocketColor(i) != SOCKET_COLOR_META && GemProps[i]->Type == SOCKET_COLOR_META) + if (itemTarget->GetSocketColor(i) != SOCKET_COLOR_META && GemProps[i]->Type == SOCKET_COLOR_META) return; // tried to put normal gem in cogwheel socket - if (itemProto->GetSocketColor(i) == SOCKET_COLOR_COGWHEEL && GemProps[i]->Type != SOCKET_COLOR_COGWHEEL) + if (itemTarget->GetSocketColor(i) == SOCKET_COLOR_COGWHEEL && GemProps[i]->Type != SOCKET_COLOR_COGWHEEL) return; // tried to put cogwheel gem in normal socket - if (itemProto->GetSocketColor(i) != SOCKET_COLOR_COGWHEEL && GemProps[i]->Type == SOCKET_COLOR_COGWHEEL) + if (itemTarget->GetSocketColor(i) != SOCKET_COLOR_COGWHEEL && GemProps[i]->Type == SOCKET_COLOR_COGWHEEL) return; } @@ -1478,7 +1478,7 @@ void WorldSession::HandleTransmogrifyItems(WorldPacket& recvData) if (transmogrifier[i]) { // Transmogrify - transmogrified[i]->SetEnchantment(TRANSMOGRIFY_ENCHANTMENT_SLOT, newEntries[i], 0, 0); + transmogrified[i]->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, newEntries[i]); player->SetVisibleItemSlot(slots[i], transmogrified[i]); transmogrified[i]->UpdatePlayedTime(player); @@ -1497,7 +1497,7 @@ void WorldSession::HandleTransmogrifyItems(WorldPacket& recvData) else { // Reset - transmogrified[i]->ClearEnchantment(TRANSMOGRIFY_ENCHANTMENT_SLOT); + transmogrified[i]->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, 0); player->SetVisibleItemSlot(slots[i], transmogrified[i]); } } diff --git a/src/server/game/Server/Packets/CharacterPackets.cpp b/src/server/game/Server/Packets/CharacterPackets.cpp index b15b939f60c..048b97248f7 100644 --- a/src/server/game/Server/Packets/CharacterPackets.cpp +++ b/src/server/game/Server/Packets/CharacterPackets.cpp @@ -100,27 +100,9 @@ WorldPackets::Character::EnumCharactersResult::CharacterInfo::CharacterInfo(Fiel for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot) { uint32 visualBase = slot * 3; - uint32 itemId = Player::GetUInt32ValueFromArray(equipment, visualBase); - if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId)) - { - uint32 enchants = Player::GetUInt32ValueFromArray(equipment, visualBase + 1); - for (uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot) - { - // values stored in 2 uint16 - uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot * 16); - if (!enchantId) - continue; - - if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId)) - { - VisualItems[slot].DisplayEnchantId = enchant->ItemVisual; - break; - } - } - - VisualItems[slot].DisplayId = 0/*proto->DisplayInfoID*/; - VisualItems[slot].InventoryType = uint8(proto->GetInventoryType()); - } + VisualItems[slot].InventoryType = Player::GetUInt32ValueFromArray(equipment, visualBase); + VisualItems[slot].DisplayId = Player::GetUInt32ValueFromArray(equipment, visualBase + 1); + VisualItems[slot].DisplayEnchantId = Player::GetUInt32ValueFromArray(equipment, visualBase + 2); } } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 9be39305691..9acd683fe92 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1970,7 +1970,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo if (!target->CanUseAttackType(BASE_ATTACK)) { if (Item* pItem = target->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND)) - target->ToPlayer()->_ApplyWeaponDamage(EQUIPMENT_SLOT_MAINHAND, pItem->GetTemplate(), NULL, apply); + target->ToPlayer()->_ApplyWeaponDamage(EQUIPMENT_SLOT_MAINHAND, pItem, apply); } } @@ -2401,7 +2401,7 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode, if (attacktype < MAX_ATTACK) { - player->_ApplyWeaponDamage(slot, item->GetTemplate(), NULL, !apply); + player->_ApplyWeaponDamage(slot, item, !apply); player->_ApplyWeaponDependentAuraMods(item, WeaponAttackType(attacktype), !apply); } } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 15a58cf76a8..eae52b77cff 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -6371,7 +6371,7 @@ SpellCastResult Spell::CheckItems() { uint32 numSockets = 0; for (uint32 socket = 0; socket < MAX_ITEM_PROTO_SOCKETS; ++socket) - if (targetItem->GetTemplate()->GetSocketColor(socket)) + if (targetItem->GetSocketColor(socket)) ++numSockets; if (numSockets == MAX_ITEM_PROTO_SOCKETS || targetItem->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 2ea5b76c7ca..1a710eb6df9 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1505,7 +1505,7 @@ void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype) // send info to the client player->SendNewItem(pItem, num_to_add, true, bgType == 0); - if (pProto->GetQuality() > ITEM_QUALITY_EPIC || (pProto->GetQuality() == ITEM_QUALITY_EPIC && pProto->GetBaseItemLevel() >= MinNewsItemLevel[sWorld->getIntConfig(CONFIG_EXPANSION)])) + if (pItem->GetQuality() > ITEM_QUALITY_EPIC || (pItem->GetQuality() == ITEM_QUALITY_EPIC && pItem->GetItemLevel() >= MinNewsItemLevel[sWorld->getIntConfig(CONFIG_EXPANSION)])) if (Guild* guild = player->GetGuild()) guild->AddGuildNews(GUILD_NEWS_ITEM_CRAFTED, player->GetGUID(), 0, pProto->GetId()); diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index 78ebe0734b5..f7ab4775c82 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -304,9 +304,6 @@ class spell_rog_deadly_poison : public SpellScriptLoader // item combat enchantments for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot) { - if (slot > PRISMATIC_ENCHANTMENT_SLOT && slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id - continue; - SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(EnchantmentSlot(slot))); if (!enchant) continue; diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 18a79ae0ed2..560a48be0c5 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -103,7 +103,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, bag, slot, " + PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, bonusListIDs, bag, slot, " "item, itemEntry FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS, "SELECT a.button, a.action, a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activeTalentGroup AND a.guid = ? ORDER BY button", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_MAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = ? AND (checked & 1) = 0 AND deliver_time <= ?", CONNECTION_ASYNC); @@ -131,8 +131,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES, "SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? ORDER BY button", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, item_guid, itemEntry, owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid WHERE mail_id = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_AUCTION_ITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, itemguid, itemEntry FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, item_guid, itemEntry, owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid WHERE mail_id = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_AUCTION_ITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, itemguid, itemEntry FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_AUCTIONS, "SELECT id, auctioneerguid, itemguid, itemEntry, count, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid", CONNECTION_SYNCH); PrepareStatement(CHAR_INS_AUCTION, "INSERT INTO auctionhouse (id, auctioneerguid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_AUCTION, "DELETE FROM auctionhouse WHERE id = ?", CONNECTION_ASYNC); @@ -154,8 +154,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, 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 = ? WHERE guid = ?", 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, transmogrification, upgradeId, enchantIllusion, 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 = ?, transmogrification = ?, upgradeId = ?, enchantIllusion = ?, bonusListIDs = ? 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); |