diff options
-rw-r--r-- | sql/updates/hotfixes/3.4.x/2023_11_23_00_hotfixes.sql | 4 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Achievements/CriteriaHandler.cpp | 4 | ||||
-rw-r--r-- | src/server/game/AuctionHouse/AuctionHouseMgr.cpp | 4 | ||||
-rw-r--r-- | src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp | 14 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.cpp | 9 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 1 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Structure.h | 66 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 26 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.h | 5 | ||||
-rw-r--r-- | src/server/game/Entities/Item/ItemTemplate.h | 4 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 58 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 4 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 2 |
15 files changed, 145 insertions, 66 deletions
diff --git a/sql/updates/hotfixes/3.4.x/2023_11_23_00_hotfixes.sql b/sql/updates/hotfixes/3.4.x/2023_11_23_00_hotfixes.sql index 6b58c6925c8..542e3ef69d1 100644 --- a/sql/updates/hotfixes/3.4.x/2023_11_23_00_hotfixes.sql +++ b/sql/updates/hotfixes/3.4.x/2023_11_23_00_hotfixes.sql @@ -55,7 +55,7 @@ CREATE TABLE `scaling_stat_values` ( `ID` int(10) unsigned NOT NULL DEFAULT '0', `Charlevel` int(11) NOT NULL DEFAULT '0', `WeaponDPS1H` int(11) NOT NULL DEFAULT '0', - `WeaponDPS2h` int(11) NOT NULL DEFAULT '0', + `WeaponDPS2H` int(11) NOT NULL DEFAULT '0', `SpellcasterDPS1H` int(11) NOT NULL DEFAULT '0', `SpellcasterDPS2H` int(11) NOT NULL DEFAULT '0', `RangedDPS` int(11) NOT NULL DEFAULT '0', @@ -63,7 +63,7 @@ CREATE TABLE `scaling_stat_values` ( `SpellPower` int(11) NOT NULL DEFAULT '0', `ShoulderBudget` int(11) NOT NULL DEFAULT '0', `TrinketBudget` int(11) NOT NULL DEFAULT '0', - `WeaponBudget` int(11) NOT NULL DEFAULT '0', + `WeaponBudget1H` int(11) NOT NULL DEFAULT '0', `PrimaryBudget` int(11) NOT NULL DEFAULT '0', `RangedBudget` int(11) NOT NULL DEFAULT '0', `TertiaryBudget` int(11) NOT NULL DEFAULT '0', diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 32506a8fcb6..6cdea6df445 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -1327,8 +1327,8 @@ void HotfixDatabaseConnection::DoPrepareStatements() PREPARE_MAX_ID_STMT(HOTFIX_SEL_SCALING_STAT_DISTRIBUTION, "SELECT MAX(ID) + 1 FROM scaling_stat_distribution", CONNECTION_SYNCH); // ScalingStatValues.db2 - PrepareStatement(HOTFIX_SEL_SCALING_STAT_VALUES, "SELECT ID, Charlevel, WeaponDPS1H, WeaponDPS2h, SpellcasterDPS1H, SpellcasterDPS2H, RangedDPS, " - "WandDPS, SpellPower, ShoulderBudget, TrinketBudget, WeaponBudget, PrimaryBudget, RangedBudget, TertiaryBudget, ClothShoulderArmor, " + PrepareStatement(HOTFIX_SEL_SCALING_STAT_VALUES, "SELECT ID, Charlevel, WeaponDPS1H, WeaponDPS2H, SpellcasterDPS1H, SpellcasterDPS2H, RangedDPS, " + "WandDPS, SpellPower, ShoulderBudget, TrinketBudget, WeaponBudget1H, PrimaryBudget, RangedBudget, TertiaryBudget, ClothShoulderArmor, " "LeatherShoulderArmor, MailShoulderArmor, PlateShoulderArmor, ClothCloakArmor, ClothChestArmor, LeatherChestArmor, MailChestArmor, " "PlateChestArmor FROM scaling_stat_values WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); PREPARE_MAX_ID_STMT(HOTFIX_SEL_SCALING_STAT_VALUES, "SELECT MAX(ID) + 1 FROM scaling_stat_values", CONNECTION_SYNCH); diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp index 27398cd0c7e..bea97f7ab09 100644 --- a/src/server/game/Achievements/CriteriaHandler.cpp +++ b/src/server/game/Achievements/CriteriaHandler.cpp @@ -410,7 +410,7 @@ bool CriteriaData::Meets(uint32 criteriaId, Player const* source, WorldObject co ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId); if (!itemTemplate) return false; - return itemTemplate->GetBaseItemLevel() >= EquippedItem.ItemLevel && itemTemplate->GetQuality() >= EquippedItem.Quality; + return itemTemplate->GetItemLevel() >= EquippedItem.ItemLevel && itemTemplate->GetQuality() >= EquippedItem.Quality; } case CRITERIA_DATA_TYPE_MAP_ID: return source->GetMapId() == Map.Id; @@ -1718,7 +1718,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 { // miscValue1 is itemid ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1)); - if (!item || item->GetBaseItemLevel() < reqValue) + if (!item || item->GetItemLevel() < reqValue) return false; break; } diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index 39949525630..ab4fe0f99e4 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -84,7 +84,7 @@ AuctionsBucketKey AuctionsBucketKey::ForItem(Item const* item) AuctionsBucketKey AuctionsBucketKey::ForCommodity(ItemTemplate const* itemTemplate) { - return { itemTemplate->GetId(), uint16(itemTemplate->GetBaseItemLevel()), 0, 0 }; + return { itemTemplate->GetId(), uint16(itemTemplate->GetItemLevel()), 0, 0 }; } void AuctionsBucketData::BuildBucketInfo(WorldPackets::AuctionHouse::BucketInfo* bucketInfo, Player const* player) const @@ -884,7 +884,7 @@ void AuctionHouseObject::AddAuction(CharacterDatabaseTransaction trans, AuctionP break; case ITEM_CLASS_GEM: case ITEM_CLASS_ITEM_ENHANCEMENT: - bucket->SortLevel = itemTemplate->GetBaseItemLevel(); + bucket->SortLevel = itemTemplate->GetItemLevel(); break; case ITEM_CLASS_CONSUMABLE: bucket->SortLevel = std::max<uint8>(1, bucket->RequiredLevel); diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp index 65d6d7cf8c0..066652b81bd 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp @@ -232,10 +232,10 @@ bool AuctionBotSeller::Initialize() case ITEM_CLASS_WEAPON: { if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_ITEM_LEVEL)) - if (prototype->GetBaseItemLevel() < value) + if (prototype->GetItemLevel() < value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_ITEM_LEVEL)) - if (prototype->GetBaseItemLevel() > value) + if (prototype->GetItemLevel() > value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_REQ_LEVEL)) if (prototype->GetBaseRequiredLevel() < static_cast<int32>(value)) @@ -316,10 +316,10 @@ bool AuctionBotSeller::Initialize() case ITEM_CLASS_TRADE_GOODS: { if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_MIN_ITEM_LEVEL)) - if (prototype->GetBaseItemLevel() < value) + if (prototype->GetItemLevel() < value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_MAX_ITEM_LEVEL)) - if (prototype->GetBaseItemLevel() > value) + if (prototype->GetItemLevel() > value) continue; break; } @@ -327,10 +327,10 @@ bool AuctionBotSeller::Initialize() case ITEM_CLASS_QUIVER: { if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_MIN_ITEM_LEVEL)) - if (prototype->GetBaseItemLevel() < value) + if (prototype->GetItemLevel() < value) continue; if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_MAX_ITEM_LEVEL)) - if (prototype->GetBaseItemLevel() > value) + if (prototype->GetItemLevel() > value) continue; break; } @@ -602,7 +602,7 @@ void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConf else { float divisor = ((itemProto->GetClass() == ITEM_CLASS_WEAPON || itemProto->GetClass() == ITEM_CLASS_ARMOR) ? 284.0f : 80.0f); - float tempLevel = (itemProto->GetBaseItemLevel() == 0 ? 1.0f : itemProto->GetBaseItemLevel()); + float tempLevel = (itemProto->GetItemLevel() == 0 ? 1.0f : itemProto->GetItemLevel()); float tempQuality = (itemProto->GetQuality() == 0 ? 1.0f : itemProto->GetQuality()); buyPrice = tempLevel * tempQuality * static_cast<float>(GetBuyModifier(itemProto))* tempLevel / divisor; diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index f0edc028f7c..6fbd316f650 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -478,6 +478,7 @@ namespace std::unordered_set<uint8> _spellFamilyNames; SpellProcsPerMinuteModContainer _spellProcsPerMinuteMods; std::unordered_map<int32, std::vector<SpellVisualMissileEntry const*>> _spellVisualMissilesBySet; + std::unordered_map<uint32, ScalingStatValuesEntry const*> _scalingStatValuesByLevel; TalentsByPosition _talentsByPosition; std::unordered_map<std::pair<uint32, uint32>, TaxiPathEntry const*> _taxiPaths; ToyItemIdsContainer _toys; @@ -1341,6 +1342,9 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul for (SpellVisualMissileEntry const* spellVisualMissile : sSpellVisualMissileStore) _spellVisualMissilesBySet[spellVisualMissile->SpellVisualMissileSetID].push_back(spellVisualMissile); + for (ScalingStatValuesEntry const* scalingStatValue : sScalingStatValuesStore) + _scalingStatValuesByLevel[scalingStatValue->Charlevel] = scalingStatValue; + for (TalentEntry const* talentInfo : sTalentStore) { ASSERT(talentInfo->ClassID < MAX_CLASSES); @@ -3051,3 +3055,8 @@ std::vector<ItemEffectEntry const*> const* DB2Manager::GetItemEffectsForItemId(u { return Trinity::Containers::MapGetValuePtr(_itemEffectsByItemId, itemId); } + +ScalingStatValuesEntry const* DB2Manager::GetScalingStatValuesForLevel(uint32 characterLevel) const +{ + return Trinity::Containers::MapGetValuePtr(_scalingStatValuesByLevel, characterLevel); +} diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 5f75928e390..0374d9228e6 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -499,6 +499,7 @@ public: bool IsUiMapPhase(uint32 phaseId) const; WMOAreaTableEntry const* GetWMOAreaTable(int32 rootId, int32 adtId, int32 groupId) const; std::vector<ItemEffectEntry const*> const* GetItemEffectsForItemId(uint32 itemId) const; + ScalingStatValuesEntry const* GetScalingStatValuesForLevel(uint32 characterLevel) const; private: friend class DB2HotfixGeneratorBase; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 1749f8a9d65..79b80d66581 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -3168,7 +3168,7 @@ struct ScalingStatValuesEntry uint32 ID; int32 Charlevel; int32 WeaponDPS1H; - int32 WeaponDPS2h; + int32 WeaponDPS2H; int32 SpellcasterDPS1H; int32 SpellcasterDPS2H; int32 RangedDPS; @@ -3176,7 +3176,7 @@ struct ScalingStatValuesEntry int32 SpellPower; int32 ShoulderBudget; int32 TrinketBudget; - int32 WeaponBudget; + int32 WeaponBudget1H; int32 PrimaryBudget; int32 RangedBudget; int32 TertiaryBudget; @@ -3189,6 +3189,68 @@ struct ScalingStatValuesEntry int32 LeatherChestArmor; int32 MailChestArmor; int32 PlateChestArmor; + + int32 getssdMultiplier(uint32 mask) const + { + if (mask & 0x4001F) + { + if (mask & 0x00000001) return ShoulderBudget; + if (mask & 0x00000002) return TrinketBudget; + if (mask & 0x00000004) return WeaponBudget1H; + if (mask & 0x00000008) return PrimaryBudget; + if (mask & 0x00000010) return RangedBudget; + if (mask & 0x00040000) return TertiaryBudget; + } + return 0; + } + + int32 getArmorMod(uint32 mask) const + { + if (mask & 0x00F001E0) + { + if (mask & 0x00000020) return ClothShoulderArmor; + if (mask & 0x00000040) return LeatherShoulderArmor; + if (mask & 0x00000080) return MailShoulderArmor; + if (mask & 0x00000100) return PlateShoulderArmor; + + if (mask & 0x00080000) return ClothCloakArmor; + if (mask & 0x00100000) return ClothChestArmor; + if (mask & 0x00200000) return LeatherChestArmor; + if (mask & 0x00400000) return MailChestArmor; + if (mask & 0x00800000) return PlateChestArmor; + } + return 0; + } + + int32 getDPSMod(uint32 mask) const + { + if (mask & 0x7E00) + { + if (mask & 0x00000200) return WeaponDPS1H; + if (mask & 0x00000400) return WeaponDPS2H; + if (mask & 0x00000800) return SpellcasterDPS1H; + if (mask & 0x00001000) return SpellcasterDPS2H; + if (mask & 0x00002000) return RangedDPS; + if (mask & 0x00004000) return WandDPS; + } + return 0; + } + + bool isTwoHand(uint32 mask) const + { + if (mask & 0x7E00) + { + if (mask & 0x00000400) return true; + if (mask & 0x00001000) return true; + } + return false; + } + + int32 getSpellBonus(uint32 mask) const + { + if (mask & 0x00008000) return SpellPower; + return 0; + } }; struct SceneScriptEntry diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 0fdaf2e4609..9dddf233a85 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -1139,7 +1139,7 @@ void Item::SetGem(uint16 slot, ItemDynamicFieldGems const* gem, uint32 gemScalin BonusData gemBonus; gemBonus.Initialize(gemTemplate); - uint32 gemBaseItemLevel = gemTemplate->GetBaseItemLevel(); + uint32 gemBaseItemLevel = gemTemplate->GetItemLevel(); if (gemBonus.PlayerLevelToItemLevelCurveId) if (uint32 scaledIlvl = uint32(sDB2Manager.GetCurveValueAt(gemBonus.PlayerLevelToItemLevelCurveId, gemScalingLevel))) gemBaseItemLevel = scaledIlvl; @@ -1564,16 +1564,7 @@ bool Item::HasStats() const ItemTemplate const* proto = GetTemplate(); Player const* owner = GetOwner(); for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) - if ((owner ? GetItemStatValue(i, owner) : proto->GetStatPercentEditor(i)) != 0) - return true; - - return false; -} - -bool Item::HasStats(WorldPackets::Item::ItemInstance const& /*itemInstance*/, BonusData const* bonus) -{ - for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) - if (bonus->ItemStatBonusAmount[i] != 0) + if (proto->GetStatModifierBonusAmount(i) != 0) return true; return false; @@ -1895,7 +1886,7 @@ uint32 Item::GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bon if (!itemTemplate) return MIN_ITEM_LEVEL; - uint32 itemLevel = itemTemplate->GetBaseItemLevel(); + uint32 itemLevel = itemTemplate->GetItemLevel(); if (bonusData.PlayerLevelToItemLevelCurveId) { @@ -1929,12 +1920,6 @@ uint32 Item::GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bon return std::min(std::max(itemLevel, uint32(MIN_ITEM_LEVEL)), uint32(MAX_ITEM_LEVEL)); } -float Item::GetItemStatValue(uint32 index, Player const* owner) const -{ - ASSERT(index < MAX_ITEM_PROTO_STATS); - return static_cast<float>(_bonusData.ItemStatBonusAmount[index]); -} - ItemDisenchantLootEntry const* Item::GetDisenchantLoot(Player const* owner) const { if (!_bonusData.CanDisenchant) @@ -2150,11 +2135,6 @@ void BonusData::Initialize(ItemTemplate const* proto) Quality = proto->GetQuality(); ItemLevelBonus = 0; RequiredLevel = proto->GetBaseRequiredLevel(); - for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) - ItemStatType[i] = proto->GetStatModifierBonusStat(i); - - for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) - ItemStatBonusAmount[i] = proto->GetStatModifierBonusAmount(i); for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) ItemStatSocketCostMultiplier[i] = proto->GetStatPercentageOfSocket(i); diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 2057db84847..feea7d67df8 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -70,8 +70,6 @@ struct BonusData uint32 Quality; int32 ItemLevelBonus; int32 RequiredLevel; - int32 ItemStatType[MAX_ITEM_PROTO_STATS]; - int32 ItemStatBonusAmount[MAX_ITEM_PROTO_STATS]; float ItemStatSocketCostMultiplier[MAX_ITEM_PROTO_STATS]; uint32 SocketColor[MAX_ITEM_PROTO_SOCKETS]; ItemBondingType Bonding; @@ -274,8 +272,6 @@ class TC_GAME_API Item : public Object static uint32 GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bonusData, uint32 level, uint32 fixedLevel, uint32 minItemLevel, uint32 minItemLevelCutoff, uint32 maxItemLevel, bool pvpBonus); int32 GetRequiredLevel() const; - int32 GetItemStatType(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_STATS); return _bonusData.ItemStatType[index]; } - float GetItemStatValue(uint32 index, Player const* owner) const; SocketColor GetSocketColor(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_SOCKETS); return SocketColor(_bonusData.SocketColor[index]); } uint32 GetAppearanceModId() const { return m_itemData->ItemAppearanceModID; } void SetAppearanceModId(uint32 appearanceModId) { SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::ItemAppearanceModID), appearanceModId); } @@ -338,7 +334,6 @@ class TC_GAME_API Item : public Object bool IsValidTransmogrificationTarget() const; bool HasStats() const; - static bool HasStats(WorldPackets::Item::ItemInstance const& itemInstance, BonusData const* bonus); static bool CanTransmogrifyItemWithItem(Item const* item, ItemModifiedAppearanceEntry const* itemModifiedAppearance); uint32 GetBuyPrice(Player const* owner, bool& standardPrice) const; static uint32 GetBuyPrice(ItemTemplate const* proto, uint32 quality, uint32 itemLevel, bool& standardPrice); diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index ddcc76d7268..ccaf8b571b4 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -786,7 +786,7 @@ struct TC_GAME_API ItemTemplate InventoryType GetInventoryType() const { return InventoryType(ExtendedData->InventoryType); } int32 GetAllowableClass() const { return ExtendedData->AllowableClass; } Trinity::RaceMask<int64> GetAllowableRace() const { return ExtendedData->AllowableRace; } - uint32 GetBaseItemLevel() const { return ExtendedData->ItemLevel; } + uint32 GetItemLevel() const { return ExtendedData->ItemLevel; } int32 GetBaseRequiredLevel() const { return ExtendedData->RequiredLevel; } uint32 GetRequiredSkill() const { return ExtendedData->RequiredSkill; } uint32 GetRequiredSkillRank() const { return ExtendedData->RequiredSkillRank; } @@ -826,6 +826,8 @@ struct TC_GAME_API ItemTemplate uint8 GetRequiredExpansion() const { return ExtendedData->ExpansionID; } int16 GetResistance(SpellSchools school) const { return ExtendedData->Resistances[school]; } int16 GetShieldBlockValue(uint32 itemLevel) const; + uint16 GetScalingStatDistributionID() const { return ExtendedData->ScalingStatDistributionID; } + int32 GetScalingStatValue() const { return BasicData->ScalingStatValue; } uint32 MaxDurability; std::vector<ItemEffectEntry const*> Effects; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f0ace58da03..87f23fa66ac 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7705,7 +7705,7 @@ void Player::DuelComplete(DuelCompleteType type) //---------------------------------------------------------// -void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply, bool updateItemAuras /*= true*/) +void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply, bool updateItemAuras /*= true*/, bool onlyForScalingItems /*= false*/) { if (slot >= INVENTORY_SLOT_BAG_END || !item) return; @@ -7723,7 +7723,7 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply, bool updateItemA 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); - _ApplyItemBonuses(item, slot, apply); + _ApplyItemBonuses(item, slot, apply, onlyForScalingItems); ApplyItemEquipSpell(item, apply); if (updateItemAuras) { @@ -7739,28 +7739,45 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply, bool updateItemA TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: completed"); } -void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply) +void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply, bool onlyForScalingItems /*= false*/) { ItemTemplate const* proto = item->GetTemplate(); if (slot >= INVENTORY_SLOT_BAG_END || !proto) return; - uint32 itemLevel = item->GetItemLevel(this); + ScalingStatDistributionEntry const* ssd = sScalingStatDistributionStore.LookupEntry(proto->GetScalingStatDistributionID()); + ScalingStatValuesEntry const* ssv = proto->GetScalingStatValue() != 0 ? sDB2Manager.GetScalingStatValuesForLevel(std::clamp<uint32>(GetLevel(), ssd->MinLevel, ssd->MaxLevel)) : nullptr; - float combatRatingMultiplier = 1.0f; - //if (GtCombatRatingsMultByILvl const* ratingMult = sCombatRatingsMultByILvlGameTable.GetRow(itemLevel)) - // combatRatingMultiplier = GetIlvlStatMultiplier(ratingMult, proto->GetInventoryType()); + if (onlyForScalingItems && (!ssd || !ssv)) + return; for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) { - int32 statType = item->GetItemStatType(i); - if (statType == -1) - continue; + int32 statType = 0; + int32 val = 0; + + if (ssd && ssv) + { + statType = ssd->StatID[i]; + if (statType == -1) + continue; + + val = (ssv->getssdMultiplier(proto->GetScalingStatValue()) * ssd->Bonus[i]) / 10000; + } + else + { + statType = proto->GetStatModifierBonusStat(i); + if (statType == -1) + continue; + + val = proto->GetStatModifierBonusAmount(i); + } - float val = item->GetItemStatValue(i, this); if (val == 0) continue; + float const combatRatingMultiplier = 1.0f; + switch (statType) { case ITEM_MOD_MANA: @@ -7982,11 +7999,24 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply) } } + // Apply Spell Power from ScalingStatValue if set + if (ssv) + if (int32 spellbonus = ssv->getSpellBonus(proto->GetScalingStatValue())) + ApplySpellPowerBonus(spellbonus, apply); + for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i) + { + SpellSchools school = SpellSchools(i); + int16 resistance = proto->GetResistance(school); + if (school == SPELL_SCHOOL_NORMAL && ssv) + if (uint32 ssvarmor = ssv->getArmorMod(proto->GetScalingStatValue())) + resistance = ssvarmor; + if (int16 resistance = proto->GetResistance(SpellSchools(i))) HandleStatFlatModifier(UnitMods(UNIT_MOD_ARMOR + i), BASE_VALUE, float(resistance), apply); + } - if (int16 shieldBlockValue = proto->GetShieldBlockValue(itemLevel)) + if (int16 shieldBlockValue = proto->GetShieldBlockValue(proto->GetItemLevel())) if (proto->GetClass() == ITEM_CLASS_ARMOR && proto->GetSubClass() == ITEM_SUBCLASS_ARMOR_SHIELD) SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::ShieldBlock), apply ? shieldBlockValue : 0); @@ -8611,7 +8641,7 @@ void Player::_ApplyAllLevelScaleItemMods(bool apply) if (!CanUseAttackType(Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType()))) continue; - _ApplyItemMods(m_items[i], i, apply); + _ApplyItemMods(m_items[i], i, apply, true); // Update item sets for heirlooms if (sDB2Manager.GetHeirloomByItemId(m_items[i]->GetEntry()) && m_items[i]->GetTemplate()->GetItemSet()) @@ -22355,7 +22385,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin if (crItem->maxcount != 0) // bought { - if (pProto->GetQuality() > ITEM_QUALITY_EPIC || (pProto->GetQuality() == ITEM_QUALITY_EPIC && pProto->GetBaseItemLevel() >= MinNewsItemLevel)) + if (pProto->GetQuality() > ITEM_QUALITY_EPIC || (pProto->GetQuality() == ITEM_QUALITY_EPIC && pProto->GetItemLevel() >= MinNewsItemLevel)) if (Guild* guild = GetGuild()) guild->AddGuildNews(GUILD_NEWS_ITEM_PURCHASED, GetGUID(), 0, item); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 7b9d2c03aa6..976e52fbc93 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2286,11 +2286,11 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> bool CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect const* aurEff) const override; - void _ApplyItemMods(Item* item, uint8 slot, bool apply, bool updateItemAuras = true); + void _ApplyItemMods(Item* item, uint8 slot, bool apply, bool updateItemAuras = true, bool onlyForScalingItems = false); void _RemoveAllItemMods(); void _ApplyAllItemMods(); void _ApplyAllLevelScaleItemMods(bool apply); - void _ApplyItemBonuses(Item* item, uint8 slot, bool apply); + void _ApplyItemBonuses(Item* item, uint8 slot, bool apply, bool onlyForScalingItems = false); void _ApplyWeaponDamage(uint8 slot, Item* item, bool apply); bool EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) const; void ToggleMetaGemsActive(uint8 exceptslot, bool apply); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index e4de9b8caa1..dae21c41307 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -6098,7 +6098,7 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32 if (!pet->HaveInDiet(foodItem->GetTemplate())) return SPELL_FAILED_WRONG_PET_FOOD; - if (foodItem->GetTemplate()->GetBaseItemLevel() + 30 <= pet->GetLevel()) + if (foodItem->GetTemplate()->GetItemLevel() + 30 <= pet->GetLevel()) return SPELL_FAILED_FOOD_LOWLEVEL; if (m_caster->ToPlayer()->IsInCombat() || pet->IsInCombat()) @@ -7564,9 +7564,9 @@ SpellCastResult Spell::CheckItems(int32* param1 /*= nullptr*/, int32* param2 /*= // Apply item level restriction if the enchanting spell has max level restrition set if (m_CastItem && m_spellInfo->MaxLevel > 0) { - if (item->GetTemplate()->GetBaseItemLevel() < (uint32)m_CastItem->GetTemplate()->GetBaseRequiredLevel()) + if (item->GetTemplate()->GetItemLevel() < (uint32)m_CastItem->GetTemplate()->GetBaseRequiredLevel()) return SPELL_FAILED_LOWLEVEL; - if (item->GetTemplate()->GetBaseItemLevel() > m_spellInfo->MaxLevel) + if (item->GetTemplate()->GetItemLevel() > m_spellInfo->MaxLevel) return SPELL_FAILED_HIGHLEVEL; } break; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 50125aa4406..d6a7e320cd1 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3491,7 +3491,7 @@ void Spell::EffectFeedPet() ExecuteLogEffectDestroyItem(SpellEffectName(effectInfo->Effect), foodItem->GetEntry()); int32 pct; - int32 levelDiff = int32(pet->GetLevel()) - int32(foodItem->GetTemplate()->GetBaseItemLevel()); + int32 levelDiff = int32(pet->GetLevel()) - int32(foodItem->GetTemplate()->GetItemLevel()); if (levelDiff >= 30) return; else if (levelDiff >= 20) |