diff options
-rw-r--r-- | sql/updates/hotfixes/master/2018_03_05_00_hotfixes.sql | 11 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.cpp | 3 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.h | 2 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2LoadInfo.h | 15 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.cpp | 15 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 1 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Structure.h | 7 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 27 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.h | 3 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 26 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 6 | ||||
-rw-r--r-- | src/server/game/Groups/Group.cpp | 2 |
12 files changed, 112 insertions, 6 deletions
diff --git a/sql/updates/hotfixes/master/2018_03_05_00_hotfixes.sql b/sql/updates/hotfixes/master/2018_03_05_00_hotfixes.sql new file mode 100644 index 00000000000..ccac08f99e7 --- /dev/null +++ b/sql/updates/hotfixes/master/2018_03_05_00_hotfixes.sql @@ -0,0 +1,11 @@ +-- +-- Table structure for table `pvp_item` +-- +DROP TABLE IF EXISTS `pvp_item`; +CREATE TABLE `pvp_item` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `ItemID` int(10) unsigned NOT NULL DEFAULT '0', + `ItemLevelBonus` tinyint(3) unsigned NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 0bca8efafb7..9ac48c17b5c 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -700,6 +700,9 @@ void HotfixDatabaseConnection::DoPrepareStatements() // PvpDifficulty.db2 PrepareStatement(HOTFIX_SEL_PVP_DIFFICULTY, "SELECT ID, BracketID, MinLevel, MaxLevel, MapID FROM pvp_difficulty ORDER BY ID DESC", CONNECTION_SYNCH); + // PvpItem.db2 + PrepareStatement(HOTFIX_SEL_PVP_ITEM, "SELECT ID, ItemID, ItemLevelBonus FROM pvp_item ORDER BY ID DESC", CONNECTION_SYNCH); + // PvpReward.db2 PrepareStatement(HOTFIX_SEL_PVP_REWARD, "SELECT ID, HonorLevel, Prestige, RewardPackID FROM pvp_reward ORDER BY ID DESC", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index eb8d0e9c596..f3711b2ded6 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -373,6 +373,8 @@ enum HotfixDatabaseStatements : uint32 HOTFIX_SEL_PVP_DIFFICULTY, + HOTFIX_SEL_PVP_ITEM, + HOTFIX_SEL_PVP_REWARD, HOTFIX_SEL_PVP_TALENT, diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h index 8c090977f7c..0c2f23ca4ae 100644 --- a/src/server/game/DataStores/DB2LoadInfo.h +++ b/src/server/game/DataStores/DB2LoadInfo.h @@ -3528,6 +3528,21 @@ struct PvpDifficultyLoadInfo } }; +struct PvpItemLoadInfo +{ + static DB2LoadInfo const* Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_INT, "ID" }, + { false, FT_INT, "ItemID" }, + { false, FT_BYTE, "ItemLevelBonus" }, + }; + static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, PVPItemMeta::Instance(), HOTFIX_SEL_PVP_ITEM); + return &loadInfo; + } +}; + struct PvpRewardLoadInfo { static DB2LoadInfo const* Instance() diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index a002b03c9c4..99b8f08495a 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -182,6 +182,7 @@ DB2Storage<PowerDisplayEntry> sPowerDisplayStore("PowerDisplay DB2Storage<PowerTypeEntry> sPowerTypeStore("PowerType.db2", PowerTypeLoadInfo::Instance()); DB2Storage<PrestigeLevelInfoEntry> sPrestigeLevelInfoStore("PrestigeLevelInfo.db2", PrestigeLevelInfoLoadInfo::Instance()); DB2Storage<PVPDifficultyEntry> sPVPDifficultyStore("PVPDifficulty.db2", PvpDifficultyLoadInfo::Instance()); +DB2Storage<PVPItemEntry> sPVPItemStore("PVPItem.db2", PvpItemLoadInfo::Instance()); DB2Storage<PvpRewardEntry> sPvpRewardStore("PvpReward.db2", PvpRewardLoadInfo::Instance()); DB2Storage<PvpTalentEntry> sPvpTalentStore("PvpTalent.db2", PvpTalentLoadInfo::Instance()); DB2Storage<PvpTalentUnlockEntry> sPvpTalentUnlockStore("PvpTalentUnlock.db2", PvpTalentUnlockLoadInfo::Instance()); @@ -364,6 +365,7 @@ namespace NameValidationRegexContainer _nameValidators; PhaseGroupContainer _phasesByGroup; PowerTypesContainer _powerTypes; + std::unordered_map<uint32, uint8> _pvpItemBonus; std::unordered_map<std::pair<uint32 /*prestige level*/, uint32 /*honor level*/>, uint32> _pvpRewardPack; PvpTalentsByPosition _pvpTalentsByPosition; uint32 _pvpTalentUnlock[MAX_PVP_TALENT_TIERS][MAX_PVP_TALENT_COLUMNS]; @@ -612,6 +614,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) LOAD_DB2(sPowerTypeStore); LOAD_DB2(sPrestigeLevelInfoStore); LOAD_DB2(sPVPDifficultyStore); + LOAD_DB2(sPVPItemStore); LOAD_DB2(sPvpRewardStore); LOAD_DB2(sPvpTalentStore); LOAD_DB2(sPvpTalentUnlockStore); @@ -947,6 +950,9 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) ASSERT(entry->BracketID < MAX_BATTLEGROUND_BRACKETS, "PvpDifficulty bracket (%d) exceeded max allowed value (%d)", entry->BracketID, MAX_BATTLEGROUND_BRACKETS); } + for (PVPItemEntry const* pvpItem : sPVPItemStore) + _pvpItemBonus[pvpItem->ItemID] = pvpItem->ItemLevelBonus; + for (PvpRewardEntry const* pvpReward : sPvpRewardStore) _pvpRewardPack[std::make_pair(pvpReward->Prestige, pvpReward->HonorLevel)] = pvpReward->RewardPackID; @@ -1993,6 +1999,15 @@ PowerTypeEntry const* DB2Manager::GetPowerTypeByName(std::string const& name) co return nullptr; } +uint8 DB2Manager::GetPvpItemLevelBonus(uint32 itemId) const +{ + auto itr = _pvpItemBonus.find(itemId); + if (itr != _pvpItemBonus.end()) + return itr->second; + + return 0; +} + std::vector<RewardPackXItemEntry const*> const* DB2Manager::GetRewardPackItemsByRewardID(uint32 rewardPackID) const { auto itr = _rewardPackItems.find(rewardPackID); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 05d91ebea6a..f81a79a7bae 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -305,6 +305,7 @@ public: std::set<uint32> GetPhasesForGroup(uint32 group) const; PowerTypeEntry const* GetPowerTypeEntry(Powers power) const; PowerTypeEntry const* GetPowerTypeByName(std::string const& name) const; + uint8 GetPvpItemLevelBonus(uint32 itemId) const; uint8 GetMaxPrestige() const; static PVPDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level); static PVPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id); diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 19274a61b06..c5cbaf90105 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -2109,6 +2109,13 @@ struct PVPDifficultyEntry BattlegroundBracketId GetBracketId() const { return BattlegroundBracketId(BracketID); } }; +struct PVPItemEntry +{ + uint32 ID; + uint32 ItemID; + uint8 ItemLevelBonus; +}; + struct PvpRewardEntry { uint32 ID; diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index f013ca1e0a1..6815d9f6c91 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -2175,10 +2175,16 @@ void Item::ItemContainerDeleteLootMoneyAndLootItemsFromDB() uint32 Item::GetItemLevel(Player const* owner) const { - return Item::GetItemLevel(GetTemplate(), _bonusData, owner->getLevel(), GetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL), GetModifier(ITEM_MODIFIER_UPGRADE_ID)); + uint32 minItemLevel = owner->GetUInt32Value(UNIT_FIELD_MIN_ITEM_LEVEL); + uint32 minItemLevelCutoff = owner->GetUInt32Value(UNIT_FIELD_MIN_ITEM_LEVEL_CUTOFF); + uint32 maxItemLevel = GetTemplate()->GetFlags3() & ITEM_FLAG3_IGNORE_ITEM_LEVEL_CAP_IN_PVP ? 0 : owner->GetUInt32Value(UNIT_FIELD_MAXITEMLEVEL); + bool pvpBonus = owner->IsUsingPvpItemLevels(); + return Item::GetItemLevel(GetTemplate(), _bonusData, owner->getLevel(), GetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL), GetModifier(ITEM_MODIFIER_UPGRADE_ID), + minItemLevel, minItemLevelCutoff, maxItemLevel, pvpBonus); } -uint32 Item::GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bonusData, uint32 level, uint32 fixedLevel, uint32 upgradeId) +uint32 Item::GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bonusData, uint32 level, uint32 fixedLevel, uint32 upgradeId, + uint32 minItemLevel, uint32 minItemLevelCutoff, uint32 maxItemLevel, bool pvpBonus) { if (!itemTemplate) return MIN_ITEM_LEVEL; @@ -2201,11 +2207,24 @@ uint32 Item::GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bon itemLevel += bonusData.ItemLevelBonus; + for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i) + itemLevel += bonusData.GemItemLevelBonus[i]; + + uint32 itemLevelBeforeUpgrades = itemLevel; if (ItemUpgradeEntry const* upgrade = sItemUpgradeStore.LookupEntry(upgradeId)) itemLevel += upgrade->ItemLevelBonus; - for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i) - itemLevel += bonusData.GemItemLevelBonus[i]; + if (pvpBonus) + itemLevel += sDB2Manager.GetPvpItemLevelBonus(itemTemplate->GetId()); + + if (itemTemplate->GetInventoryType() != INVTYPE_NON_EQUIP) + { + if (minItemLevel && (!minItemLevelCutoff || itemLevelBeforeUpgrades >= minItemLevelCutoff) && itemLevel < minItemLevel) + itemLevel = minItemLevel; + + if (maxItemLevel && itemLevel > maxItemLevel) + itemLevel = maxItemLevel; + } return std::min(std::max(itemLevel, uint32(MIN_ITEM_LEVEL)), uint32(MAX_ITEM_LEVEL)); } diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 210a3df1918..ed3abe13c50 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -262,7 +262,8 @@ class TC_GAME_API Item : public Object bool IsRangedWeapon() const { return GetTemplate()->IsRangedWeapon(); } uint32 GetQuality() const { return _bonusData.Quality; } uint32 GetItemLevel(Player const* owner) const; - static uint32 GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bonusData, uint32 level, uint32 fixedLevel, uint32 upgradeId); + static uint32 GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bonusData, uint32 level, uint32 fixedLevel, uint32 upgradeId, + uint32 minItemLevel, uint32 minItemLevelCutoff, uint32 maxItemLevel, bool pvpBonus); 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, Player const* owner) const; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d41aa8c75dc..e324b4196d8 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -348,6 +348,8 @@ Player::Player(WorldSession* session) : Unit(true), m_sceneMgr(this) _advancedCombatLoggingEnabled = false; _restMgr = Trinity::make_unique<RestMgr>(this); + + _usePvpItemLevels = false; } Player::~Player() @@ -23784,6 +23786,8 @@ void Player::SendInitialPacketsAfterAddToMap() if (_garrison) _garrison->SendRemoteInfo(); + + UpdateItemLevelAreaBasedScaling(); } void Player::SendUpdateToOutOfRangeGroupMembers() @@ -26330,6 +26334,8 @@ void Player::EnablePvpRules(bool dueToCombat /*= false*/) aura->SetDuration(-1); } } + + UpdateItemLevelAreaBasedScaling(); } void Player::DisablePvpRules() @@ -26339,7 +26345,10 @@ void Player::DisablePvpRules() return; if (!GetCombatTimer()) + { RemoveAurasDueToSpell(SPELL_PVP_RULES_ENABLED); + UpdateItemLevelAreaBasedScaling(); + } else if (Aura* aura = GetAura(SPELL_PVP_RULES_ENABLED)) aura->SetDuration(aura->GetSpellInfo()->GetMaxDuration()); } @@ -28240,3 +28249,20 @@ uint32 Player::DoRandomRoll(uint32 minimum, uint32 maximum) return roll; } + +void Player::UpdateItemLevelAreaBasedScaling() +{ + // @todo Activate pvp item levels during world pvp + Map* map = GetMap(); + bool pvpActivity = map->IsBattlegroundOrArena() || map->GetEntry()->Flags[1] & 0x40 || HasPvpRulesEnabled(); + + if (_usePvpItemLevels != pvpActivity) + { + float healthPct = GetHealthPct(); + _RemoveAllItemMods(); + ActivatePvpItemLevels(pvpActivity); + _ApplyAllItemMods(); + SetHealth(CalculatePct(GetMaxHealth(), healthPct)); + } + // @todo other types of power scaling such as timewalking +} diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 63fa4c2398f..e77aa588fa1 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2224,6 +2224,10 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> uint32 DoRandomRoll(uint32 minimum, uint32 maximum); + void UpdateItemLevelAreaBasedScaling(); + void ActivatePvpItemLevels(bool activate) { _usePvpItemLevels = activate; } + bool IsUsingPvpItemLevels() const { return _usePvpItemLevels; } + /*********************************************************/ /*** INSTANCE SYSTEM ***/ /*********************************************************/ @@ -2721,6 +2725,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void _InitHonorLevelOnLoadFromDB(uint32 /*honor*/, uint32 /*honorLevel*/, uint32 /*prestigeLevel*/); std::unique_ptr<RestMgr> _restMgr; + + bool _usePvpItemLevels; }; TC_GAME_API void AddItemsSetItem(Player* player, Item* item); diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index a68f4aec9ad..8a5bc685efe 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -1902,7 +1902,7 @@ ItemDisenchantLootEntry const* Roll::GetItemDisenchantLoot(Player const* player) bonusData.Initialize(itemInstance); ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemid); - uint32 itemLevel = Item::GetItemLevel(itemTemplate, bonusData, player->getLevel(), 0, lootItemInSlot->upgradeId); + uint32 itemLevel = Item::GetItemLevel(itemTemplate, bonusData, player->getLevel(), 0, lootItemInSlot->upgradeId, 0, 0, 0, false); return Item::GetDisenchantLoot(itemTemplate, bonusData.Quality, itemLevel); } |