TrinityCore
Loading...
Searching...
No Matches
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::ranges::find_if(config.Entries, [=](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 if (traitNodeEntry->TraitDefinitionID)
92 {
93 TraitDefinitionEntry const* traitDefinition = sTraitDefinitionStore.LookupEntry(traitNodeEntry->TraitDefinitionID);
94 if (!traitDefinition)
95 {
97 return;
98 }
99
100 if (traitDefinition->SpellID && _player->GetSpellHistory()->HasCooldown(traitDefinition->SpellID))
101 {
103 return;
104 }
105
106 if (traitDefinition->VisibleSpellID && _player->GetSpellHistory()->HasCooldown(traitDefinition->VisibleSpellID))
107 {
109 return;
110 }
111 }
112
113 hasRemovedEntries = true;
114 }
115
116 if (traitEntry)
117 {
118 if (newEntry.Rank)
119 traitEntry->Rank = newEntry.Rank;
120 else
121 std::erase_if(newConfigState.Entries, [&newEntry](WorldPackets::Traits::TraitEntry const& traitEntry)
122 {
123 return traitEntry.TraitNodeID == newEntry.TraitNodeID && traitEntry.TraitNodeEntryID == newEntry.TraitNodeEntryID;
124 });
125 }
126 else
127 newConfigState.Entries.emplace_back() = newEntry;
128 }
129
130 TraitMgr::LearnResult validationResult = TraitMgr::ValidateConfig(newConfigState, _player, true);
131 if (validationResult != TraitMgr::LearnResult::Ok)
132 {
133 SendPacket(WorldPackets::Traits::TraitConfigCommitFailed(configId, 0, AsUnderlyingType(validationResult)).Write());
134 return;
135 }
136
137 bool needsCastTime = newConfigState.Type == TraitConfigType::Combat && hasRemovedEntries;
138
139 if (traitsCommitConfig.SavedLocalIdentifier)
140 newConfigState.LocalIdentifier = traitsCommitConfig.SavedLocalIdentifier;
141 else if (UF::TraitConfig const* savedConfig = _player->GetTraitConfig(traitsCommitConfig.SavedLocalIdentifier))
142 newConfigState.LocalIdentifier = savedConfig->LocalIdentifier;
143
144 _player->UpdateTraitConfig(std::move(newConfigState), traitsCommitConfig.SavedConfigID, needsCastTime);
145}
146
148{
149 if (classTalentsRequestNewConfig.Config.Type != TraitConfigType::Combat)
150 return;
151
153 return;
154
155 int64 configCount = std::ranges::count_if(_player->m_activePlayerData->TraitConfigs, [](UF::TraitConfig const& traitConfig)
156 {
157 return static_cast<TraitConfigType>(*traitConfig.Type) == TraitConfigType::Combat
158 && (static_cast<TraitCombatConfigFlags>(*traitConfig.CombatConfigFlags) & TraitCombatConfigFlags::ActiveForSpec) == TraitCombatConfigFlags::None;
159 }, [](auto const& pair) -> UF::TraitConfig const& { return pair.second.value; });
160 if (configCount >= TraitMgr::MAX_COMBAT_TRAIT_CONFIGS)
161 return;
162
163 auto findFreeLocalIdentifier = [&]()
164 {
165 int32 index = 1;
166 while (_player->m_activePlayerData->TraitConfigs.FindIf([&](UF::TraitConfig const& traitConfig)
167 {
168 return static_cast<TraitConfigType>(*traitConfig.Type) == TraitConfigType::Combat
169 && traitConfig.ChrSpecializationID == int32(_player->GetPrimarySpecialization())
170 && traitConfig.LocalIdentifier == index;
171 }).first)
172 ++index;
173
174 return index;
175 };
176
178 classTalentsRequestNewConfig.Config.LocalIdentifier = findFreeLocalIdentifier();
179
180 for (UF::TraitEntry const& grantedEntry : TraitMgr::GetGrantedTraitEntriesForConfig(classTalentsRequestNewConfig.Config, _player))
181 {
182 auto entryItr = std::ranges::find_if(classTalentsRequestNewConfig.Config.Entries,
183 [&](WorldPackets::Traits::TraitEntry const& entry) { return entry.TraitNodeID == grantedEntry.TraitNodeID && entry.TraitNodeEntryID == grantedEntry.TraitNodeEntryID; });
184
185 WorldPackets::Traits::TraitEntry& newEntry = entryItr != classTalentsRequestNewConfig.Config.Entries.end() ? *entryItr : classTalentsRequestNewConfig.Config.Entries.emplace_back();
186 newEntry.TraitNodeID = grantedEntry.TraitNodeID;
187 newEntry.TraitNodeEntryID = grantedEntry.TraitNodeEntryID;
188 newEntry.Rank = grantedEntry.Rank;
189 newEntry.GrantedRanks = grantedEntry.GrantedRanks;
190 if (TraitNodeEntryEntry const* traitNodeEntry = sTraitNodeEntryStore.LookupEntry(grantedEntry.TraitNodeEntryID))
191 if (newEntry.Rank + newEntry.GrantedRanks > traitNodeEntry->MaxRanks)
192 newEntry.Rank = std::max(0, traitNodeEntry->MaxRanks - newEntry.GrantedRanks);
193 }
194
195 TraitMgr::LearnResult validationResult = TraitMgr::ValidateConfig(classTalentsRequestNewConfig.Config, _player);
196 if (validationResult != TraitMgr::LearnResult::Ok)
197 return;
198
199 _player->CreateTraitConfig(classTalentsRequestNewConfig.Config);
200}
201
203{
204 _player->RenameTraitConfig(classTalentsRenameConfig.ConfigID, std::move(classTalentsRenameConfig.Name));
205}
206
208{
209 _player->DeleteTraitConfig(classTalentsDeleteConfig.ConfigID);
210}
211
213{
214 UF::TraitConfig const* traitConfig = _player->GetTraitConfig(classTalentsSetStarterBuildActive.ConfigID);
215 if (!traitConfig)
216 return;
217
218 if (static_cast<TraitConfigType>(*traitConfig->Type) != TraitConfigType::Combat)
219 return;
220
222 return;
223
224 if (classTalentsSetStarterBuildActive.Active)
225 {
226 WorldPackets::Traits::TraitConfig newConfigState(*traitConfig);
227
228 auto findFreeLocalIdentifier = [&]()
229 {
230 int32 index = 1;
231 while (_player->m_activePlayerData->TraitConfigs.FindIf([&](UF::TraitConfig const& traitConfig)
232 {
233 return static_cast<TraitConfigType>(*traitConfig.Type) == TraitConfigType::Combat
234 && traitConfig.ChrSpecializationID == int32(_player->GetPrimarySpecialization())
235 && traitConfig.LocalIdentifier == index;
236 }).first)
237 ++index;
238
239 return index;
240 };
241
244 newConfigState.LocalIdentifier = findFreeLocalIdentifier();
245
246 _player->UpdateTraitConfig(std::move(newConfigState), 0, true);
247 }
248 else
249 _player->SetTraitConfigUseStarterBuild(classTalentsSetStarterBuildActive.ConfigID, false);
250}
251
253{
254 _player->SetTraitConfigUseSharedActionBars(classTalentsSetUsesSharedActionBars.ConfigID, classTalentsSetUsesSharedActionBars.UsesShared,
255 classTalentsSetUsesSharedActionBars.IsLastSelectedSavedConfig);
256}
@ STATUS_IN_PROGRESS
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:2851
TraitCombatConfigFlags
Definition DBCEnums.h:2821
int64_t int64
Definition Define.h:149
int32_t int32
Definition Define.h:150
@ TALENT_FAILED_UNKNOWN
Definition Player.h:1176
@ TALENT_FAILED_AFFECTING_COMBAT
Definition Player.h:1180
@ TALENT_FAILED_CANT_REMOVE_TALENT
Definition Player.h:1181
@ TALENT_FAILED_IN_PVP_MATCH
Definition Player.h:1185
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
BattlegroundStatus GetStatus() const
constexpr bool HasFlag(T flag) const
Definition EnumFlag.h:106
ChrSpecialization GetPrimarySpecialization() const
Definition Player.h:2008
void SetTraitConfigUseStarterBuild(int32 traitConfigId, bool useStarterBuild)
Definition Player.cpp:29466
void SetTraitConfigUseSharedActionBars(int32 traitConfigId, bool usesSharedActionBars, bool isLastSelectedSavedConfig)
Definition Player.cpp:29490
UF::UpdateField< UF::ActivePlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition Player.h:3062
UF::TraitConfig const * GetTraitConfig(int32 configId) const
Definition Player.cpp:29192
void DeleteTraitConfig(int32 deletedConfigId)
Definition Player.cpp:29420
void UpdateTraitConfig(WorldPackets::Traits::TraitConfig &&newConfig, int32 savedConfigId, bool withCastTime)
Definition Player.cpp:29197
Battleground * GetBattleground() const
Definition Player.cpp:25719
void CreateTraitConfig(WorldPackets::Traits::TraitConfig &traitConfig)
Definition Player.cpp:29124
void RenameTraitConfig(int32 editedConfigId, std::string &&newName)
Definition Player.cpp:29405
bool HasCooldown(SpellInfo const *spellInfo, uint32 itemId=0) const
SpellHistory * GetSpellHistory()
Definition Unit.h:1498
bool IsInCombat() const
Definition Unit.h:1058
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:46
void InitializeStarterBuildTraitConfig(WorldPackets::Traits::TraitConfig &traitConfig, PlayerDataAccessor player)
LearnResult ValidateConfig(WorldPackets::Traits::TraitConfig &traitConfig, PlayerDataAccessor player, bool requireSpendingAllCurrencies, bool removeInvalidEntries)
Definition TraitMgr.cpp:838
std::vector< UF::TraitEntry > GetGrantedTraitEntriesForConfig(WorldPackets::Traits::TraitConfig const &traitConfig, PlayerDataAccessor player)
Definition TraitMgr.cpp:766
EnumFlag< TraitTreeFlag > GetFlags() const
UpdateField< int32, 4, 6 > Type
UpdateField< int32, 8, 10 > CombatConfigFlags
TraitCombatConfigFlags CombatConfigFlags
std::vector< TraitEntry > Entries