Repository navigation
Expand file tree
/
Copy pathRacials.lua
More file actions
120 lines (110 loc) · 5.21 KB
/
Copy pathRacials.lua
File metadata and controls
120 lines (110 loc) · 5.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
-- WickCore
-- Racials.lua — every race's two actives, as a display-only cooldown row.
--
-- Forever gives every race two active and two passive racials. This row
-- shows the actives as secure cast buttons with a Cooldown widget under
-- each. Cooldown values are secret in combat on Forever; they are passed
-- straight into SetCooldown, which accepts secrets, and never compared.
--
-- Data from talentsforever.com (https://talentsforever.com), CC BY 4.0,
-- read off the BlizzCon 2026 demo. Names bind to spells in game.
local ADDON = ...
local Core = LibStub("WickCore-1.0", true)
if not Core or Core._sourceAddon ~= ADDON then return end
local Racials = {}
Core.Racials = Racials
local D, R, Chrome = Core.Dialect, Core.Restrict, Core.Chrome
local C = Chrome.Colors
-- Keyed by the UnitRace token. Skyborne has two factions with one shared
-- active and one that differs; both are listed and the unknown one is
-- skipped when the spell is not known.
Racials.DATA = {
Orc = { actives = { "Blood Fury", "Shatter Curse" }, passives = { "Axe Specialization", "Hardiness" } },
Scourge = { actives = { "Will of the Forsaken", "Cannibalize" }, passives = { "Underwater Breathing", "Touch of the Grave" } },
Tauren = { actives = { "War Stomp" }, passives = { "Cultivation", "Plainsrunning", "Endurance" } },
Troll = { actives = { "Berserking", "Rapid Regeneration" }, passives = { "Beast Slaying", "Regeneration" } },
Skyborne = { actives = { "Walk on Air", "Skysight", "Read Ley Line" }, passives = { "Wind Blessed", "Elemental Insight" } },
Human = { actives = { "Will to Survive", "Perception" }, passives = { "Sword Specialization", "The Human Spirit" } },
Dwarf = { actives = { "Stoneform", "Find Treasure" }, passives = { "Mace Specialization", "Big Game Hunter" } },
NightElf = { actives = { "Elune's Light", "Shadowmeld" }, passives = { "Quickness", "Wisp Spirit" } },
Gnome = { actives = { "Escape Artist", "Eureka!" }, passives = { "Expansive Mind", "Engineering Specialization" } },
}
Racials.ATTRIBUTION = "Racial data from talentsforever.com (CC BY 4.0)"
function Racials:ForPlayer()
local _, token = UnitRace("player")
return self.DATA[token], token
end
-- Actives the player actually knows. Names resolve through the spellbook.
function Racials:KnownActives()
local data = self:ForPlayer()
if not data then return {} end
local out = {}
for _, name in ipairs(data.actives) do
local info = D.GetSpellInfo(name)
if info and info.spellID and (D.IsSpellKnown(info.spellID) or not rawget(_G, "C_SpellBook")) then
out[#out + 1] = { name = name, spellID = info.spellID, icon = info.icon }
elseif info and info.spellID then
-- IsSpellKnown may lag at login; keep the button, it just fails to cast.
out[#out + 1] = { name = name, spellID = info.spellID, icon = info.icon }
end
end
return out
end
-- ============================================================
-- Row widget
-- ============================================================
local ICON = 30
function Racials:Attach(parent, y)
self.buttons = self.buttons or {}
local actives = self:KnownActives()
local x = 0
for i, a in ipairs(actives) do
local b = self.buttons[i]
if not b then
b = CreateFrame("Button", nil, parent, "SecureActionButtonTemplate")
b:SetSize(ICON, ICON)
b:RegisterForClicks("AnyUp", "AnyDown")
Chrome:AddBorder(b)
b.icon = b:CreateTexture(nil, "ARTWORK")
b.icon:SetPoint("TOPLEFT", 1, -1)
b.icon:SetPoint("BOTTOMRIGHT", -1, 1)
b.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
b.cd = CreateFrame("Cooldown", nil, b, "CooldownFrameTemplate")
b.cd:SetAllPoints(b.icon)
b:SetScript("OnEnter", function(s)
GameTooltip:SetOwner(s, "ANCHOR_TOP")
if s.spellID and GameTooltip.SetSpellByID then GameTooltip:SetSpellByID(s.spellID)
else GameTooltip:SetText(s.spellName or "") end
GameTooltip:Show()
end)
b:SetScript("OnLeave", function() GameTooltip:Hide() end)
self.buttons[i] = b
end
b.spellID, b.spellName = a.spellID, a.name
if not InCombatLockdown() then
b:SetAttribute("type", "spell")
b:SetAttribute("spell", a.name)
end
b.icon:SetTexture(a.icon)
b:ClearAllPoints()
b:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
b:Show()
x = x + ICON + 6
end
for i = #actives + 1, #self.buttons do self.buttons[i]:Hide() end
self.parent = parent
self:Refresh()
return y - ICON - 6, #actives
end
-- Feed cooldowns through to the widget. Secret values are fine here.
function Racials:Refresh()
if not self.buttons then return end
for _, b in ipairs(self.buttons) do
if b:IsShown() and b.spellID then
local cd = D.GetSpellCooldown(b.spellID)
if cd and cd.start ~= nil and cd.duration ~= nil then
pcall(b.cd.SetCooldown, b.cd, cd.start, cd.duration, cd.modRate)
end
end
end
end