aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp6
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp20
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp79
-rw-r--r--src/server/game/DataStores/DB2Stores.h4
-rw-r--r--src/server/game/DataStores/DB2Structure.h30
-rw-r--r--src/server/game/DataStores/DB2fmt.h19
-rw-r--r--src/server/game/DataStores/DBCEnums.h12
-rw-r--r--src/server/game/DataStores/DBCStores.cpp186
-rw-r--r--src/server/game/DataStores/DBCStores.h2
-rw-r--r--src/server/game/DataStores/DBCStructure.h28
-rw-r--r--src/server/game/DataStores/DBCfmt.h4
-rw-r--r--src/server/game/Entities/Item/Container/Bag.cpp2
-rw-r--r--src/server/game/Entities/Item/Item.cpp236
-rw-r--r--src/server/game/Entities/Item/Item.h74
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.cpp11
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.h4
-rw-r--r--src/server/game/Entities/Player/Player.cpp198
-rw-r--r--src/server/game/Entities/Player/Player.h4
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp4
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp18
-rw-r--r--src/server/game/Server/Packets/CharacterPackets.cpp24
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp4
-rw-r--r--src/server/game/Spells/Spell.cpp2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
-rw-r--r--src/server/scripts/Spells/spell_rogue.cpp3
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp10
26 files changed, 543 insertions, 443 deletions
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);