TrinityCore
TraitHandler.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "WorldSession.h"
19#include "Battleground.h"
20#include "DB2Stores.h"
21#include "Player.h"
22#include "SpellHistory.h"
23#include "TraitMgr.h"
24#include "TraitPackets.h"
25
27{
28 int32 configId = traitsCommitConfig.Config.ID;
29 UF::TraitConfig const* existingConfig = _player->GetTraitConfig(configId);
30 if (!existingConfig)
31 {
33 return;
34 }
35
36 if (_player->IsInCombat())
37 {
39 return;
40 }
41
43 {
45 return;
46 }
47
48 auto findEntry = [](WorldPackets::Traits::TraitConfig& config, int32 traitNodeId, int32 traitNodeEntryId) -> WorldPackets::Traits::TraitEntry*
49 {
50 auto entryItr = std::find_if(config.Entries.begin(), config.Entries.end(), [=](WorldPackets::Traits::TraitEntry const& traitEntry)
51 {
52 return traitEntry.TraitNodeID == traitNodeId && traitEntry.TraitNodeEntryID == traitNodeEntryId;
53 });
54 return entryItr != config.Entries.end() ? &*entryItr : nullptr;
55 };
56
57 bool hasRemovedEntries = false;
58 WorldPackets::Traits::TraitConfig newConfigState(*existingConfig);
59 for (WorldPackets::Traits::TraitEntry const& newEntry : traitsCommitConfig.Config.Entries)
60 {
61 WorldPackets::Traits::TraitEntry* traitEntry = findEntry(newConfigState, newEntry.TraitNodeID, newEntry.TraitNodeEntryID);
62 if (traitEntry && traitEntry->Rank > newEntry.Rank)
63 {
64 TraitNodeEntry const* traitNode = sTraitNodeStore.LookupEntry(newEntry.TraitNodeID);
65 if (!traitNode)
66 {
68 return;
69 }
70
71 TraitTreeEntry const* traitTree = sTraitTreeStore.LookupEntry(traitNode->TraitTreeID);
72 if (!traitTree)
73 {
75 return;
76 }
77
78 if (traitTree->GetFlags().HasFlag(TraitTreeFlag::CannotRefund))
79 {
81 return;
82 }
83
84 TraitNodeEntryEntry const* traitNodeEntry = sTraitNodeEntryStore.LookupEntry(newEntry.TraitNodeEntryID);
85 if (!traitNodeEntry)
86 {
88 return;
89 }
90
91 TraitDefinitionEntry const* traitDefinition = sTraitDefinitionStore.LookupEntry(traitNodeEntry->TraitDefinitionID);
92 if (!traitDefinition)
93 {
95 return;
96 }
97
98 if (traitDefinition->SpellID && _player->GetSpellHistory()->HasCooldown(traitDefinition->SpellID))
99 {
101 return;
102 }
103
104 if (traitDefinition->VisibleSpellID && _player->GetSpellHistory()->HasCooldown(traitDefinition->VisibleSpellID))
105 {
107 return;
108 }
109
110 hasRemovedEntries = true;
111 }
112
113 if (traitEntry)
114 {
115 if (newEntry.Rank)
116 traitEntry->Rank = newEntry.Rank;
117 else
118 newConfigState.Entries.erase(std::remove_if(newConfigState.Entries.begin(), newConfigState.Entries.end(), [&newEntry](WorldPackets::Traits::TraitEntry const& traitEntry)
119 {
120 return traitEntry.TraitNodeID == newEntry.TraitNodeID && traitEntry.TraitNodeEntryID == newEntry.TraitNodeEntryID;
121 }), newConfigState.Entries.end());
122 }
123 else
124 newConfigState.Entries.emplace_back() = newEntry;
125 }
126
127 TraitMgr::LearnResult validationResult = TraitMgr::ValidateConfig(newConfigState, _player, true);
128 if (validationResult != TraitMgr::LearnResult::Ok)
129 {
130 SendPacket(WorldPackets::Traits::TraitConfigCommitFailed(configId, 0, AsUnderlyingType(validationResult)).Write());
131 return;
132 }
133
134 bool needsCastTime = newConfigState.Type == TraitConfigType::Combat && hasRemovedEntries;
135
136 if (traitsCommitConfig.SavedLocalIdentifier)
137 newConfigState.LocalIdentifier = traitsCommitConfig.SavedLocalIdentifier;
138 else if (UF::TraitConfig const* savedConfig = _player->GetTraitConfig(traitsCommitConfig.SavedLocalIdentifier))
139 newConfigState.LocalIdentifier = savedConfig->LocalIdentifier;
140
141 _player->UpdateTraitConfig(std::move(newConfigState), traitsCommitConfig.SavedConfigID, needsCastTime);
142}
143
145{
146 if (classTalentsRequestNewConfig.Config.Type != TraitConfigType::Combat)
147 return;
148
150 return;
151
152 int64 configCount = std::count_if(_player->m_activePlayerData->TraitConfigs.begin(), _player->m_activePlayerData->TraitConfigs.end(), [](UF::TraitConfig const& traitConfig)
153 {
154 return static_cast<TraitConfigType>(*traitConfig.Type) == TraitConfigType::Combat
155 && (static_cast<TraitCombatConfigFlags>(*traitConfig.CombatConfigFlags) & TraitCombatConfigFlags::ActiveForSpec) == TraitCombatConfigFlags::None;
156 });
157 if (configCount >= TraitMgr::MAX_COMBAT_TRAIT_CONFIGS)
158 return;
159
160 auto findFreeLocalIdentifier = [&]()
161 {
162 int32 index = 1;
163 while (_player->m_activePlayerData->TraitConfigs.FindIndexIf([&](UF::TraitConfig const& traitConfig)
164 {
165 return static_cast<TraitConfigType>(*traitConfig.Type) == TraitConfigType::Combat
166 && traitConfig.ChrSpecializationID == int32(_player->GetPrimarySpecialization())
167 && traitConfig.LocalIdentifier == index;
168 }) >= 0)
169 ++index;
170
171 return index;
172 };
173
175 classTalentsRequestNewConfig.Config.LocalIdentifier = findFreeLocalIdentifier();
176
177 for (UF::TraitEntry const& grantedEntry : TraitMgr::GetGrantedTraitEntriesForConfig(classTalentsRequestNewConfig.Config, _player))
178 {
179 auto entryItr = std::find_if(classTalentsRequestNewConfig.Config.Entries.begin(), classTalentsRequestNewConfig.Config.Entries.end(),
180 [&](WorldPackets::Traits::TraitEntry const& entry) { return entry.TraitNodeID == grantedEntry.TraitNodeID && entry.TraitNodeEntryID == grantedEntry.TraitNodeEntryID; });
181
182 WorldPackets::Traits::TraitEntry& newEntry = entryItr != classTalentsRequestNewConfig.Config.Entries.end() ? *entryItr : classTalentsRequestNewConfig.Config.Entries.emplace_back();
183 newEntry.TraitNodeID = grantedEntry.TraitNodeID;
184 newEntry.TraitNodeEntryID = grantedEntry.TraitNodeEntryID;
185 newEntry.Rank = grantedEntry.Rank;
186 newEntry.GrantedRanks = grantedEntry.GrantedRanks;
187 if (TraitNodeEntryEntry const* traitNodeEntry = sTraitNodeEntryStore.LookupEntry(grantedEntry.TraitNodeEntryID))
188 if (newEntry.Rank + newEntry.GrantedRanks > traitNodeEntry->MaxRanks)
189 newEntry.Rank = std::max(0, traitNodeEntry->MaxRanks - newEntry.GrantedRanks);
190 }
191
192 TraitMgr::LearnResult validationResult = TraitMgr::ValidateConfig(classTalentsRequestNewConfig.Config, _player);
193 if (validationResult != TraitMgr::LearnResult::Ok)
194 return;
195
196 _player->CreateTraitConfig(classTalentsRequestNewConfig.Config);
197}
198
200{
201 _player->RenameTraitConfig(classTalentsRenameConfig.ConfigID, classTalentsRenameConfig.Name.Move());
202}
203
205{
206 _player->DeleteTraitConfig(classTalentsDeleteConfig.ConfigID);
207}
208
210{
211 UF::TraitConfig const* traitConfig = _player->GetTraitConfig(classTalentsSetStarterBuildActive.ConfigID);
212 if (!traitConfig)
213 return;
214
215 if (static_cast<TraitConfigType>(*traitConfig->Type) != TraitConfigType::Combat)
216 return;
217
219 return;
220
221 if (classTalentsSetStarterBuildActive.Active)
222 {
223 WorldPackets::Traits::TraitConfig newConfigState(*traitConfig);
224
225 auto findFreeLocalIdentifier = [&]()
226 {
227 int32 index = 1;
228 while (_player->m_activePlayerData->TraitConfigs.FindIndexIf([&](UF::TraitConfig const& traitConfig)
229 {
230 return static_cast<TraitConfigType>(*traitConfig.Type) == TraitConfigType::Combat
231 && traitConfig.ChrSpecializationID == int32(_player->GetPrimarySpecialization())
232 && traitConfig.LocalIdentifier == index;
233 }) >= 0)
234 ++index;
235
236 return index;
237 };
238
241 newConfigState.LocalIdentifier = findFreeLocalIdentifier();
242
243 _player->UpdateTraitConfig(std::move(newConfigState), 0, true);
244 }
245 else
246 _player->SetTraitConfigUseStarterBuild(classTalentsSetStarterBuildActive.ConfigID, false);
247}
248
250{
251 _player->SetTraitConfigUseSharedActionBars(classTalentsSetUsesSharedActionBars.ConfigID, classTalentsSetUsesSharedActionBars.UsesShared,
252 classTalentsSetUsesSharedActionBars.IsLastSelectedSavedConfig);
253}
@ STATUS_IN_PROGRESS
Definition: Battleground.h:167
DB2Storage< TraitNodeEntry > sTraitNodeStore("TraitNode.db2", &TraitNodeLoadInfo::Instance)
DB2Storage< TraitTreeEntry > sTraitTreeStore("TraitTree.db2", &TraitTreeLoadInfo::Instance)
DB2Storage< TraitNodeEntryEntry > sTraitNodeEntryStore("TraitNodeEntry.db2", &TraitNodeEntryLoadInfo::Instance)
DB2Storage< TraitDefinitionEntry > sTraitDefinitionStore("TraitDefinition.db2", &TraitDefinitionLoadInfo::Instance)
TraitConfigType
Definition: DBCEnums.h:2185
TraitCombatConfigFlags
Definition: DBCEnums.h:2157
int64_t int64
Definition: Define.h:137
int32_t int32
Definition: Define.h:138
@ TALENT_FAILED_UNKNOWN
Definition: Player.h:1062
@ TALENT_FAILED_AFFECTING_COMBAT
Definition: Player.h:1066
@ TALENT_FAILED_CANT_REMOVE_TALENT
Definition: Player.h:1067
@ TALENT_FAILED_IN_PVP_MATCH
Definition: Player.h:1071
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:491
BattlegroundStatus GetStatus() const
Definition: Battleground.h:284
constexpr bool HasFlag(T flag) const
Definition: EnumFlag.h:106
ChrSpecialization GetPrimarySpecialization() const
Definition: Player.h:1841
void SetTraitConfigUseStarterBuild(int32 traitConfigId, bool useStarterBuild)
Definition: Player.cpp:28484
void SetTraitConfigUseSharedActionBars(int32 traitConfigId, bool usesSharedActionBars, bool isLastSelectedSavedConfig)
Definition: Player.cpp:28511
UF::TraitConfig const * GetTraitConfig(int32 configId) const
Definition: Player.cpp:28247
void DeleteTraitConfig(int32 deletedConfigId)
Definition: Player.cpp:28438
void UpdateTraitConfig(WorldPackets::Traits::TraitConfig &&newConfig, int32 savedConfigId, bool withCastTime)
Definition: Player.cpp:28256
Battleground * GetBattleground() const
Definition: Player.cpp:24976
UF::UpdateField< UF::ActivePlayerData, 0, TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition: Player.h:2864
void CreateTraitConfig(WorldPackets::Traits::TraitConfig &traitConfig)
Definition: Player.cpp:28195
void RenameTraitConfig(int32 editedConfigId, std::string &&newName)
Definition: Player.cpp:28420
bool HasCooldown(SpellInfo const *spellInfo, uint32 itemId=0) const
SpellHistory * GetSpellHistory()
Definition: Unit.h:1457
bool IsInCombat() const
Definition: Unit.h:1043
std::string && Move()
WorldPacket const * Write() override
void HandleClassTalentsSetUsesSharedActionBars(WorldPackets::Traits::ClassTalentsSetUsesSharedActionBars const &classTalentsSetUsesSharedActionBars)
void HandleClassTalentsSetStarterBuildActive(WorldPackets::Traits::ClassTalentsSetStarterBuildActive const &classTalentsSetStarterBuildActive)
void HandleClassTalentsRequestNewConfig(WorldPackets::Traits::ClassTalentsRequestNewConfig &classTalentsRequestNewConfig)
void HandleClassTalentsDeleteConfig(WorldPackets::Traits::ClassTalentsDeleteConfig const &classTalentsDeleteConfig)
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
Player * _player
void HandleClassTalentsRenameConfig(WorldPackets::Traits::ClassTalentsRenameConfig &classTalentsRenameConfig)
void HandleTraitsCommitConfig(WorldPackets::Traits::TraitsCommitConfig const &traitsCommitConfig)
constexpr uint32 MAX_COMBAT_TRAIT_CONFIGS
Definition: TraitMgr.h:44
void InitializeStarterBuildTraitConfig(WorldPackets::Traits::TraitConfig &traitConfig, PlayerDataAccessor player)
Definition: TraitMgr.cpp:693
LearnResult ValidateConfig(WorldPackets::Traits::TraitConfig const &traitConfig, PlayerDataAccessor player, bool requireSpendingAllCurrencies)
Definition: TraitMgr.cpp:559
LearnResult
Definition: TraitMgr.h:47
std::vector< UF::TraitEntry > GetGrantedTraitEntriesForConfig(WorldPackets::Traits::TraitConfig const &traitConfig, PlayerDataAccessor player)
Definition: TraitMgr.cpp:492
EnumFlag< TraitTreeFlag > GetFlags() const
UpdateField< int32, 4, 5 > Type
Definition: UpdateFields.h:736
UpdateField< int32, 8, 9 > CombatConfigFlags
Definition: UpdateFields.h:739
TraitCombatConfigFlags CombatConfigFlags
std::vector< TraitEntry > Entries