TrinityCore
cs_learn.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/* ScriptData
19Name: learn_commandscript
20%Complete: 100
21Comment: All learn related commands
22Category: commandscripts
23EndScriptData */
24
25#include "ScriptMgr.h"
26#include "Chat.h"
27#include "ChatCommand.h"
28#include "DB2Stores.h"
29#include "Language.h"
30#include "LanguageMgr.h"
31#include "ObjectMgr.h"
32#include "Player.h"
33#include "RBAC.h"
34#include "SpellInfo.h"
35#include "SpellMgr.h"
36#include "WorldSession.h"
37
38using namespace Trinity::ChatCommands;
40{
41public:
42 learn_commandscript() : CommandScript("learn_commandscript") { }
43
45 {
46 static ChatCommandTable learnAllCommandTable =
47 {
56 };
57
58 static ChatCommandTable learnMyCommandTable =
59 {
62 };
63
64 static ChatCommandTable learnCommandTable =
65 {
67 { "all", learnAllCommandTable },
68 { "my", learnMyCommandTable }
69 };
70
71 static ChatCommandTable commandTable =
72 {
73 { "learn", learnCommandTable },
75 };
76 return commandTable;
77 }
78
79 static bool HandleLearnCommand(ChatHandler* handler, SpellInfo const* spell, Optional<EXACT_SEQUENCE("all")> allRanks)
80 {
81 Player* targetPlayer = handler->getSelectedPlayerOrSelf();
82
83 if (!targetPlayer)
84 {
86 handler->SetSentErrorMessage(true);
87 return false;
88 }
89
90 if (!SpellMgr::IsSpellValid(spell, handler->GetSession()->GetPlayer()))
91 {
93 handler->SetSentErrorMessage(true);
94 return false;
95 }
96
97 if (!allRanks && targetPlayer->HasSpell(spell->Id))
98 {
99 if (targetPlayer == handler->GetPlayer())
101 else
102 handler->PSendSysMessage(LANG_TARGET_KNOWN_SPELL, handler->GetNameLink(targetPlayer).c_str());
103 handler->SetSentErrorMessage(true);
104 return false;
105 }
106
107 targetPlayer->LearnSpell(spell->Id, false);
108 if (allRanks)
109 {
110 uint32 spellId = spell->Id;
111 while ((spellId = sSpellMgr->GetNextSpellInChain(spellId)))
112 targetPlayer->LearnSpell(spellId, false);
113 }
114
115 return true;
116 }
117
119 {
120 for (std::pair<uint32 const, SkillLineAbilityEntry const*> skillSpell : Trinity::Containers::MakeIteratorPair(sSpellMgr->GetSkillLineAbilityMapBounds(SKILL_INTERNAL)))
121 {
122 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(skillSpell.second->Spell, DIFFICULTY_NONE);
123 if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo, handler->GetSession()->GetPlayer(), false))
124 continue;
125
126 handler->GetSession()->GetPlayer()->LearnSpell(skillSpell.second->Spell, false);
127 }
128
130 return true;
131 }
132
134 {
135 Player* player = handler->GetPlayer();
136 for (auto const& [id, quest] : sObjectMgr->GetQuestTemplates())
137 {
138 if (quest->GetAllowableClasses() && player->SatisfyQuestClass(quest.get(), false))
139 player->LearnQuestRewardedSpells(quest.get());
140 }
141 return true;
142 }
143
145 {
146 ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(handler->GetPlayer()->GetClass());
147 if (!classEntry)
148 return true;
149 uint32 family = classEntry->SpellClassSet;
150
151 for (uint32 i = 0; i < sSkillLineAbilityStore.GetNumRows(); ++i)
152 {
153 SkillLineAbilityEntry const* entry = sSkillLineAbilityStore.LookupEntry(i);
154 if (!entry)
155 continue;
156
157 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(entry->Spell, DIFFICULTY_NONE);
158 if (!spellInfo)
159 continue;
160
161 // skip server-side/triggered spells
162 if (spellInfo->SpellLevel == 0)
163 continue;
164
165 // skip wrong class/race skills
166 if (!handler->GetSession()->GetPlayer()->IsSpellFitByClassAndRace(spellInfo->Id))
167 continue;
168
169 // skip other spell families
170 if (spellInfo->SpellFamilyName != family)
171 continue;
172
173 // skip broken spells
174 if (!SpellMgr::IsSpellValid(spellInfo, handler->GetSession()->GetPlayer(), false))
175 continue;
176
177 handler->GetSession()->GetPlayer()->LearnSpell(spellInfo->Id, false);
178 }
179
181 return true;
182 }
183
185 {
186 Player* player = handler->GetSession()->GetPlayer();
187 uint32 playerClass = player->GetClass();
188
189 for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
190 {
191 TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);
192 if (!talentInfo)
193 continue;
194
195 if (playerClass != talentInfo->ClassID)
196 continue;
197
198 if (talentInfo->SpecID && player->GetPrimarySpecialization() != ChrSpecialization(talentInfo->SpecID))
199 continue;
200
201 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID, DIFFICULTY_NONE);
202 if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo, handler->GetSession()->GetPlayer(), false))
203 continue;
204
205 player->AddTalent(talentInfo, player->GetActiveTalentGroup(), true);
206 player->LearnSpell(talentInfo->SpellID, false);
207 }
208
209 player->SendTalentsInfoData();
210
212 return true;
213 }
214
216 {
217 /* TODO: 6.x remove pet talents
218 Player* player = handler->GetSession()->GetPlayer();
219
220 Pet* pet = player->GetPet();
221 if (!pet)
222 {
223 handler->SendSysMessage(LANG_NO_PET_FOUND);
224 handler->SetSentErrorMessage(true);
225 return false;
226 }
227
228 CreatureTemplate const* creatureInfo = pet->GetCreatureTemplate();
229 if (!creatureInfo)
230 {
231 handler->SendSysMessage(LANG_WRONG_PET_TYPE);
232 handler->SetSentErrorMessage(true);
233 return false;
234 }
235
236 CreatureFamilyEntry const* petFamily = sCreatureFamilyStore.LookupEntry(creatureInfo->family);
237 if (!petFamily)
238 {
239 handler->SendSysMessage(LANG_WRONG_PET_TYPE);
240 handler->SetSentErrorMessage(true);
241 return false;
242 }
243
244 if (petFamily->PetTalentType < 0) // not hunter pet
245 {
246 handler->SendSysMessage(LANG_WRONG_PET_TYPE);
247 handler->SetSentErrorMessage(true);
248 return false;
249 }
250
251 for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
252 {
253 TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);
254 if (!talentInfo)
255 continue;
256
257 TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TabID);
258 if (!talentTabInfo)
259 continue;
260
261 // prevent learn talent for different family (cheating)
262 if (((1 << petFamily->PetTalentType) & talentTabInfo->PetTalentMask) == 0)
263 continue;
264
265 // search highest talent rank
266 uint32 spellId = 0;
267
268 for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank)
269 {
270 if (talentInfo->SpellRank[rank] != 0)
271 {
272 spellId = talentInfo->SpellRank[rank];
273 break;
274 }
275 }
276
277 if (!spellId) // ??? none spells in talent
278 continue;
279
280 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
281 if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo, handler->GetSession()->GetPlayer(), false))
282 continue;
283
284 // learn highest rank of talent and learn all non-talent spell ranks (recursive by tree)
285 pet->learnSpellHighRank(spellId);
286 }
287
288 pet->SetFreeTalentPoints(0);
289
290 handler->SendSysMessage(LANG_COMMAND_LEARN_PET_TALENTS);*/
291 return true;
292 }
293
295 {
296 sLanguageMgr->ForEachLanguage([handler](uint32 /*lang*/, LanguageDesc const& languageDesc)
297 {
298 if (languageDesc.SpellId)
299 handler->GetSession()->GetPlayer()->LearnSpell(languageDesc.SpellId, false);
300
301 return true;
302 });
303
305 return true;
306 }
307
309 {
310 Player* const player = handler->GetPlayer();
311 player->LearnSpell(63364, false); /* 63364 - Saronite Barrier (reduces damage taken by 99%) */
312 player->LearnSpell(1908, false); /* 1908 - Uber Heal Over Time (heals target to full constantly) */
313 player->LearnSpell(27680, false); /* 27680 - Berserk (+500% damage, +150% speed, 10m duration) */
314 player->LearnSpell(62555, false); /* 62555 - Berserk (+500% damage, +150% melee haste, 10m duration) */
315 player->LearnSpell(64238, false); /* 64238 - Berserk (+900% damage, +150% melee haste, 30m duration) */
316 player->LearnSpell(72525, false); /* 72525 - Berserk (+240% damage, +160% haste, infinite duration) */
317 player->LearnSpell(66776, false); /* 66776 - Rage (+300% damage, -95% damage taken, +100% speed, infinite duration) */
318 return true;
319 }
320
322 {
323 if (!player)
324 player = PlayerIdentifier::FromTargetOrSelf(handler);
325 if (!player || !player->IsConnected())
326 return false;
327
328 Player* target = player->GetConnectedPlayer();
329 target->LearnDefaultSkills();
330 target->LearnCustomSpells();
331 target->LearnQuestRewardedSpells();
332
333 handler->PSendSysMessage(LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST, handler->GetNameLink(target).c_str());
334 return true;
335 }
336
338 {
339 if (!player)
340 player = PlayerIdentifier::FromTargetOrSelf(handler);
341 if (!player || !player->IsConnected())
342 return false;
343
344 Player* target = player->GetConnectedPlayer();
345 for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i)
346 {
347 SkillLineEntry const* skillInfo = sSkillLineStore.LookupEntry(i);
348 if (!skillInfo)
349 continue;
350
351 if ((skillInfo->CategoryID == SKILL_CATEGORY_PROFESSION || skillInfo->CategoryID == SKILL_CATEGORY_SECONDARY) &&
352 skillInfo->CanLink) // only prof. with recipes have
353 {
355 }
356 }
357
359 return true;
360 }
361
362 static bool HandleLearnAllRecipesCommand(ChatHandler* handler, WTail namePart)
363 {
364 // Learns all recipes of specified profession and sets skill to max
365 // Example: .learn all_recipes enchanting
366
367 Player* target = handler->getSelectedPlayer();
368 if (!target)
369 {
371 return false;
372 }
373
374 if (namePart.empty())
375 return false;
376
377 // converting string that we try to find to lower case
378 wstrToLower(namePart);
379
380 uint32 skillId = 0;
381 char const* name = nullptr;
382 for (uint32 i = 1; i < sSkillLineStore.GetNumRows(); ++i)
383 {
384 SkillLineEntry const* skillInfo = sSkillLineStore.LookupEntry(i);
385 if (!skillInfo)
386 continue;
387
388 if ((skillInfo->CategoryID != SKILL_CATEGORY_PROFESSION &&
389 skillInfo->CategoryID != SKILL_CATEGORY_SECONDARY) ||
390 !skillInfo->CanLink) // only prof with recipes have set
391 continue;
392
394 for (; locale < TOTAL_LOCALES; locale = LocaleConstant(locale + 1))
395 {
396 name = skillInfo->DisplayName[locale];
397 if (!name || !*name)
398 continue;
399
400 if (Utf8FitTo(name, namePart))
401 break;
402 }
403
404 if (locale < TOTAL_LOCALES)
405 {
406 skillId = i;
407 break;
408 }
409 }
410
411 if (!(name && skillId))
412 return false;
413
414 HandleLearnSkillRecipesHelper(target, skillId);
415
416 uint16 maxLevel = target->GetPureMaxSkillValue(skillId);
417 target->SetSkill(skillId, target->GetSkillStep(skillId), maxLevel, maxLevel);
419 return true;
420 }
421
422 static void HandleLearnSkillRecipesHelper(Player* player, uint32 skillId)
423 {
424 uint32 classmask = player->GetClassMask();
425
426 std::vector<SkillLineAbilityEntry const*> const* skillLineAbilities = sDB2Manager.GetSkillLineAbilitiesBySkill(skillId);
427 if (!skillLineAbilities)
428 return;
429
430 for (SkillLineAbilityEntry const* skillLine : *skillLineAbilities)
431 {
432 // not high rank
433 if (skillLine->SupercedesSpell)
434 continue;
435
436 // skip racial skills
437 if (!skillLine->RaceMask.IsEmpty())
438 continue;
439
440 // skip wrong class skills
441 if (skillLine->ClassMask && (skillLine->ClassMask & classmask) == 0)
442 continue;
443
444 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(skillLine->Spell, DIFFICULTY_NONE);
445 if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo, player, false))
446 continue;
447
448 player->LearnSpell(skillLine->Spell, false);
449 }
450 }
451
452 static bool HandleUnLearnCommand(ChatHandler* handler, SpellInfo const* spell, Optional<EXACT_SEQUENCE("all")> allRanks)
453 {
454 Player* target = handler->getSelectedPlayer();
455
456 if (!target)
457 {
459 handler->SetSentErrorMessage(true);
460 return false;
461 }
462
463 uint32 spellId = spell->Id;
464 if (allRanks)
465 spellId = sSpellMgr->GetFirstSpellInChain(spellId);
466
467 if (target->HasSpell(spellId))
468 target->RemoveSpell(spellId, false, !allRanks);
469 else
471
472 return true;
473 }
474};
475
477{
479}
#define EXACT_SEQUENCE(str)
LocaleConstant
Definition: Common.h:48
@ TOTAL_LOCALES
Definition: Common.h:62
@ LOCALE_enUS
Definition: Common.h:49
DB2Storage< SkillLineEntry > sSkillLineStore("SkillLine.db2", &SkillLineLoadInfo::Instance)
DB2Storage< ChrClassesEntry > sChrClassesStore("ChrClasses.db2", &ChrClassesLoadInfo::Instance)
DB2Storage< SkillLineAbilityEntry > sSkillLineAbilityStore("SkillLineAbility.db2", &SkillLineAbilityLoadInfo::Instance)
DB2Storage< TalentEntry > sTalentStore("Talent.db2", &TalentLoadInfo::Instance)
#define sDB2Manager
Definition: DB2Stores.h:538
@ DIFFICULTY_NONE
Definition: DBCEnums.h:874
ChrSpecialization
Definition: DBCEnums.h:357
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
#define sLanguageMgr
Definition: LanguageMgr.h:97
@ LANG_COMMAND_LEARN_ALL_RECIPES
Definition: Language.h:679
@ LANG_YOU_KNOWN_SPELL
Definition: Language.h:555
@ LANG_COMMAND_LEARN_ALL_DEBUG_HELP
Definition: Language.h:444
@ LANG_FORGET_SPELL
Definition: Language.h:558
@ LANG_COMMAND_LEARN_ALL_PETTALENT_HELP
Definition: Language.h:450
@ LANG_COMMAND_LEARN_ALL_CRAFT
Definition: Language.h:493
@ LANG_LEARNING_GM_SKILLS
Definition: Language.h:554
@ LANG_COMMAND_LEARN_ALL_LANGUAGES_HELP
Definition: Language.h:447
@ LANG_COMMAND_LEARN_MY_TRAINER_HELP
Definition: Language.h:442
@ LANG_COMMAND_LEARN_CLASS_TALENTS
Definition: Language.h:491
@ LANG_COMMAND_LEARN_ALL_BLIZZARD_HELP
Definition: Language.h:443
@ LANG_COMMAND_LEARN_CLASS_SPELLS
Definition: Language.h:490
@ LANG_COMMAND_LEARN_ALL_LANG
Definition: Language.h:492
@ LANG_COMMAND_LEARN_ALL_CRAFTS_HELP
Definition: Language.h:445
@ LANG_COMMAND_LEARN_ALL_DEFAULT_HELP
Definition: Language.h:446
@ LANG_COMMAND_LEARN_ALL_RECIPES_HELP
Definition: Language.h:448
@ LANG_COMMAND_UNLEARN_HELP
Definition: Language.h:440
@ LANG_NO_CHAR_SELECTED
Definition: Language.h:150
@ LANG_PLAYER_NOT_FOUND
Definition: Language.h:567
@ LANG_COMMAND_LEARN_ALL_TALENTS_HELP
Definition: Language.h:449
@ LANG_COMMAND_SPELL_BROKEN
Definition: Language.h:548
@ LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST
Definition: Language.h:664
@ LANG_COMMAND_LEARN_MY_QUESTS_HELP
Definition: Language.h:441
@ LANG_TARGET_KNOWN_SPELL
Definition: Language.h:556
@ LANG_COMMAND_LEARN_HELP
Definition: Language.h:439
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
Role Based Access Control related classes definition.
@ SKILL_CATEGORY_SECONDARY
@ SKILL_CATEGORY_PROFESSION
@ SKILL_INTERNAL
#define sSpellMgr
Definition: SpellMgr.h:849
void wstrToLower(std::wstring &str)
Definition: Util.cpp:480
bool Utf8FitTo(std::string_view str, std::wstring_view search)
Definition: Util.cpp:750
Player * getSelectedPlayerOrSelf()
Definition: Chat.cpp:244
Player * getSelectedPlayer()
Definition: Chat.cpp:200
WorldSession * GetSession()
Definition: Chat.h:42
virtual std::string GetNameLink() const
Definition: Chat.cpp:58
void PSendSysMessage(const char *fmt, Args &&... args)
Definition: Chat.h:57
void SetSentErrorMessage(bool val)
Definition: Chat.h:114
Player * GetPlayer() const
Definition: Chat.cpp:39
virtual void SendSysMessage(std::string_view str, bool escapeCharacters=false)
Definition: Chat.cpp:113
void LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill=0, bool suppressMessaging=false, Optional< int32 > traitDefinitionId={})
Definition: Player.cpp:3216
ChrSpecialization GetPrimarySpecialization() const
Definition: Player.h:1841
void LearnQuestRewardedSpells()
Definition: Player.cpp:24681
void LearnCustomSpells()
Definition: Player.cpp:24542
void SendTalentsInfoData()
Definition: Player.cpp:27287
bool IsSpellFitByClassAndRace(uint32 spell_id) const
Definition: Player.cpp:25155
void SetSkill(uint32 id, uint16 step, uint16 newVal, uint16 maxVal)
Definition: Player.cpp:5786
uint16 GetPureMaxSkillValue(uint32 skill) const
Definition: Player.cpp:6082
bool SatisfyQuestClass(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15736
bool AddTalent(TalentEntry const *talent, uint8 spec, bool learning)
Definition: Player.cpp:2688
uint16 GetSkillStep(uint32 skill) const
Definition: Player.cpp:6040
uint8 GetActiveTalentGroup() const
Definition: Player.h:1843
void RemoveSpell(uint32 spell_id, bool disabled=false, bool learn_low_rank=true, bool suppressMessaging=false)
Definition: Player.cpp:3260
bool HasSpell(uint32 spell) const override
Definition: Player.cpp:3792
void LearnDefaultSkills()
Definition: Player.cpp:24562
uint32 SpellLevel
Definition: SpellInfo.h:384
uint32 const Id
Definition: SpellInfo.h:325
uint32 SpellFamilyName
Definition: SpellInfo.h:408
static bool IsSpellValid(SpellInfo const *spellInfo, Player *player=nullptr, bool msg=true)
Some checks for spells, to prevent adding deprecated/broken spells for trainers, spell book,...
Definition: SpellMgr.cpp:142
uint8 GetClass() const
Definition: Unit.h:752
uint32 GetClassMask() const
Definition: Unit.h:754
Player * GetPlayer() const
static bool HandleLearnMySpellsCommand(ChatHandler *handler)
Definition: cs_learn.cpp:144
static bool HandleLearnDebugSpellsCommand(ChatHandler *handler)
Definition: cs_learn.cpp:308
static bool HandleUnLearnCommand(ChatHandler *handler, SpellInfo const *spell, Optional< EXACT_SEQUENCE("all")> allRanks)
Definition: cs_learn.cpp:452
static bool HandleLearnAllPetTalentsCommand(ChatHandler *)
Definition: cs_learn.cpp:215
static bool HandleLearnAllRecipesCommand(ChatHandler *handler, WTail namePart)
Definition: cs_learn.cpp:362
static bool HandleLearnAllTalentsCommand(ChatHandler *handler)
Definition: cs_learn.cpp:184
static bool HandleLearnMyQuestsCommand(ChatHandler *handler)
Definition: cs_learn.cpp:133
static bool HandleLearnAllCraftsCommand(ChatHandler *handler, Optional< PlayerIdentifier > player)
Definition: cs_learn.cpp:337
static bool HandleLearnAllGMCommand(ChatHandler *handler)
Definition: cs_learn.cpp:118
ChatCommandTable GetCommands() const override
Definition: cs_learn.cpp:44
static bool HandleLearnAllDefaultCommand(ChatHandler *handler, Optional< PlayerIdentifier > player)
Definition: cs_learn.cpp:321
static bool HandleLearnAllLangCommand(ChatHandler *handler)
Definition: cs_learn.cpp:294
static bool HandleLearnCommand(ChatHandler *handler, SpellInfo const *spell, Optional< EXACT_SEQUENCE("all")> allRanks)
Definition: cs_learn.cpp:79
static void HandleLearnSkillRecipesHelper(Player *player, uint32 skillId)
Definition: cs_learn.cpp:422
void AddSC_learn_commandscript()
Definition: cs_learn.cpp:476
std::vector< ChatCommandBuilder > ChatCommandTable
Definition: ChatCommand.h:49
constexpr IteratorPair< iterator, end_iterator > MakeIteratorPair(iterator first, end_iterator second)
Definition: IteratorPair.h:48
@ RBAC_PERM_COMMAND_UNLEARN
Definition: RBAC.h:301
@ RBAC_PERM_COMMAND_LEARN_ALL_LANG
Definition: RBAC.h:299
@ RBAC_PERM_COMMAND_LEARN_ALL_CRAFTS
Definition: RBAC.h:297
@ RBAC_PERM_COMMAND_LEARN_ALL_RECIPES
Definition: RBAC.h:300
@ RBAC_PERM_COMMAND_LEARN_ALL_TALENTS
Definition: RBAC.h:295
@ RBAC_PERM_COMMAND_LEARN
Definition: RBAC.h:289
@ RBAC_PERM_COMMAND_LEARN_ALL_MY_SPELLS
Definition: RBAC.h:294
@ RBAC_PERM_COMMAND_LEARN_ALL_GM
Definition: RBAC.h:296
@ RBAC_PERM_COMMAND_LEARN_ALL_DEFAULT
Definition: RBAC.h:298
@ RBAC_PERM_COMMAND_LEARN_MY_PETTALENTS
Definition: RBAC.h:293
uint32 SpellId
Definition: LanguageMgr.h:30
LocalizedString DisplayName
uint32 SpellID