diff options
author | Shauren <shauren.trinity@gmail.com> | 2018-09-18 23:37:45 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2018-09-26 19:01:31 +0200 |
commit | e0309d94c8502d57734998cac769c474f355f7a2 (patch) | |
tree | a6c162585dccc51156eebc6a665c761a74788d52 /src | |
parent | 573dd01c6c51c0898ac17bb3073a5a7e7db89193 (diff) |
Core/Players: Updated pvp talent implementation to bfa
Diffstat (limited to 'src')
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.cpp | 4 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.cpp | 86 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 8 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Structure.h | 15 | ||||
-rw-r--r-- | src/server/game/DataStores/DBCEnums.h | 3 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 189 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 11 | ||||
-rw-r--r-- | src/server/game/Handlers/SkillHandler.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Server/Packets/TalentPackets.h | 2 |
9 files changed, 127 insertions, 193 deletions
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; |