bfc00e5 - Redo config tables
[wowui.git] / Indicators.lua
1 local media = LibStub:GetLibrary("LibSharedMedia-3.0");
2 local f = RaidFrameCustomization.frames;
3 local positions = RaidFrameCustomization.positions;
4 local pad = 2;
5 local paddings = {
6     TOPLEFT = {pad, -pad},
7     TOPRIGHT = {-pad, -pad},
8     CENTER = {0, 0},
9     BOTTOMLEFT = {pad, pad},
10     BOTTOMRIGHT = {-pad, pad}
11 };
12 local watchedAuras; -- all watched auras
13 local indicatorAuras; -- watched auras per indicator
14 local auraFilters = {"HELPFUL", "HARMFUL"};
15 local DEFAULT_ICON = "Interface\\AddOns\\RaidFrameCustomization\\images\\rhomb";
16 local _;
17
18 -- global functions used every update
19 local GetTime = GetTime;
20 local UnitAura = UnitAura;
21 local UnitIsUnit = UnitIsUnit;
22 local UnitIsConnected = UnitIsConnected;
23 local UnitIsDeadOrGhost = UnitIsDeadOrGhost;
24 local CompactRaidFrameContainer_ApplyToFrames = CompactRaidFrameContainer_ApplyToFrames;
25
26 -- list of important auras TODO try to use spellIDs
27 local centerAuras = {
28     "Power Word: Shield"
29 };
30
31 local function dPrint(s)
32     DEFAULT_CHAT_FRAME:AddMessage("Indicators: ".. tostring(s));
33 end
34
35 local function configureIndicators(frame)
36     local frameName = frame:GetName();
37     if not f[frameName] then return end
38
39     local config = RaidFrameCustomization.db.profile;
40     local font = media and media:Fetch('font', config.indicatorFont) or STANDARD_TEXT_FONT;
41     for pos, ind in pairs(f[frameName]) do
42         ind.text:SetFont(font, config[pos]["textSize"]);
43         ind.text:SetTextColor(unpack(config[pos]["color"]));
44         ind.icon:SetWidth(config[pos]["iconSize"]);
45         ind.icon:SetHeight(config[pos]["iconSize"]);
46         ind.icon:SetTexture(DEFAULT_ICON);
47         if config[pos]["showIcon"] then
48             ind.icon:Show();
49         else
50             ind.icon:Hide();
51         end
52     end
53 end
54
55 -- Create the FontStrings used for indicators
56 local function setupCompactUnitFrame(frame)
57     local name = frame:GetName();
58     f[name] = {};
59     for _, pos in ipairs(positions) do
60         f[name][pos] = {};
61         f[name][pos].text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
62         f[name][pos].text:SetPoint(pos, frame, pos, paddings[pos][1], paddings[pos][2]);
63         f[name][pos].icon = frame:CreateTexture(nil, "OVERLAY");
64         f[name][pos].icon:SetPoint(pos, frame, pos, paddings[pos][1], paddings[pos][2]);
65     end
66     configureIndicators(frame);
67 end
68
69 -- Get all unit auras TODO change to event driven, only remaining updating with timer
70 local function getAuras(unit)
71     local unitAuras = {};
72     local auraName, icon, count, expires, caster, debuffType, spellId;
73     local filter;
74
75     for _, filter in ipairs(auraFilters) do
76         local i = 1;
77         while true do
78             auraName, _, icon, count, debuffType, _, expires, caster, _, _, spellId = UnitAura(unit, i, filter);
79             if not spellId then break end
80             if watchedAuras[auraName] or watchedAuras[spellId] or watchedAuras[debuffType] then
81                 local aura = {};
82                 aura.auraName = auraName;
83                 aura.spellId = spellId;
84                 aura.count = count;
85                 aura.expires = expires;
86                 aura.mine = UnitIsUnit(caster, "player");
87                 aura.icon = icon;
88                 aura.debuffType = debuffType;
89                 table.insert(unitAuras, aura);
90             end
91             i = i + 1;
92         end
93     end
94     return unitAuras;
95 end
96
97 -- Check the indicators on a frame and update the times on them
98 local function updateIndicators(frame)
99     if not frame.unit then return end
100     local unit = frame.unit;
101     local frameName = frame:GetName();
102
103     -- Check if the indicator object exists, else create it
104     if not f[frameName] then setupCompactUnitFrame(frame) end
105     -- Hide if unit is dead/disconnected
106     if (not UnitIsConnected(unit)) or UnitIsDeadOrGhost(frame.displayedUnit) then
107         for _, ind in pairs(f[frameName]) do
108             ind.text:SetText("");
109             ind.icon:SetTexture("");
110         end
111         return;
112     end
113
114     local unitAuras = getAuras(unit);
115     for pos, ind in pairs(f[frameName]) do
116         -- try to find matching aura
117         local found, aura;
118         for _, aura in pairs(unitAuras) do
119             if indicatorAuras[pos][aura.auraName] or indicatorAuras[pos][aura.spellId] or
120                indicatorAuras[pos][aura.debuffType] then
121                 found = aura;
122                 -- break on first matching buff/debuff cast by me
123                 -- otherwise continue through
124                 if aura.mine then break end
125             end
126         end
127
128         local config = RaidFrameCustomization.db.profile[pos];
129         if found then
130             if config.mine and not found.mine then
131                 -- don't show
132                 ind.icon:SetTexture("");
133                 ind.text:SetText("");
134             else
135                 if config.showIcon and not config.useDefaultIcon then
136                     -- show icon TODO coloring
137                     ind.icon:SetTexture(found.icon);
138                 end
139                 -- TODO make show text into general setting
140                 -- under which you can select what text to show
141                 if config.showText then
142                     -- show text
143                     local text;
144                     local remaining = found.expires - GetTime();
145                     if remaining > 60 then
146                         text = string.format("%dm", ceil(remaining/60));
147                     else
148                         text = string.format("%d", floor(remaining+0.5));
149                     end
150
151                     if config.stack and found.count > 0 then
152                         if text then
153                             text = found.count.."-"..text;
154                         else
155                             text = found.count;
156                         end
157                     end
158
159                     ind.text:SetText(text);
160                 end
161             end
162         else
163             -- not found, show nothing
164             ind.icon:SetTexture("");
165             ind.text:SetText("");
166         end
167     end
168 end
169
170 -- Update all indicators
171 function RaidFrameCustomization:UpdateAllIndicators()
172     CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", updateIndicators);
173 end
174
175 -- Used to update everything that is affected by the configuration
176 function RaidFrameCustomization:RefreshConfig()
177     self:OnDisable(); -- clear everything
178     if self.db.profile.enabled then
179         CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", configureIndicators);
180         -- Format aura strings
181         watchedAuras = {};
182         indicatorAuras = {};
183         for _, pos in ipairs(positions) do
184             indicatorAuras[pos] = {};
185             for _, aura in ipairs(self.db.profile[pos]["auras"]) do
186                 watchedAuras[aura] = true;
187                 indicatorAuras[pos][aura] = true;
188             end
189         end
190
191         if next(watchedAuras) ~= nil then
192             self.updateTimer = self:ScheduleRepeatingTimer("UpdateAllIndicators", 0.15);
193         end
194     end
195 end