File src/ChorusRaidUnitButtonTemplate.lua changed (mode: 100644) (index 08a5a40..0755351) |
... |
... |
function Chorus.raidUnitButtonMain(self) |
52 |
52 |
|
|
53 |
53 |
Chorus.raidUnitButtonAttributeChangedProcessor(self, 'unit', self:GetAttribute('unit')) |
Chorus.raidUnitButtonAttributeChangedProcessor(self, 'unit', self:GetAttribute('unit')) |
54 |
54 |
--[[ TODO Add menu popup for unit frames ]]-- |
--[[ TODO Add menu popup for unit frames ]]-- |
|
55 |
|
--[[ TODO Add range indicator ]]-- |
|
56 |
|
--[[ TODO Add threat indicator ]]-- |
|
57 |
|
--[[ TODO Add role indicator ]]-- |
55 |
58 |
end |
end |
File src/ChorusRangeFrameTemplate.lua added (mode: 100644) (index 0000000..40f6327) |
|
1 |
|
local IsSpellInRange = IsSpellInRange |
|
2 |
|
|
|
3 |
|
local Chorus = Chorus |
|
4 |
|
|
|
5 |
|
--[[ Populate range spell map at runtime initialization. ]]-- |
|
6 |
|
local spellMap = { |
|
7 |
|
--[[ Paladin ]]-- |
|
8 |
|
['Cleanse'] = 40, |
|
9 |
|
['Purify'] = 40, |
|
10 |
|
['Hammer of Justice'] = 10, |
|
11 |
|
['Judgement of Light'] = 10, |
|
12 |
|
['Blessing of Might'] = 30, |
|
13 |
|
--[[ Priest ]]-- |
|
14 |
|
['Lesser Heal'] = 40, |
|
15 |
|
['Smite'] = 30, |
|
16 |
|
['Power Word: Fortitude'] = 30, |
|
17 |
|
['Resurrection'] = 30, |
|
18 |
|
['Mind Control'] = 20, |
|
19 |
|
--[[ Any ]]-- |
|
20 |
|
['Shoot'] = 30, |
|
21 |
|
} |
|
22 |
|
|
|
23 |
|
--[[ Duplicate getUnit logic to make sure it cannot be overriden at runtime. ]]-- |
|
24 |
|
|
|
25 |
|
local function getUnit(f) |
|
26 |
|
local p = f:GetParent() |
|
27 |
|
local u = f.unit or f:GetAttribute('unit') |
|
28 |
|
if not u and p then |
|
29 |
|
u = p.unit or p:GetAttribute('unit') |
|
30 |
|
end |
|
31 |
|
return u |
|
32 |
|
end |
|
33 |
|
|
|
34 |
|
local function rangeFrameUpdate(self) |
|
35 |
|
assert(self ~= nil) |
|
36 |
|
|
|
37 |
|
local unitDesignation = getUnit(self) or 'none' |
|
38 |
|
|
|
39 |
|
assert(unitDesignation ~= nil) |
|
40 |
|
assert('string' == type(unitDesignation)) |
|
41 |
|
unitDesignation = string.lower(strtrim(unitDesignation)) |
|
42 |
|
assert(string.len(unitDesignation) >= 1) |
|
43 |
|
assert(string.len(unitDesignation) <= 256) |
|
44 |
|
|
|
45 |
|
local label = self.label or _G[self:GetName() .. 'Text'] |
|
46 |
|
assert(label ~= nil) |
|
47 |
|
|
|
48 |
|
--[[ Frame must be always shown to keep update processor running. ]]-- |
|
49 |
|
if not UnitExists(unitDesignation) then |
|
50 |
|
label:SetText(nil) |
|
51 |
|
return |
|
52 |
|
end |
|
53 |
|
|
|
54 |
|
local rangeFlag = nil |
|
55 |
|
local distanceYards = nil |
|
56 |
|
local maxRangeYards = 0 |
|
57 |
|
for spellName, rangeYards in pairs(spellMap) do |
|
58 |
|
local flag = IsSpellInRange(spellName, unitDesignation) |
|
59 |
|
--[[ 1 == flag: in range; ]]-- |
|
60 |
|
--[[ 0 == flag: out of range; ]]-- |
|
61 |
|
--[[ nil == flag: not applicable or cannot be cast on given target. ]]-- |
|
62 |
|
if not rangeFlag and flag then |
|
63 |
|
rangeFlag = flag |
|
64 |
|
end |
|
65 |
|
maxRangeYards = math.max(rangeYards, maxRangeYards) |
|
66 |
|
if 1 == flag then |
|
67 |
|
rangeFlag = 1 |
|
68 |
|
if not distanceYards then |
|
69 |
|
distanceYards = rangeYards |
|
70 |
|
end |
|
71 |
|
distanceYards = math.min(distanceYards, rangeYards) |
|
72 |
|
end |
|
73 |
|
end |
|
74 |
|
|
|
75 |
|
local t |
|
76 |
|
if 1 == rangeFlag then |
|
77 |
|
t = string.format('<%d yd', distanceYards) |
|
78 |
|
label:SetTextColor(1, 1, 1) |
|
79 |
|
elseif 0 == rangeFlag then |
|
80 |
|
t = string.format('>%d yd', maxRangeYards) |
|
81 |
|
label:SetTextColor(1, 0, 0) |
|
82 |
|
else |
|
83 |
|
t = nil |
|
84 |
|
end |
|
85 |
|
label:SetText(t) |
|
86 |
|
end |
|
87 |
|
|
|
88 |
|
local function rangeFrameUpdateProcessor(self) |
|
89 |
|
assert(self ~= nil) |
|
90 |
|
|
|
91 |
|
--[[ Reduce update frequency to roughly 6 frames per second. ]]-- |
|
92 |
|
if self.lastUpdateInstance and 'number' == type(self.lastUpdateInstance) then |
|
93 |
|
local now = GetTime() |
|
94 |
|
if now - self.lastUpdateInstance > 0.1667 then |
|
95 |
|
self.lastUpdateInstance = now |
|
96 |
|
else |
|
97 |
|
return |
|
98 |
|
end |
|
99 |
|
end |
|
100 |
|
|
|
101 |
|
rangeFrameUpdate(self) |
|
102 |
|
end |
|
103 |
|
|
|
104 |
|
local function rangeFrameMain(self) |
|
105 |
|
assert(self ~= nil) |
|
106 |
|
|
|
107 |
|
self.label = _G[self:GetName() .. 'Text'] |
|
108 |
|
self:SetScript('OnUpdate', rangeFrameUpdateProcessor) |
|
109 |
|
end |
|
110 |
|
|
|
111 |
|
--[[ Hide reference to the internal function, for some reason. ]]-- |
|
112 |
|
Chorus.rangeFrameMain = function(...) |
|
113 |
|
return rangeFrameMain(...) |
|
114 |
|
end |
File src/ChorusRangeFrameTemplate.xml added (mode: 100644) (index 0000000..172aff8) |
|
1 |
|
<?xml version="1.0" encoding="UTF-8"?> |
|
2 |
|
<Ui xmlns="http://www.blizzard.com/wow/ui/"> |
|
3 |
|
<Script file="ChorusRangeFrameTemplate.lua"/> |
|
4 |
|
<Frame name="ChorusRangeFrameTemplate" virtual="true"> |
|
5 |
|
<Size> |
|
6 |
|
<AbsDimension x="48" y="24" /> |
|
7 |
|
</Size> |
|
8 |
|
<Layers> |
|
9 |
|
<Layer level="OVERLAY"> |
|
10 |
|
<FontString name="$parentText" inherits="SystemFont_Shadow_Med1" setAllPoints="true"/> |
|
11 |
|
</Layer> |
|
12 |
|
</Layers> |
|
13 |
|
<Scripts> |
|
14 |
|
<OnLoad> |
|
15 |
|
Chorus.rangeFrameMain(self); |
|
16 |
|
</OnLoad> |
|
17 |
|
</Scripts> |
|
18 |
|
</Frame> |
|
19 |
|
<Frame name="ChorusTargetRangeFrame" inherits="ChorusRangeFrameTemplate"> |
|
20 |
|
<Anchors> |
|
21 |
|
<Anchor point="CENTER"> |
|
22 |
|
<AbsDimension x="128" y="32"/> |
|
23 |
|
</Anchor> |
|
24 |
|
</Anchors> |
|
25 |
|
<Attributes> |
|
26 |
|
<Attribute name="unit" type="string" value="target"/> |
|
27 |
|
</Attributes> |
|
28 |
|
</Frame> |
|
29 |
|
</Ui> |