Talents & Specialization API (Retail — Patch 12.0.0)
Comprehensive reference for class talents, hero talents, the traits system, and specialization APIs.
Source: https://warcraft.wiki.gg/wiki/World_of_Warcraft_API
Current as of: Patch 12.0.0 (Build 65655) — January 28, 2026
Scope: Retail only.
Scope
- C_ClassTalents — Talent loadouts, config management
- C_Traits — Trait system (nodes, entries, configs, currencies)
- C_SpecializationInfo — Specialization queries
- Global Spec Functions — GetSpecialization, SetSpecialization
- Profession Specialization — C_ProfessionSpecUI (cross-ref professions skill)
Architecture Overview
The talent system uses a layered architecture:
- Specialization — Top level: player picks a spec (e.g., Fire Mage)
- C_ClassTalents — Manages loadouts (saved talent builds) and provides high-level talent tree interaction
- C_Traits — Low-level trait system: nodes, entries, definitions, configs, currencies
- Hero Talents — Sub-trees within the talent system, selected as a package
C_ClassTalents — Talent Loadouts & Config
Loadout Management
| Function |
Returns |
Description |
C_ClassTalents.GetActiveConfigID() |
configID |
Active talent config |
C_ClassTalents.GetConfigIDsBySpecID(specID) |
configIDs |
Configs for spec |
C_ClassTalents.GetStarterBuildActive() |
isActive |
Using starter build? |
C_ClassTalents.GetHasStarterBuild() |
hasStarterBuild |
Starter build available? |
C_ClassTalents.SetStarterBuildActive(active) |
success |
Toggle starter build |
C_ClassTalents.GetTraitTreeForSpec(specID) |
treeID |
Trait tree for spec |
C_ClassTalents.GetHeroTalentSpecsForClassSpec(specID) |
heroSpecIDs |
Hero talent specs |
C_ClassTalents.CanCreateNewConfig() |
canCreate |
Can create new loadout? |
C_ClassTalents.RequestNewConfig(name) |
success |
Create new loadout |
C_ClassTalents.DeleteConfig(configID) |
success |
Delete loadout |
C_ClassTalents.RenameConfig(configID, name) |
success |
Rename loadout |
C_ClassTalents.UpdateLastSelectedSavedConfigID(specID, configID) |
— |
Set last selected config |
C_ClassTalents.GetLastSelectedSavedConfigID(specID) |
configID |
Last selected config |
Talent Import/Export
| Function |
Returns |
Description |
C_ClassTalents.ImportLoadout(importString) |
success, loadoutEntryInfo |
Import talent string |
C_ClassTalents.GetLoadoutExportString() |
exportString |
Export current build |
C_ClassTalents.ViewLoadout(loadoutInfo) |
— |
Preview a loadout |
Talent Commit
| Function |
Returns |
Description |
C_ClassTalents.CommitConfig(configID) |
success |
Apply talent config |
C_ClassTalents.CanChangeTalents() |
canChange, failureReason |
Can change talents? |
C_ClassTalents.HasUnspentTalentPoints() |
hasUnspent |
Has unspent points? |
C_ClassTalents.GetConfigBaseName(configID) |
baseName |
Config display name |
C_Traits — Core Trait System
Config Functions
| Function |
Returns |
Description |
C_Traits.GetConfigInfo(configID) |
configInfo |
Config details |
C_Traits.GetConfigsByType(configType) |
configIDs |
Configs by type |
C_Traits.HasValidInspectData() |
hasData |
Valid inspect data? |
Tree Functions
| Function |
Returns |
Description |
C_Traits.GetTreeInfo(configID, treeID) |
treeInfo |
Tree structure |
C_Traits.GetTreeNodes(treeID) |
nodeIDs |
All nodes in tree |
C_Traits.GetTreeCurrencyInfo(configID, treeID, traitCurrencyIndex) |
currencyInfo |
Tree currency info |
Node Functions
| Function |
Returns |
Description |
C_Traits.GetNodeInfo(configID, nodeID) |
nodeInfo |
Complete node data |
C_Traits.GetNodeCost(configID, nodeID) |
costs |
Node cost |
C_Traits.CanPurchaseRank(configID, nodeID) |
canPurchase |
Can buy next rank? |
C_Traits.CanRefundRank(configID, nodeID) |
canRefund |
Can refund rank? |
C_Traits.PurchaseRank(configID, nodeID) |
success |
Purchase rank |
C_Traits.RefundRank(configID, nodeID) |
success |
Refund rank |
C_Traits.SetSelection(configID, nodeID, entryID) |
success |
Select choice node |
C_Traits.GetNodePositionForTree(treeID, nodeID) |
posX, posY |
Node visual position |
Node Info Fields
The nodeInfo table from GetNodeInfo():
ID — Node ID
posX, posY — Position in tree
type — Node type (Single, Tiered, Selection, SubTreeSelection)
maxRanks — Maximum ranks
activeRank — Current active rank
currentRank — Current rank (may differ from active during editing)
entryIDs — Available entries (for choice nodes)
activeEntry — Currently active entry
currentEntry — Entry during editing
canPurchaseRank — Can purchase next rank
canRefundRank — Can refund a rank
isAvailable — Node unlocked
isCascadeRepurchasable — Can cascade repurchase
isVisible — Visible in UI
meetsEdgeRequirements — Edge requirements met
groupIDs — Associated groups
visibleEdges — Connected edges
conditionIDs — Conditions for availability
subTreeID — Sub-tree ID (hero talents)
Entry Functions
| Function |
Returns |
Description |
C_Traits.GetEntryInfo(configID, entryID) |
entryInfo |
Entry details |
C_Traits.GetDefinitionInfo(definitionID) |
definitionInfo |
Spell/ability for entry |
C_Traits.GetSubTreeInfo(configID, subTreeID) |
subTreeInfo |
Sub-tree (hero) details |
C_Traits.GetSubTreesForSpecID(specID) |
subTreeIDs |
Sub-trees for spec |
Entry Info Fields
definitionID — The talent definition
type — Entry type
maxRanks — Max ranks for this entry
isAvailable — Is this entry available
conditionIDs — Conditions
Definition Info Fields
spellID — Spell granted by this talent
overrideName — Override display name
overrideSubtext — Override subtext
overrideIcon — Override icon
Condition Functions
| Function |
Returns |
Description |
C_Traits.GetConditionInfo(configID, conditionID) |
conditionInfo |
Condition details |
Currency Functions
| Function |
Returns |
Description |
C_Traits.GetTraitCurrencyInfo(traitCurrencyID) |
currencyInfo |
Currency info |
Global Specialization Functions
| Function |
Returns |
Description |
GetSpecialization() |
specIndex |
Current spec index (1-4) |
GetSpecializationInfo(specIndex [, isInspect [, isPet [, inspectUnit [, sex]]]]) |
id, name, description, icon, role, primaryStat |
Spec details |
GetSpecializationInfoByID(specID) |
id, name, description, icon, role, primaryStat, ... |
Spec details by ID |
GetSpecializationInfoForClassID(classID, specIndex) |
id, name, description, icon, role, primaryStat |
Spec for class |
GetSpecializationInfoForSpecID(specID [, sex]) |
id, name, description, icon, role, primaryStat |
Spec by spec ID |
GetSpecializationRole(specIndex) |
role |
Spec's role type |
GetSpecializationRoleByID(specID) |
role |
Role by spec ID |
GetNumSpecializations([isInspect [, isPet]]) |
numSpecs |
Number of specs |
GetNumSpecializationsForClassID(classID) |
numSpecs |
Specs for class |
SetSpecialization(specIndex) |
— |
Switch spec |
GetActiveSpecGroup() |
specGroup |
Active spec group |
GetSpecializationMasterySpells(specIndex [, isInspect [, isPet]]) |
spellIDs |
Mastery spell(s) |
GetSpecializationSpells(specIndex [, isInspect [, isPet]]) |
... (spellID, level pairs) |
Spec spells |
C_SpecializationInfo
| Function |
Returns |
Description |
C_SpecializationInfo.CanPlayerUseTalentSpecUI() |
canUse, failureReason |
Can use talent UI? |
C_SpecializationInfo.GetAllSelectedPvpTalentIDs() |
talentIDs |
Selected PvP talents |
C_SpecializationInfo.GetInspectSelectedPvpTalent(inspectUnit, talentIndex) |
talentID |
Inspected PvP talent |
C_SpecializationInfo.GetPvpTalentAlertStatus() |
hasUnspent |
PvP talent alert? |
C_SpecializationInfo.GetPvpTalentSlotInfo(slotIndex) |
slotInfo |
PvP talent slot |
C_SpecializationInfo.GetPvpTalentSlotUnlockLevel(slotIndex) |
level |
PvP slot unlock level |
C_SpecializationInfo.GetPvpTalentUnlockLevel(talentID) |
level |
PvP talent unlock level |
C_SpecializationInfo.GetSpellsDisplay(specID) |
spellIDs |
Display spells for spec |
C_SpecializationInfo.IsInitialized() |
isInitialized |
Spec system ready? |
C_SpecializationInfo.MatchesCurrentSpecSet(setID) |
matches |
Equipment set matches spec? |
C_SpecializationInfo.SetPvpTalentLocked(talentID, locked) |
— |
Lock PvP talent |
Common Patterns
Get Active Spec Info
local specIndex = GetSpecialization()
if specIndex then
local specID, specName, specDesc, specIcon, specRole = GetSpecializationInfo(specIndex)
print("Current Spec:", specName, "Role:", specRole)
end
Iterate Talent Tree Nodes
local configID = C_ClassTalents.GetActiveConfigID()
if configID then
local specID = PlayerUtil.GetCurrentSpecID and PlayerUtil.GetCurrentSpecID()
or GetSpecializationInfo(GetSpecialization())
local treeID = C_ClassTalents.GetTraitTreeForSpec(specID)
if treeID then
local nodeIDs = C_Traits.GetTreeNodes(treeID)
for _, nodeID in ipairs(nodeIDs) do
local nodeInfo = C_Traits.GetNodeInfo(configID, nodeID)
if nodeInfo and nodeInfo.isVisible and nodeInfo.activeRank > 0 then
local entryInfo = C_Traits.GetEntryInfo(configID, nodeInfo.activeEntry.entryID)
if entryInfo then
local defInfo = C_Traits.GetDefinitionInfo(entryInfo.definitionID)
if defInfo then
local spellName = C_Spell.GetSpellName(defInfo.spellID)
print(spellName, "Rank:", nodeInfo.activeRank)
end
end
end
end
end
end
Export/Import Talent String
-- Export current talents
local exportString = C_ClassTalents.GetLoadoutExportString()
print("Talent string:", exportString)
-- Import talents (must be out of combat)
local success, loadoutInfo = C_ClassTalents.ImportLoadout(exportString)
if success then
C_ClassTalents.ViewLoadout(loadoutInfo)
end
Switch Specialization
local function SwitchSpec(specIndex)
if specIndex ~= GetSpecialization() then
if not InCombatLockdown() then
SetSpecialization(specIndex)
else
print("Cannot change spec in combat")
end
end
end
Key Events
| Event |
Payload |
Description |
PLAYER_SPECIALIZATION_CHANGED |
unit |
Specialization changed |
ACTIVE_COMBAT_CONFIG_CHANGED |
configID |
Active talent config changed |
TRAIT_CONFIG_CREATED |
configInfo |
New config created |
TRAIT_CONFIG_DELETED |
configID |
Config deleted |
TRAIT_CONFIG_UPDATED |
configID |
Config updated |
TRAIT_CONFIG_LIST_UPDATED |
— |
Config list changed |
TRAIT_NODE_CHANGED |
nodeID |
Trait node changed |
TRAIT_NODE_ENTRY_UPDATED |
nodeID |
Node entry updated |
TRAIT_TREE_CHANGED |
treeID |
Tree structure changed |
TRAIT_TREE_CURRENCY_INFO_UPDATED |
treeID |
Currency info changed |
SPECIALIZATION_CHANGE_CAST_FAILED |
— |
Spec change failed |
CONFIRM_TALENT_WIPE |
cost, respecType |
Confirm talent wipe |
STARTER_BUILD_ACTIVATION_FAILED |
— |
Starter build failed |
SELECTED_PVP_TALENTS_CHANGED |
— |
PvP talents changed |
PVP_TALENTS_UPDATE |
— |
PvP talents refreshed |
HERO_TALENT_SELECTION_CHANGED |
— |
Hero talent selection changed |
Gotchas & Restrictions
- configID is per-spec — Each specialization has its own set of configs. Active configID changes on spec switch.
- Cannot change talents in combat —
C_ClassTalents.CommitConfig() and SetSpecialization() fail in combat.
- Trait system is generic —
C_Traits is the underlying system used for class talents, hero talents, AND profession specializations. The configType differentiates them.
- Node types matter — Single nodes have one entry, Selection (choice) nodes have multiple entries you pick between.
- Hero talents are sub-trees — Hero talent selection is a SubTreeSelection node type. Use
C_Traits.GetSubTreeInfo().
- GetNodeInfo is expensive — Cache node info when iterating the full tree. Don't call in OnUpdate.
- Loadout export is opaque — The export string format is internal. Use the API functions, don't parse manually.
- specIndex vs specID —
GetSpecialization() returns an index (1-4), not a specID. Use GetSpecializationInfo() to get the specID.
1---2name: wow-api-talents3description: Complete reference for WoW Retail Class Talents, Hero Talents, Traits system, Specialization, and Profession Specialization APIs. Covers C_ClassTalents (loadouts, config management, talent tree interactions), C_Traits (the underlying trait system — nodes, entries, configs, currencies, conditions), C_SpecializationInfo (spec queries, recommended content), global specialization functions (GetSpecialization, GetSpecializationInfo, SetSpecialization), and profession specialization. Use when working with talent trees, talent loadouts, hero talent selection, trait nodes, specialization switching, or talent import/export.4---5
6# Talents & Specialization API (Retail — Patch 12.0.0)
7
8Comprehensive reference for class talents, hero talents, the traits system, and specialization APIs.
9
10> **Source:** https://warcraft.wiki.gg/wiki/World_of_Warcraft_API
11> **Current as of:** Patch 12.0.0 (Build 65655) — January 28, 2026
12> **Scope:** Retail only.
13
14---
15
16## Scope
17
18- **C_ClassTalents** — Talent loadouts, config management
19- **C_Traits** — Trait system (nodes, entries, configs, currencies)
20- **C_SpecializationInfo** — Specialization queries
21- **Global Spec Functions** — GetSpecialization, SetSpecialization
22- **Profession Specialization** — C_ProfessionSpecUI (cross-ref professions skill)
23
24---
25
26## Architecture Overview
27
28The talent system uses a layered architecture:
29
301. **Specialization** — Top level: player picks a spec (e.g., Fire Mage)
312. **C_ClassTalents** — Manages loadouts (saved talent builds) and provides high-level talent tree interaction
323. **C_Traits** — Low-level trait system: nodes, entries, definitions, configs, currencies
334. **Hero Talents** — Sub-trees within the talent system, selected as a package
34
35---
36
37## C_ClassTalents — Talent Loadouts & Config
38
39### Loadout Management
40
41| Function | Returns | Description |
42|----------|---------|-------------|
43| `C_ClassTalents.GetActiveConfigID()` | `configID` | Active talent config |
44| `C_ClassTalents.GetConfigIDsBySpecID(specID)` | `configIDs` | Configs for spec |
45| `C_ClassTalents.GetStarterBuildActive()` | `isActive` | Using starter build? |
46| `C_ClassTalents.GetHasStarterBuild()` | `hasStarterBuild` | Starter build available? |
47| `C_ClassTalents.SetStarterBuildActive(active)` | `success` | Toggle starter build |
48| `C_ClassTalents.GetTraitTreeForSpec(specID)` | `treeID` | Trait tree for spec |
49| `C_ClassTalents.GetHeroTalentSpecsForClassSpec(specID)` | `heroSpecIDs` | Hero talent specs |
50| `C_ClassTalents.CanCreateNewConfig()` | `canCreate` | Can create new loadout? |
51| `C_ClassTalents.RequestNewConfig(name)` | `success` | Create new loadout |
52| `C_ClassTalents.DeleteConfig(configID)` | `success` | Delete loadout |
53| `C_ClassTalents.RenameConfig(configID, name)` | `success` | Rename loadout |
54| `C_ClassTalents.UpdateLastSelectedSavedConfigID(specID, configID)` | — | Set last selected config |
55| `C_ClassTalents.GetLastSelectedSavedConfigID(specID)` | `configID` | Last selected config |
56
57### Talent Import/Export
58
59| Function | Returns | Description |
60|----------|---------|-------------|
61| `C_ClassTalents.ImportLoadout(importString)` | `success, loadoutEntryInfo` | Import talent string |
62| `C_ClassTalents.GetLoadoutExportString()` | `exportString` | Export current build |
63| `C_ClassTalents.ViewLoadout(loadoutInfo)` | — | Preview a loadout |
64
65### Talent Commit
66
67| Function | Returns | Description |
68|----------|---------|-------------|
69| `C_ClassTalents.CommitConfig(configID)` | `success` | Apply talent config |
70| `C_ClassTalents.CanChangeTalents()` | `canChange, failureReason` | Can change talents? |
71| `C_ClassTalents.HasUnspentTalentPoints()` | `hasUnspent` | Has unspent points? |
72| `C_ClassTalents.GetConfigBaseName(configID)` | `baseName` | Config display name |
73
74---
75
76## C_Traits — Core Trait System
77
78### Config Functions
79
80| Function | Returns | Description |
81|----------|---------|-------------|
82| `C_Traits.GetConfigInfo(configID)` | `configInfo` | Config details |
83| `C_Traits.GetConfigsByType(configType)` | `configIDs` | Configs by type |
84| `C_Traits.HasValidInspectData()` | `hasData` | Valid inspect data? |
85
86### Tree Functions
87
88| Function | Returns | Description |
89|----------|---------|-------------|
90| `C_Traits.GetTreeInfo(configID, treeID)` | `treeInfo` | Tree structure |
91| `C_Traits.GetTreeNodes(treeID)` | `nodeIDs` | All nodes in tree |
92| `C_Traits.GetTreeCurrencyInfo(configID, treeID, traitCurrencyIndex)` | `currencyInfo` | Tree currency info |
93
94### Node Functions
95
96| Function | Returns | Description |
97|----------|---------|-------------|
98| `C_Traits.GetNodeInfo(configID, nodeID)` | `nodeInfo` | Complete node data |
99| `C_Traits.GetNodeCost(configID, nodeID)` | `costs` | Node cost |
100| `C_Traits.CanPurchaseRank(configID, nodeID)` | `canPurchase` | Can buy next rank? |
101| `C_Traits.CanRefundRank(configID, nodeID)` | `canRefund` | Can refund rank? |
102| `C_Traits.PurchaseRank(configID, nodeID)` | `success` | Purchase rank |
103| `C_Traits.RefundRank(configID, nodeID)` | `success` | Refund rank |
104| `C_Traits.SetSelection(configID, nodeID, entryID)` | `success` | Select choice node |
105| `C_Traits.GetNodePositionForTree(treeID, nodeID)` | `posX, posY` | Node visual position |
106
107### Node Info Fields
108
109The `nodeInfo` table from `GetNodeInfo()`:
110
111- `ID` — Node ID
112- `posX`, `posY` — Position in tree
113- `type` — Node type (Single, Tiered, Selection, SubTreeSelection)
114- `maxRanks` — Maximum ranks
115- `activeRank` — Current active rank
116- `currentRank` — Current rank (may differ from active during editing)
117- `entryIDs` — Available entries (for choice nodes)
118- `activeEntry` — Currently active entry
119- `currentEntry` — Entry during editing
120- `canPurchaseRank` — Can purchase next rank
121- `canRefundRank` — Can refund a rank
122- `isAvailable` — Node unlocked
123- `isCascadeRepurchasable` — Can cascade repurchase
124- `isVisible` — Visible in UI
125- `meetsEdgeRequirements` — Edge requirements met
126- `groupIDs` — Associated groups
127- `visibleEdges` — Connected edges
128- `conditionIDs` — Conditions for availability
129- `subTreeID` — Sub-tree ID (hero talents)
130
131### Entry Functions
132
133| Function | Returns | Description |
134|----------|---------|-------------|
135| `C_Traits.GetEntryInfo(configID, entryID)` | `entryInfo` | Entry details |
136| `C_Traits.GetDefinitionInfo(definitionID)` | `definitionInfo` | Spell/ability for entry |
137| `C_Traits.GetSubTreeInfo(configID, subTreeID)` | `subTreeInfo` | Sub-tree (hero) details |
138| `C_Traits.GetSubTreesForSpecID(specID)` | `subTreeIDs` | Sub-trees for spec |
139
140### Entry Info Fields
141
142- `definitionID` — The talent definition
143- `type` — Entry type
144- `maxRanks` — Max ranks for this entry
145- `isAvailable` — Is this entry available
146- `conditionIDs` — Conditions
147
148### Definition Info Fields
149
150- `spellID` — Spell granted by this talent
151- `overrideName` — Override display name
152- `overrideSubtext` — Override subtext
153- `overrideIcon` — Override icon
154
155### Condition Functions
156
157| Function | Returns | Description |
158|----------|---------|-------------|
159| `C_Traits.GetConditionInfo(configID, conditionID)` | `conditionInfo` | Condition details |
160
161### Currency Functions
162
163| Function | Returns | Description |
164|----------|---------|-------------|
165| `C_Traits.GetTraitCurrencyInfo(traitCurrencyID)` | `currencyInfo` | Currency info |
166
167---
168
169## Global Specialization Functions
170
171| Function | Returns | Description |
172|----------|---------|-------------|
173| `GetSpecialization()` | `specIndex` | Current spec index (1-4) |
174| `GetSpecializationInfo(specIndex [, isInspect [, isPet [, inspectUnit [, sex]]]])` | `id, name, description, icon, role, primaryStat` | Spec details |
175| `GetSpecializationInfoByID(specID)` | `id, name, description, icon, role, primaryStat, ...` | Spec details by ID |
176| `GetSpecializationInfoForClassID(classID, specIndex)` | `id, name, description, icon, role, primaryStat` | Spec for class |
177| `GetSpecializationInfoForSpecID(specID [, sex])` | `id, name, description, icon, role, primaryStat` | Spec by spec ID |
178| `GetSpecializationRole(specIndex)` | `role` | Spec's role type |
179| `GetSpecializationRoleByID(specID)` | `role` | Role by spec ID |
180| `GetNumSpecializations([isInspect [, isPet]])` | `numSpecs` | Number of specs |
181| `GetNumSpecializationsForClassID(classID)` | `numSpecs` | Specs for class |
182| `SetSpecialization(specIndex)` | — | Switch spec |
183| `GetActiveSpecGroup()` | `specGroup` | Active spec group |
184| `GetSpecializationMasterySpells(specIndex [, isInspect [, isPet]])` | `spellIDs` | Mastery spell(s) |
185| `GetSpecializationSpells(specIndex [, isInspect [, isPet]])` | `... (spellID, level pairs)` | Spec spells |
186
187---
188
189## C_SpecializationInfo
190
191| Function | Returns | Description |
192|----------|---------|-------------|
193| `C_SpecializationInfo.CanPlayerUseTalentSpecUI()` | `canUse, failureReason` | Can use talent UI? |
194| `C_SpecializationInfo.GetAllSelectedPvpTalentIDs()` | `talentIDs` | Selected PvP talents |
195| `C_SpecializationInfo.GetInspectSelectedPvpTalent(inspectUnit, talentIndex)` | `talentID` | Inspected PvP talent |
196| `C_SpecializationInfo.GetPvpTalentAlertStatus()` | `hasUnspent` | PvP talent alert? |
197| `C_SpecializationInfo.GetPvpTalentSlotInfo(slotIndex)` | `slotInfo` | PvP talent slot |
198| `C_SpecializationInfo.GetPvpTalentSlotUnlockLevel(slotIndex)` | `level` | PvP slot unlock level |
199| `C_SpecializationInfo.GetPvpTalentUnlockLevel(talentID)` | `level` | PvP talent unlock level |
200| `C_SpecializationInfo.GetSpellsDisplay(specID)` | `spellIDs` | Display spells for spec |
201| `C_SpecializationInfo.IsInitialized()` | `isInitialized` | Spec system ready? |
202| `C_SpecializationInfo.MatchesCurrentSpecSet(setID)` | `matches` | Equipment set matches spec? |
203| `C_SpecializationInfo.SetPvpTalentLocked(talentID, locked)` | — | Lock PvP talent |
204
205---
206
207## Common Patterns
208
209### Get Active Spec Info
210
211```lua
212local specIndex = GetSpecialization()
213if specIndex then
214 local specID, specName, specDesc, specIcon, specRole = GetSpecializationInfo(specIndex)
215 print("Current Spec:", specName, "Role:", specRole)
216end
217```
218
219### Iterate Talent Tree Nodes
220
221```lua
222local configID = C_ClassTalents.GetActiveConfigID()
223if configID then
224 local specID = PlayerUtil.GetCurrentSpecID and PlayerUtil.GetCurrentSpecID()
225 or GetSpecializationInfo(GetSpecialization())
226 local treeID = C_ClassTalents.GetTraitTreeForSpec(specID)
227 if treeID then
228 local nodeIDs = C_Traits.GetTreeNodes(treeID)
229 for _, nodeID in ipairs(nodeIDs) do
230 local nodeInfo = C_Traits.GetNodeInfo(configID, nodeID)
231 if nodeInfo and nodeInfo.isVisible and nodeInfo.activeRank > 0 then
232 local entryInfo = C_Traits.GetEntryInfo(configID, nodeInfo.activeEntry.entryID)
233 if entryInfo then
234 local defInfo = C_Traits.GetDefinitionInfo(entryInfo.definitionID)
235 if defInfo then
236 local spellName = C_Spell.GetSpellName(defInfo.spellID)
237 print(spellName, "Rank:", nodeInfo.activeRank)
238 end
239 end
240 end
241 end
242 end
243end
244```
245
246### Export/Import Talent String
247
248```lua
249-- Export current talents
250local exportString = C_ClassTalents.GetLoadoutExportString()
251print("Talent string:", exportString)
252
253-- Import talents (must be out of combat)
254local success, loadoutInfo = C_ClassTalents.ImportLoadout(exportString)
255if success then
256 C_ClassTalents.ViewLoadout(loadoutInfo)
257end
258```
259
260### Switch Specialization
261
262```lua
263local function SwitchSpec(specIndex)
264 if specIndex ~= GetSpecialization() then
265 if not InCombatLockdown() then
266 SetSpecialization(specIndex)
267 else
268 print("Cannot change spec in combat")
269 end
270 end
271end
272```
273
274---
275
276## Key Events
277
278| Event | Payload | Description |
279|-------|---------|-------------|
280| `PLAYER_SPECIALIZATION_CHANGED` | unit | Specialization changed |
281| `ACTIVE_COMBAT_CONFIG_CHANGED` | configID | Active talent config changed |
282| `TRAIT_CONFIG_CREATED` | configInfo | New config created |
283| `TRAIT_CONFIG_DELETED` | configID | Config deleted |
284| `TRAIT_CONFIG_UPDATED` | configID | Config updated |
285| `TRAIT_CONFIG_LIST_UPDATED` | — | Config list changed |
286| `TRAIT_NODE_CHANGED` | nodeID | Trait node changed |
287| `TRAIT_NODE_ENTRY_UPDATED` | nodeID | Node entry updated |
288| `TRAIT_TREE_CHANGED` | treeID | Tree structure changed |
289| `TRAIT_TREE_CURRENCY_INFO_UPDATED` | treeID | Currency info changed |
290| `SPECIALIZATION_CHANGE_CAST_FAILED` | — | Spec change failed |
291| `CONFIRM_TALENT_WIPE` | cost, respecType | Confirm talent wipe |
292| `STARTER_BUILD_ACTIVATION_FAILED` | — | Starter build failed |
293| `SELECTED_PVP_TALENTS_CHANGED` | — | PvP talents changed |
294| `PVP_TALENTS_UPDATE` | — | PvP talents refreshed |
295| `HERO_TALENT_SELECTION_CHANGED` | — | Hero talent selection changed |
296
297---
298
299## Gotchas & Restrictions
300
3011. **configID is per-spec** — Each specialization has its own set of configs. Active configID changes on spec switch.
3022. **Cannot change talents in combat** — `C_ClassTalents.CommitConfig()` and `SetSpecialization()` fail in combat.
3033. **Trait system is generic** — `C_Traits` is the underlying system used for class talents, hero talents, AND profession specializations. The `configType` differentiates them.
3044. **Node types matter** — Single nodes have one entry, Selection (choice) nodes have multiple entries you pick between.
3055. **Hero talents are sub-trees** — Hero talent selection is a SubTreeSelection node type. Use `C_Traits.GetSubTreeInfo()`.
3066. **GetNodeInfo is expensive** — Cache node info when iterating the full tree. Don't call in OnUpdate.
3077. **Loadout export is opaque** — The export string format is internal. Use the API functions, don't parse manually.
3088. **specIndex vs specID** — `GetSpecialization()` returns an index (1-4), not a specID. Use `GetSpecializationInfo()` to get the specID.