aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2018-09-18 23:37:45 +0200
committerShauren <shauren.trinity@gmail.com>2018-09-26 19:01:31 +0200
commite0309d94c8502d57734998cac769c474f355f7a2 (patch)
treea6c162585dccc51156eebc6a665c761a74788d52
parent573dd01c6c51c0898ac17bb3073a5a7e7db89193 (diff)
Core/Players: Updated pvp talent implementation to bfa
-rw-r--r--sql/base/characters_database.sql10
-rw-r--r--sql/updates/characters/master/2018_09_18_00_characters.sql8
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp4
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp86
-rw-r--r--src/server/game/DataStores/DB2Stores.h8
-rw-r--r--src/server/game/DataStores/DB2Structure.h15
-rw-r--r--src/server/game/DataStores/DBCEnums.h3
-rw-r--r--src/server/game/Entities/Player/Player.cpp189
-rw-r--r--src/server/game/Entities/Player/Player.h11
-rw-r--r--src/server/game/Handlers/SkillHandler.cpp2
-rw-r--r--src/server/game/Server/Packets/TalentPackets.h2
11 files changed, 142 insertions, 196 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql
index 687f66af959..3e07e87a99c 100644
--- a/sql/base/characters_database.sql
+++ b/sql/base/characters_database.sql
@@ -1095,9 +1095,12 @@ DROP TABLE IF EXISTS `character_pvp_talent`;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `character_pvp_talent` (
`guid` bigint(20) unsigned NOT NULL,
- `talentId` mediumint(8) unsigned NOT NULL,
+ `talentId0` int(10) unsigned NOT NULL,
+ `talentId1` int(10) unsigned NOT NULL,
+ `talentId2` int(10) unsigned NOT NULL,
+ `talentId3` int(10) unsigned NOT NULL,
`talentGroup` tinyint(3) unsigned NOT NULL DEFAULT '0',
- PRIMARY KEY (`guid`,`talentId`,`talentGroup`)
+ PRIMARY KEY (`guid`,`talentGroup`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -3566,7 +3569,8 @@ INSERT INTO `updates` VALUES
('2018_03_04_00_characters.sql','2A4CD2EE2547E718490706FADC78BF36F0DED8D6','RELEASED','2018-03-04 18:15:24',0),
('2018_04_28_00_characters.sql','CBD0FDC0F32DE3F456F7CE3D9CAD6933CD6A50F5','RELEASED','2018-04-28 12:44:09',0),
('2018_07_28_00_characters.sql','31F66AE7831251A8915625EC7F10FA138AB8B654','RELEASED','2018-07-28 18:30:19',0),
-('2018_07_31_00_characters.sql','7DA8D4A4534520B23E6F5BBD5B8EE205B799C798','RELEASED','2018-07-31 20:54:39',0);
+('2018_07_31_00_characters.sql','7DA8D4A4534520B23E6F5BBD5B8EE205B799C798','RELEASED','2018-07-31 20:54:39',0),
+('2018_09_18_00_characters.sql','7FE9641C93ED762597C08F1E9B6649C9EC2F0E47','RELEASED','2018-09-18 23:34:29',0);
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
UNLOCK TABLES;
diff --git a/sql/updates/characters/master/2018_09_18_00_characters.sql b/sql/updates/characters/master/2018_09_18_00_characters.sql
new file mode 100644
index 00000000000..8a2dc041fe3
--- /dev/null
+++ b/sql/updates/characters/master/2018_09_18_00_characters.sql
@@ -0,0 +1,8 @@
+TRUNCATE `character_pvp_talent`;
+ALTER TABLE `character_pvp_talent`
+ DROP PRIMARY KEY,
+ CHANGE `talentId` `talentId0` int(10) unsigned NOT NULL AFTER `guid`,
+ ADD `talentId1` int(10) unsigned NOT NULL AFTER `talentId0`,
+ ADD `talentId2` int(10) unsigned NOT NULL AFTER `talentId1`,
+ ADD `talentId3` int(10) unsigned NOT NULL AFTER `talentId2`,
+ ADD PRIMARY KEY(`guid`,`talentGroup`);
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index d0227fde660..359a1dd92db 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -139,7 +139,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_CHARACTER_BGDATA, "SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell FROM character_battleground_data WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyphId FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT talentId, talentGroup FROM character_talent WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_CHARACTER_PVP_TALENTS, "SELECT talentId, talentGroup FROM character_pvp_talent WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHARACTER_PVP_TALENTS, "SELECT talentId0, talentId1, talentId2, talentId3, talentGroup FROM character_pvp_talent WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_SKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_RANDOMBG, "SELECT guid FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_BANNED, "SELECT guid FROM character_banned WHERE guid = ? AND active = 1", CONNECTION_ASYNC);
@@ -624,7 +624,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_OWNER, "DELETE FROM petition_sign WHERE ownerguid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_CHAR_GLYPHS, "INSERT INTO character_glyphs VALUES(?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_CHAR_TALENT, "INSERT INTO character_talent (guid, talentId, talentGroup) VALUES (?, ?, ?)", CONNECTION_ASYNC);
- PrepareStatement(CHAR_INS_CHAR_PVP_TALENT, "INSERT INTO character_pvp_talent (guid, talentId, talentGroup) VALUES (?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_CHAR_PVP_TALENT, "INSERT INTO character_pvp_talent (guid, talentId0, talentId1, talentId2, talentId3, talentGroup) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHAR_LIST_SLOT, "UPDATE characters SET slot = ? WHERE guid = ? AND account = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_CHAR_FISHINGSTEPS, "INSERT INTO character_fishingsteps (guid, fishingSteps) VALUES (?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_FISHINGSTEPS, "DELETE FROM character_fishingsteps WHERE guid = ?", CONNECTION_ASYNC);
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index 64ca72a6381..795dcdbc650 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -191,9 +191,9 @@ DB2Storage<PowerTypeEntry> sPowerTypeStore("PowerType.db2",
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());
+DB2Storage<PvpTalentCategoryEntry> sPvpTalentCategoryStore("PvpTalentCategory.db2", PvpTalentCategoryLoadInfo::Instance());
+DB2Storage<PvpTalentSlotUnlockEntry> sPvpTalentSlotUnlockStore("PvpTalentSlotUnlock.db2", PvpTalentSlotUnlockLoadInfo::Instance());
DB2Storage<QuestFactionRewardEntry> sQuestFactionRewardStore("QuestFactionReward.db2", QuestFactionRewardLoadInfo::Instance());
DB2Storage<QuestMoneyRewardEntry> sQuestMoneyRewardStore("QuestMoneyReward.db2", QuestMoneyRewardLoadInfo::Instance());
DB2Storage<QuestPackageItemEntry> sQuestPackageItemStore("QuestPackageItem.db2", QuestPackageItemLoadInfo::Instance());
@@ -320,7 +320,6 @@ typedef std::unordered_map<uint32, std::array<std::vector<NameGenEntry const*>,
typedef std::array<std::vector<Trinity::wregex>, TOTAL_LOCALES + 1> NameValidationRegexContainer;
typedef std::unordered_map<uint32, std::vector<uint32>> PhaseGroupContainer;
typedef std::array<PowerTypeEntry const*, MAX_POWERS> PowerTypesContainer;
-typedef std::vector<PvpTalentEntry const*> PvpTalentsByPosition[MAX_CLASSES][MAX_PVP_TALENT_TIERS][MAX_PVP_TALENT_COLUMNS];
typedef std::unordered_map<uint32, std::pair<std::vector<QuestPackageItemEntry const*>, std::vector<QuestPackageItemEntry const*>>> QuestPackageItemContainer;
typedef std::unordered_map<uint32, uint32> RulesetItemUpgradeContainer;
typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRaceClassInfoContainer;
@@ -377,9 +376,7 @@ namespace
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];
+ PvpTalentSlotUnlockEntry const* _pvpTalentSlotUnlock[MAX_PVP_TALENT_SLOTS];
QuestPackageItemContainer _questPackages;
std::unordered_map<uint32, std::vector<RewardPackXCurrencyTypeEntry const*>> _rewardPackCurrencyTypes;
std::unordered_map<uint32, std::vector<RewardPackXItemEntry const*>> _rewardPackItems;
@@ -632,9 +629,10 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sPrestigeLevelInfoStore);
LOAD_DB2(sPVPDifficultyStore);
LOAD_DB2(sPVPItemStore);
- LOAD_DB2(sPvpRewardStore);
+ //LOAD_DB2(sPvpRewardStore);
LOAD_DB2(sPvpTalentStore);
- LOAD_DB2(sPvpTalentUnlockStore);
+ LOAD_DB2(sPvpTalentCategoryStore);
+ LOAD_DB2(sPvpTalentSlotUnlockStore);
LOAD_DB2(sQuestFactionRewardStore);
LOAD_DB2(sQuestMoneyRewardStore);
LOAD_DB2(sQuestPackageItemStore);
@@ -976,28 +974,17 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
for (PVPItemEntry const* pvpItem : sPVPItemStore)
_pvpItemBonus[pvpItem->ItemID] = pvpItem->ItemLevelDelta;
- for (PvpRewardEntry const* pvpReward : sPvpRewardStore)
- _pvpRewardPack[std::make_pair(pvpReward->PrestigeLevel, pvpReward->HonorLevel)] = pvpReward->RewardPackID;
-
- for (PvpTalentEntry const* talentInfo : sPvpTalentStore)
+ for (PvpTalentSlotUnlockEntry const* talentUnlock : sPvpTalentSlotUnlockStore)
{
- ASSERT(talentInfo->ClassID < MAX_CLASSES);
- ASSERT(talentInfo->TierID < MAX_PVP_TALENT_TIERS, "MAX_PVP_TALENT_TIERS must be at least %u", talentInfo->TierID + 1);
- ASSERT(talentInfo->ColumnIndex < MAX_PVP_TALENT_COLUMNS, "MAX_PVP_TALENT_COLUMNS must be at least %u", talentInfo->ColumnIndex + 1);
- if (!talentInfo->ClassID)
+ ASSERT(talentUnlock->Slot < (1 << MAX_PVP_TALENT_SLOTS));
+ for (int8 i = 0; i < MAX_PVP_TALENT_SLOTS; ++i)
{
- for (uint32 i = 1; i < MAX_CLASSES; ++i)
- _pvpTalentsByPosition[i][talentInfo->TierID][talentInfo->ColumnIndex].push_back(talentInfo);
+ if (talentUnlock->Slot & (1 << i))
+ {
+ ASSERT(!_pvpTalentSlotUnlock[i]);
+ _pvpTalentSlotUnlock[i] = talentUnlock;
+ }
}
- else
- _pvpTalentsByPosition[talentInfo->ClassID][talentInfo->TierID][talentInfo->ColumnIndex].push_back(talentInfo);
- }
-
- for (PvpTalentUnlockEntry const* talentUnlock : sPvpTalentUnlockStore)
- {
- ASSERT(talentUnlock->TierID < MAX_PVP_TALENT_TIERS, "MAX_PVP_TALENT_TIERS must be at least %u", talentUnlock->TierID + 1);
- ASSERT(talentUnlock->ColumnIndex < MAX_PVP_TALENT_COLUMNS, "MAX_PVP_TALENT_COLUMNS must be at least %u", talentUnlock->ColumnIndex + 1);
- _pvpTalentUnlock[talentUnlock->TierID][talentUnlock->ColumnIndex] = talentUnlock->HonorLevel;
}
for (QuestPackageItemEntry const* questPackageItem : sQuestPackageItemStore)
@@ -2000,16 +1987,6 @@ ResponseCodes DB2Manager::ValidateName(std::wstring const& name, LocaleConstant
return CHAR_NAME_SUCCESS;
}
-uint8 DB2Manager::GetMaxPrestige() const
-{
- uint8 max = 0;
- for (PrestigeLevelInfoEntry const* prestigeLevelInfo : sPrestigeLevelInfoStore)
- if (!prestigeLevelInfo->IsDisabled())
- max = std::max(prestigeLevelInfo->PrestigeLevel, max);
-
- return max;
-}
-
PVPDifficultyEntry const* DB2Manager::GetBattlegroundBracketByLevel(uint32 mapid, uint32 level)
{
PVPDifficultyEntry const* maxEntry = nullptr; // used for level > max listed level case
@@ -2040,27 +2017,24 @@ PVPDifficultyEntry const* DB2Manager::GetBattlegroundBracketById(uint32 mapid, B
return nullptr;
}
-uint32 DB2Manager::GetRewardPackIDForPvpRewardByHonorLevelAndPrestige(uint8 honorLevel, uint8 prestige) const
-{
- auto itr = _pvpRewardPack.find({ prestige, honorLevel });
- if (itr == _pvpRewardPack.end())
- itr = _pvpRewardPack.find({ 0, honorLevel });
-
- if (itr == _pvpRewardPack.end())
- return 0;
-
- return itr->second;
-}
-
-uint32 DB2Manager::GetRequiredHonorLevelForPvpTalent(PvpTalentEntry const* talentInfo) const
+uint32 DB2Manager::GetRequiredLevelForPvpTalentSlot(uint8 slot, Classes class_) const
{
- ASSERT(talentInfo);
- return _pvpTalentUnlock[talentInfo->TierID][talentInfo->ColumnIndex];
-}
+ ASSERT(slot < MAX_PVP_TALENT_SLOTS);
+ if (_pvpTalentSlotUnlock[slot])
+ {
+ switch (class_)
+ {
+ case CLASS_DEATH_KNIGHT:
+ return _pvpTalentSlotUnlock[slot]->DeathKnightLevelRequired;
+ case CLASS_DEMON_HUNTER:
+ return _pvpTalentSlotUnlock[slot]->DemonHunterLevelRequired;
+ default:
+ break;
+ }
+ return _pvpTalentSlotUnlock[slot]->LevelRequired;
+ }
-std::vector<PvpTalentEntry const*> const& DB2Manager::GetPvpTalentsByPosition(uint32 class_, uint32 tier, uint32 column) const
-{
- return _pvpTalentsByPosition[class_][tier][column];
+ return 0;
}
std::vector<QuestPackageItemEntry const*> const* DB2Manager::GetQuestPackageItems(uint32 questPackageID) const
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index 68a10fbd4d3..2517433b58b 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -149,7 +149,8 @@ TC_GAME_API extern DB2Storage<PhaseEntry> sPhaseStore;
TC_GAME_API extern DB2Storage<PlayerConditionEntry> sPlayerConditionStore;
TC_GAME_API extern DB2Storage<PowerDisplayEntry> sPowerDisplayStore;
TC_GAME_API extern DB2Storage<PvpTalentEntry> sPvpTalentStore;
-TC_GAME_API extern DB2Storage<PvpTalentUnlockEntry> sPvpTalentUnlockStore;
+TC_GAME_API extern DB2Storage<PvpTalentCategoryEntry> sPvpTalentCategoryStore;
+TC_GAME_API extern DB2Storage<PvpTalentSlotUnlockEntry> sPvpTalentSlotUnlockStore;
TC_GAME_API extern DB2Storage<QuestFactionRewardEntry> sQuestFactionRewardStore;
TC_GAME_API extern DB2Storage<QuestMoneyRewardEntry> sQuestMoneyRewardStore;
TC_GAME_API extern DB2Storage<QuestSortEntry> sQuestSortStore;
@@ -311,12 +312,9 @@ public:
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);
- uint32 GetRewardPackIDForPvpRewardByHonorLevelAndPrestige(uint8 honorLevel, uint8 prestige) const;
- uint32 GetRequiredHonorLevelForPvpTalent(PvpTalentEntry const* talentInfo) const;
- std::vector<PvpTalentEntry const*> const& GetPvpTalentsByPosition(uint32 class_, uint32 tier, uint32 column) const;
+ uint32 GetRequiredLevelForPvpTalentSlot(uint8 slot, Classes class_) const;
std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItems(uint32 questPackageID) const;
std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItemsFallback(uint32 questPackageID) const;
uint32 GetQuestUniqueBitFlag(uint32 questId);
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index 574087b8900..f6f31f26d2c 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -2220,6 +2220,21 @@ struct PvpTalentEntry
int32 LevelRequired;
};
+struct PvpTalentCategoryEntry
+{
+ uint32 ID;
+ uint8 TalentSlotMask;
+};
+
+struct PvpTalentSlotUnlockEntry
+{
+ uint32 ID;
+ int8 Slot;
+ int32 LevelRequired;
+ int32 DeathKnightLevelRequired;
+ int32 DemonHunterLevelRequired;
+};
+
struct QuestFactionRewardEntry
{
uint32 ID;
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index fe7913f26b0..65ab692ceaf 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -1003,8 +1003,7 @@ enum SummonPropFlags
#define MAX_TALENT_TIERS 7
#define MAX_TALENT_COLUMNS 3
-#define MAX_PVP_TALENT_TIERS 6
-#define MAX_PVP_TALENT_COLUMNS 3
+#define MAX_PVP_TALENT_SLOTS 4
enum TaxiNodeFlags
{
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index f956d970992..2371a9b8a82 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -3565,9 +3565,6 @@ void Player::ResetPvpTalents()
if (!talentInfo)
continue;
- if (talentInfo->ClassID && talentInfo->ClassID != getClass())
- continue;
-
RemovePvpTalent(talentInfo);
}
@@ -6496,24 +6493,11 @@ void Player::SetHonorLevel(uint8 level)
if (level == oldHonorLevel)
return;
- uint32 rewardPackID = sDB2Manager.GetRewardPackIDForPvpRewardByHonorLevelAndPrestige(level, prestige);
- RewardPlayerWithRewardPack(rewardPackID);
-
SetUInt32Value(PLAYER_FIELD_HONOR_LEVEL, level);
UpdateHonorNextLevel();
UpdateCriteria(CRITERIA_TYPE_HONOR_LEVEL_REACHED);
- // This code is here because no link was found between those items and this reward condition in the db2 files.
- // Interesting CriteriaTree found: Tree ids: 51140, 51156 (criteria id 31773, modifier tree id 37759)
- if (level == 50 && prestige == 1)
- {
- if (GetTeam() == ALLIANCE)
- AddItem(138992, 1);
- else
- AddItem(138996, 1);
- }
-
if (CanPrestige())
Prestige();
}
@@ -6529,15 +6513,12 @@ void Player::Prestige()
bool Player::CanPrestige() const
{
- if (GetSession()->GetExpansion() >= EXPANSION_LEGION && getLevel() >= PLAYER_LEVEL_MIN_HONOR && GetHonorLevel() >= PLAYER_MAX_HONOR_LEVEL && GetPrestigeLevel() < sDB2Manager.GetMaxPrestige())
- return true;
-
return false;
}
bool Player::IsMaxPrestige() const
{
- return GetPrestigeLevel() == sDB2Manager.GetMaxPrestige();
+ return true;
}
void Player::UpdateHonorNextLevel()
@@ -26238,62 +26219,59 @@ void Player::ResetTalentSpecialization()
UpdateItemSetAuras(false);
}
-TalentLearnResult Player::LearnPvpTalent(uint32 talentID, int32* spellOnCooldown)
+TalentLearnResult Player::LearnPvpTalent(uint32 talentID, uint8 slot, int32* spellOnCooldown)
{
+ if (slot >= MAX_PVP_TALENT_SLOTS)
+ return TALENT_FAILED_UNKNOWN;
+
if (IsInCombat())
return TALENT_FAILED_AFFECTING_COMBAT;
- if (getLevel() < PLAYER_LEVEL_MIN_HONOR)
- return TALENT_FAILED_UNKNOWN;
+ if (isDead())
+ return TALENT_FAILED_CANT_DO_THAT_RIGHT_NOW;
PvpTalentEntry const* talentInfo = sPvpTalentStore.LookupEntry(talentID);
if (!talentInfo)
return TALENT_FAILED_UNKNOWN;
- if (talentInfo->SpecID)
- {
- if (talentInfo->SpecID != GetInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID))
- return TALENT_FAILED_UNKNOWN;
- }
- else if (talentInfo->Role >= 0)
- {
- if (talentInfo->Role != sChrSpecializationStore.AssertEntry(GetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID))->Role)
- return TALENT_FAILED_UNKNOWN;
- }
+ if (talentInfo->SpecID != GetInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID))
+ return TALENT_FAILED_UNKNOWN;
- // prevent learn talent for different class (cheating)
- if (talentInfo->ClassID && talentInfo->ClassID != getClass())
+ if (talentInfo->LevelRequired > getLevel())
+ return TALENT_FAILED_UNKNOWN;
+
+ if (sDB2Manager.GetRequiredLevelForPvpTalentSlot(slot, Classes(getClass())) > getLevel())
return TALENT_FAILED_UNKNOWN;
- if (!GetPrestigeLevel())
- if (sDB2Manager.GetRequiredHonorLevelForPvpTalent(talentInfo) > GetHonorLevel())
+ if (PvpTalentCategoryEntry const* talentCategory = sPvpTalentCategoryStore.LookupEntry(talentInfo->PvpTalentCategoryID))
+ if (!(talentCategory->TalentSlotMask & (1 << slot)))
return TALENT_FAILED_UNKNOWN;
- // Check if player doesn't have any talent in current tier
- for (uint32 c = 0; c < MAX_PVP_TALENT_COLUMNS; ++c)
- {
- for (PvpTalentEntry const* talent : sDB2Manager.GetPvpTalentsByPosition(getClass(), talentInfo->TierID, c))
- {
- if (HasPvpTalent(talent->ID, GetActiveTalentGroup()) && !HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC))
- return TALENT_FAILED_REST_AREA;
+ // Check if player doesn't have this talent in other slot
+ if (HasPvpTalent(talentID, GetActiveTalentGroup()))
+ return TALENT_FAILED_UNKNOWN;
- if (GetSpellHistory()->HasCooldown(talent->SpellID))
- {
- *spellOnCooldown = talent->SpellID;
- return TALENT_FAILED_CANT_REMOVE_TALENT;
- }
+ if (PvpTalentEntry const* talent = sPvpTalentStore.LookupEntry(GetPvpTalentMap(GetActiveTalentGroup())[slot]))
+ {
+ if (!HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) && !HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHANGING_TALENTS))
+ return TALENT_FAILED_REST_AREA;
- RemovePvpTalent(talent);
+ if (GetSpellHistory()->HasCooldown(talent->SpellID))
+ {
+ *spellOnCooldown = talent->SpellID;
+ return TALENT_FAILED_CANT_REMOVE_TALENT;
}
+
+ RemovePvpTalent(talent);
}
- if (!AddPvpTalent(talentInfo, GetActiveTalentGroup(), true))
+ if (!AddPvpTalent(talentInfo, GetActiveTalentGroup(), slot))
return TALENT_FAILED_UNKNOWN;
return TALENT_LEARN_OK;
}
-bool Player::AddPvpTalent(PvpTalentEntry const* talent, uint8 activeTalentGroup, bool learning)
+bool Player::AddPvpTalent(PvpTalentEntry const* talent, uint8 activeTalentGroup, uint8 slot)
{
ASSERT(talent);
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID);
@@ -26316,11 +26294,7 @@ bool Player::AddPvpTalent(PvpTalentEntry const* talent, uint8 activeTalentGroup,
if (talent->OverridesSpellID)
AddOverrideSpell(talent->OverridesSpellID, talent->SpellID);
- PlayerTalentMap::iterator itr = GetPvpTalentMap(activeTalentGroup)->find(talent->ID);
- if (itr != GetPvpTalentMap(activeTalentGroup)->end())
- itr->second = PLAYERSPELL_UNCHANGED;
- else
- (*GetPvpTalentMap(activeTalentGroup))[talent->ID] = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
+ GetPvpTalentMap(activeTalentGroup)[slot] = talent->ID;
return true;
}
@@ -26338,28 +26312,29 @@ void Player::RemovePvpTalent(PvpTalentEntry const* talent)
RemoveOverrideSpell(talent->OverridesSpellID, talent->SpellID);
// if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted
- PlayerTalentMap::iterator plrPvpTalent = GetPvpTalentMap(GetActiveTalentGroup())->find(talent->ID);
- if (plrPvpTalent != GetPvpTalentMap(GetActiveTalentGroup())->end())
- plrPvpTalent->second = PLAYERSPELL_REMOVED;
+ auto plrPvpTalent = std::find(GetPvpTalentMap(GetActiveTalentGroup()).begin(), GetPvpTalentMap(GetActiveTalentGroup()).end(), talent->ID);
+ if (plrPvpTalent != GetPvpTalentMap(GetActiveTalentGroup()).end())
+ *plrPvpTalent = 0;
}
void Player::TogglePvpTalents(bool enable)
{
- PlayerTalentMap const* pvpTalents = GetPvpTalentMap(GetActiveTalentGroup());
- for (PlayerTalentMap::value_type const& v : *pvpTalents)
+ PlayerPvpTalentMap const& pvpTalents = GetPvpTalentMap(GetActiveTalentGroup());
+ for (uint32 pvpTalentId : pvpTalents)
{
- PvpTalentEntry const* pvpTalentInfo = sPvpTalentStore.AssertEntry(v.first);
- if (enable && v.second != PLAYERSPELL_REMOVED)
- LearnSpell(pvpTalentInfo->SpellID, false);
- else
- RemoveSpell(pvpTalentInfo->SpellID, true);
+ if (PvpTalentEntry const* pvpTalentInfo = sPvpTalentStore.LookupEntry(pvpTalentId))
+ {
+ if (enable)
+ LearnSpell(pvpTalentInfo->SpellID, false);
+ else
+ RemoveSpell(pvpTalentInfo->SpellID, true);
+ }
}
}
bool Player::HasPvpTalent(uint32 talentID, uint8 activeTalentGroup) const
{
- PlayerTalentMap::const_iterator itr = GetPvpTalentMap(activeTalentGroup)->find(talentID);
- return (itr != GetPvpTalentMap(activeTalentGroup)->end() && itr->second != PLAYERSPELL_REMOVED);
+ return std::find(GetPvpTalentMap(activeTalentGroup).begin(), GetPvpTalentMap(activeTalentGroup).end(), talentID) != GetPvpTalentMap(activeTalentGroup).end();
}
void Player::EnablePvpRules(bool dueToCombat /*= false*/)
@@ -26517,12 +26492,11 @@ void Player::SendTalentsInfoData()
continue;
PlayerTalentMap* talents = GetTalentMap(i);
- PlayerTalentMap* pvpTalents = GetPvpTalentMap(i);
+ PlayerPvpTalentMap const& pvpTalents = GetPvpTalentMap(i);
WorldPackets::Talent::TalentGroupInfo groupInfoPkt;
groupInfoPkt.SpecID = spec->ID;
groupInfoPkt.TalentIDs.reserve(talents->size());
- groupInfoPkt.PvPTalentIDs.reserve(pvpTalents->size());
for (PlayerTalentMap::const_iterator itr = talents->begin(); itr != talents->end(); ++itr)
{
@@ -26537,9 +26511,6 @@ void Player::SendTalentsInfoData()
continue;
}
- if (talentInfo->ClassID != getClass())
- continue;
-
SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
if (!spellEntry)
{
@@ -26551,22 +26522,19 @@ void Player::SendTalentsInfoData()
groupInfoPkt.TalentIDs.push_back(uint16(itr->first));
}
- for (PlayerTalentMap::const_iterator itr = pvpTalents->begin(); itr != pvpTalents->end(); ++itr)
+ for (std::size_t slot = 0; slot < MAX_PVP_TALENT_SLOTS; ++slot)
{
- if (itr->second == PLAYERSPELL_REMOVED)
+ if (!pvpTalents[slot])
continue;
- PvpTalentEntry const* talentInfo = sPvpTalentStore.LookupEntry(itr->first);
+ PvpTalentEntry const* talentInfo = sPvpTalentStore.LookupEntry(pvpTalents[slot]);
if (!talentInfo)
{
TC_LOG_ERROR("entities.player", "Player::SendTalentsInfoData: Player '%s' (%s) has unknown pvp talent id: %u",
- GetName().c_str(), GetGUID().ToString().c_str(), itr->first);
+ GetName().c_str(), GetGUID().ToString().c_str(), pvpTalents[slot]);
continue;
}
- if (talentInfo->ClassID && talentInfo->ClassID != getClass())
- continue;
-
SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
if (!spellEntry)
{
@@ -26575,7 +26543,7 @@ void Player::SendTalentsInfoData()
continue;
}
- groupInfoPkt.PvPTalentIDs.push_back(uint16(itr->first));
+ groupInfoPkt.PvPTalentIDs.push_back(uint16(pvpTalents[slot]));
}
packet.Info.TalentGroups.push_back(groupInfoPkt);
@@ -26854,12 +26822,13 @@ void Player::_LoadTalents(PreparedQueryResult result)
void Player::_LoadPvpTalents(PreparedQueryResult result)
{
- // "SELECT TalentID, TalentGroup FROM character_pvp_talent WHERE guid = ?"
+ // "SELECT talentID0, talentID1, talentID2, talentID3, talentGroup FROM character_pvp_talent WHERE guid = ?"
if (result)
{
do
- if (PvpTalentEntry const* talent = sPvpTalentStore.LookupEntry((*result)[0].GetUInt32()))
- AddPvpTalent(talent, (*result)[1].GetUInt8(), false);
+ for (uint8 slot = 0; slot < MAX_PVP_TALENT_SLOTS; ++slot)
+ if (PvpTalentEntry const* talent = sPvpTalentStore.LookupEntry((*result)[slot].GetUInt32()))
+ AddPvpTalent(talent, (*result)[4].GetUInt8(), slot);
while (result->NextRow());
}
}
@@ -26870,11 +26839,10 @@ void Player::_SaveTalents(SQLTransaction& trans)
stmt->setUInt64(0, GetGUID().GetCounter());
trans->Append(stmt);
- PlayerTalentMap* talents;
for (uint8 group = 0; group < MAX_SPECIALIZATIONS; ++group)
{
- talents = GetTalentMap(group);
- for (PlayerTalentMap::iterator itr = talents->begin(); itr != talents->end();)
+ PlayerTalentMap* talents = GetTalentMap(group);
+ for (auto itr = talents->begin(); itr != talents->end();)
{
if (itr->second == PLAYERSPELL_REMOVED)
{
@@ -26897,22 +26865,15 @@ void Player::_SaveTalents(SQLTransaction& trans)
for (uint8 group = 0; group < MAX_SPECIALIZATIONS; ++group)
{
- talents = GetPvpTalentMap(group);
- for (PlayerTalentMap::iterator itr = talents->begin(); itr != talents->end();)
- {
- if (itr->second == PLAYERSPELL_REMOVED)
- {
- itr = talents->erase(itr);
- continue;
- }
-
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_PVP_TALENT);
- stmt->setUInt64(0, GetGUID().GetCounter());
- stmt->setUInt32(1, itr->first);
- stmt->setUInt8(2, group);
- trans->Append(stmt);
- ++itr;
- }
+ PlayerPvpTalentMap const& talents = GetPvpTalentMap(group);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_PVP_TALENT);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ stmt->setUInt32(1, talents[0]);
+ stmt->setUInt32(2, talents[1]);
+ stmt->setUInt32(3, talents[2]);
+ stmt->setUInt32(4, talents[3]);
+ stmt->setUInt8(5, group);
+ trans->Append(stmt);
}
}
@@ -26996,15 +26957,6 @@ void Player::ActivateTalentGroup(ChrSpecializationEntry const* spec)
if (!talentInfo)
continue;
- // unlearn only talents for character class
- // some spell learned by one class as normal spells or know at creation but another class learn it as talent,
- // to prevent unexpected lost normal learned spell skip another class talents
- if (talentInfo->ClassID && talentInfo->ClassID != getClass())
- continue;
-
- if (talentInfo->SpellID == 0)
- continue;
-
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
if (!spellInfo)
continue;
@@ -27053,21 +27005,16 @@ void Player::ActivateTalentGroup(ChrSpecializationEntry const* spec)
}
}
- for (uint32 pvpTalentID = 0; pvpTalentID < sTalentStore.GetNumRows(); ++pvpTalentID)
+ for (uint8 slot = 0; slot < MAX_PVP_TALENT_SLOTS; ++slot)
{
- PvpTalentEntry const* talentInfo = sPvpTalentStore.LookupEntry(pvpTalentID);
+ PvpTalentEntry const* talentInfo = sPvpTalentStore.LookupEntry(GetPvpTalentMap(GetActiveTalentGroup())[slot]);
if (!talentInfo)
continue;
- // learn only talents for character class (or x-class talents)
- if (talentInfo->ClassID && talentInfo->ClassID != getClass())
- continue;
-
if (!talentInfo->SpellID)
continue;
- if (HasPvpTalent(talentInfo->ID, GetActiveTalentGroup()))
- AddPvpTalent(talentInfo, GetActiveTalentGroup(), true);
+ AddPvpTalent(talentInfo, GetActiveTalentGroup(), slot);
}
LearnSpecializationSpells();
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index fd2b6e9a049..967d4fae3f4 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -240,6 +240,7 @@ struct PlayerCurrency
};
typedef std::unordered_map<uint32, PlayerSpellState> PlayerTalentMap;
+typedef std::array<uint32, MAX_PVP_TALENT_SLOTS> PlayerPvpTalentMap;
typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap;
typedef std::unordered_set<SpellModifier*> SpellModContainer;
typedef std::unordered_map<uint32, PlayerCurrency> PlayerCurrenciesMap;
@@ -1012,7 +1013,7 @@ struct TC_GAME_API SpecializationInfo
}
PlayerTalentMap Talents[MAX_SPECIALIZATIONS];
- PlayerTalentMap PvpTalents[MAX_SPECIALIZATIONS];
+ PlayerPvpTalentMap PvpTalents[MAX_SPECIALIZATIONS];
std::vector<uint32> Glyphs[MAX_SPECIALIZATIONS];
uint32 ResetTalentsCost;
time_t ResetTalentsTime;
@@ -1648,8 +1649,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
uint32 CalculateTalentsTiers() const;
void ResetTalentSpecialization();
- TalentLearnResult LearnPvpTalent(uint32 talentID, int32* spellOnCooldown);
- bool AddPvpTalent(PvpTalentEntry const* talent, uint8 activeTalentGroup, bool learning);
+ TalentLearnResult LearnPvpTalent(uint32 talentID, uint8 slot, int32* spellOnCooldown);
+ bool AddPvpTalent(PvpTalentEntry const* talent, uint8 activeTalentGroup, uint8 slot);
void RemovePvpTalent(PvpTalentEntry const* talent);
void TogglePvpTalents(bool enable);
bool HasPvpTalent(uint32 talentID, uint8 activeTalentGroup) const;
@@ -1664,8 +1665,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
PlayerTalentMap const* GetTalentMap(uint8 spec) const { return &_specializationInfo.Talents[spec]; }
PlayerTalentMap* GetTalentMap(uint8 spec) { return &_specializationInfo.Talents[spec]; }
- PlayerTalentMap const* GetPvpTalentMap(uint8 spec) const { return &_specializationInfo.PvpTalents[spec]; }
- PlayerTalentMap* GetPvpTalentMap(uint8 spec) { return &_specializationInfo.PvpTalents[spec]; }
+ PlayerPvpTalentMap const& GetPvpTalentMap(uint8 spec) const { return _specializationInfo.PvpTalents[spec]; }
+ PlayerPvpTalentMap& GetPvpTalentMap(uint8 spec) { return _specializationInfo.PvpTalents[spec]; }
std::vector<uint32> const& GetGlyphs(uint8 spec) const { return _specializationInfo.Glyphs[spec]; }
std::vector<uint32>& GetGlyphs(uint8 spec) { return _specializationInfo.Glyphs[spec]; }
ActionButtonList const& GetActionButtons() const { return m_actionButtons; }
diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp
index fc1741c6885..d7af3a34737 100644
--- a/src/server/game/Handlers/SkillHandler.cpp
+++ b/src/server/game/Handlers/SkillHandler.cpp
@@ -57,7 +57,7 @@ void WorldSession::HandleLearnPvpTalentsOpcode(WorldPackets::Talent::LearnPvpTal
bool anythingLearned = false;
for (uint32 talentId : packet.Talents)
{
- if (TalentLearnResult result = _player->LearnPvpTalent(talentId, &learnPvpTalentsFailed.SpellID))
+ if (TalentLearnResult result = _player->LearnPvpTalent(talentId, 0, &learnPvpTalentsFailed.SpellID))
{
if (!learnPvpTalentsFailed.Reason)
learnPvpTalentsFailed.Reason = result;
diff --git a/src/server/game/Server/Packets/TalentPackets.h b/src/server/game/Server/Packets/TalentPackets.h
index 920f724095e..27db9f99eb5 100644
--- a/src/server/game/Server/Packets/TalentPackets.h
+++ b/src/server/game/Server/Packets/TalentPackets.h
@@ -127,7 +127,7 @@ namespace WorldPackets
class LearnPvpTalentsFailed final : public ServerPacket
{
public:
- LearnPvpTalentsFailed() : ServerPacket(SMSG_LEARN_PVP_TALENTS_FAILED, 1 + 4 + 4 + 2 * MAX_PVP_TALENT_TIERS) { }
+ LearnPvpTalentsFailed() : ServerPacket(SMSG_LEARN_PVP_TALENTS_FAILED, 1 + 4 + 4 + (2 + 1) * MAX_PVP_TALENT_SLOTS) { }
WorldPacket const* Write() override;