aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/hotfixes/master/2018_03_05_00_hotfixes.sql11
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp3
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.h2
-rw-r--r--src/server/game/DataStores/DB2LoadInfo.h15
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp15
-rw-r--r--src/server/game/DataStores/DB2Stores.h1
-rw-r--r--src/server/game/DataStores/DB2Structure.h7
-rw-r--r--src/server/game/Entities/Item/Item.cpp27
-rw-r--r--src/server/game/Entities/Item/Item.h3
-rw-r--r--src/server/game/Entities/Player/Player.cpp26
-rw-r--r--src/server/game/Entities/Player/Player.h6
-rw-r--r--src/server/game/Groups/Group.cpp2
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);
}