4 local format = string.format;
5 local ssub = string.sub;
6 local GetActionInfo, GetActionTexture = GetActionInfo, GetActionTexture;
7 local GetActionLossOfControlCooldown = GetActionLossOfControlCooldown;
8 local GetActionCooldown, GetActionCharges = GetActionCooldown, GetActionCharges;
9 local IsConsumableAction, IsStackableAction = IsConsumableAction, IsStackableAction;
10 local IsItemAction, GetActionCount = IsItemAction, GetActionCount;
11 local IsSpellOverlayed, GetMacroSpell = IsSpellOverlayed, GetMacroSpell;
12 local IsMounted = IsMounted;
13 local HasAction, IsUsableAction = HasAction, IsUsableAction;
14 local IsCurrentAction, IsAutoRepeatAction = IsCurrentAction, IsAutoRepeatAction;
15 local CreateFrame = CreateFrame;
16 local RegisterStateDriver = RegisterStateDriver;
17 local CooldownFrame_Set, CooldownFrame_Clear = CooldownFrame_Set, CooldownFrame_Clear;
18 local CTimerAfter = C_Timer.After;
19 local GameTooltip = nil;
20 local COOLDOWN_TYPE_LOSS_OF_CONTROL = COOLDOWN_TYPE_LOSS_OF_CONTROL;
21 local COOLDOWN_TYPE_NORMAL = COOLDOWN_TYPE_NORMAL;
22 local CDTexture = "Interface\\Cooldown\\edge";
23 local locCDTexture = "Interface\\Cooldown\\edge-LoC";
25 local BUTTONLOCK = true; -- change to lock button dragging
80 -- used as bonus bars for some classes
111 local usingBonusbars = {
112 --["WARRIOR"] = {[7]=true, [8]=true, [9]=true}, -- not using stance separated actionbars
113 ["DRUID"] = {[7]=true, [8]=true, [9]=true}, -- moonkin form page is usable anyway
114 --["DRUID"] = {[7]=true, [8]=true, [9]=true,[10]=true},
115 ["ROGUE"] = {[7]=true},
116 --["PRIEST"] = {[7]=true}, -- shadowform doesn't change abilities
121 ["Vildan"] = {1, 2, 3, 4,},
122 ["Gedren"] = {1, 2, 3, 4,},
127 local activeButtons = {};
129 local ActionBars = CreateFrame("Frame", "OmaActionBars", UIParent);
130 local inheritedFrames =
131 "SecureActionButtonTemplate,SecureHandlerDragTemplate,SecureHandlerStateTemplate";
133 local numChargeCDs = 0;
134 local function createChargeCD(parent)
135 numChargeCDs = numChargeCDs + 1;
136 local frame = CreateFrame("Cooldown", "OmaChargeCD"..numChargeCDs, parent, "CooldownFrameTemplate");
137 frame:SetHideCountdownNumbers(false);
138 frame:SetDrawSwipe(false);
139 frame:SetAllPoints(parent);
140 frame:SetFrameStrata("TOOLTIP");
144 local function clearChargeCD(parent)
145 if parent.chargecd then CooldownFrame_Clear(parent.chargecd) end
148 local function startChargeCD(parent, start, duration, modrate)
150 return clearChargeCD(parent);
152 parent.chargecd = parent.chargecd or createChargeCD(parent);
153 CooldownFrame_Set(parent.chargecd, start, duration, true, true, modrate);
158 local function updateCooldown(button, slot)
159 -- CD update from FrameXML/ActionButton.lua
160 local locstart, locduration = GetActionLossOfControlCooldown(slot);
161 local start, duration, enable, modrate = GetActionCooldown(slot);
162 local charges, maxcharges, chargestart, chargeduration, chargemodrate = GetActionCharges(slot);
163 if (locstart + locduration) > (start + duration) then
164 if button.cd.currentCooldownType ~= COOLDOWN_TYPE_LOSS_OF_CONTROL then
165 button.cd:SetEdgeTexture(locCDTexture);
166 button.cd:SetSwipeColor(0.17, 0, 0);
167 button.cd:SetHideCountdownNumbers(true);
168 button.cd.currentCooldownType = COOLDOWN_TYPE_LOSS_OF_CONTROL;
171 CooldownFrame_Set(button.cd, locstart, locduration, true, true, modrate);
172 clearChargeCD(button);
174 if button.cd.currentCooldownType ~= COOLDOWN_TYPE_NORMAL then
175 button.cd:SetEdgeTexture(CDTexture);
176 button.cd:SetSwipeColor(0, 0, 0);
177 button.cd:SetHideCountdownNumbers(false);
178 button.cd.currentCooldownType = COOLDOWN_TYPE_NORMAL;
182 button.cd:SetScript("OnCooldownDone", redoCooldown);
184 if charges and maxcharges and maxcharges > 1 and charges < maxcharges then
185 startChargeCD(button, chargestart, chargeduration, chargemodrate);
187 clearChargeCD(button);
189 CooldownFrame_Set(button.cd, start, duration, enable, false, modrate);
193 local function redoCooldown(cd)
194 local button = cd:GetParent();
195 cd:SetScript("OnCooldownDone", nil);
196 updateCooldown(button, button.slot);
199 local function updateCount(button, slot)
200 if IsConsumableAction(slot) or IsStackableAction(slot) or
201 (not IsItemAction(slot) and GetActionCount(slot) > 0) then
202 local count = GetActionCount(slot);
204 button.count:SetText("*");
206 button.count:SetText(count);
210 local charges, maxcharges = GetActionCharges(slot);
211 if maxcharges > 1 then
212 button.count:SetText(charges);
220 local function updateUsable(button, slot)
221 local isUsable, noMana = IsUsableAction(slot);
223 button.icon:SetVertexColor(1, 1, 1);
225 button.icon:SetVertexColor(0, 0.5, 1);
227 button.icon:SetVertexColor(0.4, 0.4, 0.4);
231 local function updateState(button, slot)
232 button:SetChecked(IsCurrentAction(slot) or IsAutoRepeatAction(slot));
235 local function updateGlow(button, slot, spell, hide)
236 local stype, id, _ = GetActionInfo(slot);
237 if stype == "spell" and (spell and id == spell or IsSpellOverlayed(id)) then
243 elseif stype == "macro" then
244 local _, _, macroid = GetMacroSpell(id);
245 if macroid and (spell and macroid == spell or IsSpellOverlayed(macroid)) then
254 else -- TODO FlyoutHasSpell glow
259 local function updateButton(button, slot)
260 if HasAction(slot) then
261 activeButtons[slot] = button;
263 button.icon:SetTexture(GetActionTexture(slot));
264 updateCooldown(button, slot);
265 updateUsable(button, slot);
266 updateState(button, slot);
267 updateCount(button, slot);
268 updateGlow(button, slot);
269 if not IsConsumableAction(slot) and not IsStackableAction(slot) then
270 button.text:SetText(ssub(GetActionText(slot) or "", 1, 4));
273 if button.hotkey.shown then button.hotkey:Show() end
275 activeButtons[slot] = nil;
276 if not button.grid then button.base:Hide() end
277 button.icon:SetTexture(nil);
280 button.hotkey:Hide();
283 button:SetChecked(false);
287 local function updateHotkeys(button)
288 local key = GetBindingKey(format("CLICK %s:LeftButton", button:GetName()));
289 if key and key ~= "" then
290 -- from LibKeyBound-1.0
292 key = key:gsub(" ", "");
293 key = key:gsub("ALT%-", "a");
294 key = key:gsub("CTRL%-", "c");
295 key = key:gsub("SHIFT%-", "s");
296 key = key:gsub("NUMPAD", "n");
297 button.hotkey:SetText(key);
298 button.hotkey.shown = true;
299 button.hotkey:Show();
301 button.hotkey.shown = nil;
302 button.hotkey:Hide();
306 local mainbartoggle = "[overridebar][possessbar][shapeshift]possess;";
307 mainbartoggle = mainbartoggle.."[bonusbar:1,stealth:1]bonusbar2;"; -- prowl
308 mainbartoggle = mainbartoggle.."[bonusbar:1]bonusbar1;[bonusbar:2]bonusbar2;"; -- cat form, unused
309 mainbartoggle = mainbartoggle.."[bonusbar:3]bonusbar3;[bonusbar:4]bonusbar4;"; -- bear form, moonkin form
310 mainbartoggle = mainbartoggle.."normal";
311 local function setupSnippets(secure, slot)
312 -- FrameXML/SecureHandlers.lua has arguments and return value
313 -- args: self, button, kind, value, ... (kind, value, ... from GetCursorInfo())
314 -- returns: kind, target, detail
315 -- or: "clear", kind, target, detail
316 -- used for Pickup* functions
317 -- some of these snippets based on LibActionButton-1.0
318 secure:SetAttribute("_ondragstart", [=[
319 return "action", self:GetAttribute("action");
321 secure:SetAttribute("_onreceivedrag", [=[
322 if not kind or not value then return nil end
323 return "action", self:GetAttribute("action");
325 -- pre-wrapper can pass a message to post-wrapper
326 secure:WrapScript(secure, "OnDragStart", [=[
327 local kind, value = GetActionInfo(self:GetAttribute("action"));
328 return "message", format("%s|%s", tostring(kind), tostring(value));
330 local kind, value = GetActionInfo(self:GetAttribute("action"));
331 if message ~= format("%s|%s", tostring(kind), tostring(value)) then
332 self:CallMethod("ActionChanged");
335 secure:WrapScript(secure, "OnReceiveDrag", [=[
336 local kind, value = GetActionInfo(self:GetAttribute("action"));
337 return "message", format("%s|%s", tostring(kind), tostring(value));
339 local kind, value = GetActionInfo(self:GetAttribute("action"));
340 if message ~= format("%s|%s", tostring(kind), tostring(value)) then
341 self:CallMethod("ActionChanged");
344 function secure:UpdateState()
345 return updateState(self, self.slot);
347 secure:WrapScript(secure, "OnClick", [=[
348 local kind, value = GetActionInfo(self:GetAttribute("action"));
349 return nil, format("%s|%s", tostring(kind), tostring(value));
351 local kind, value = GetActionInfo(self:GetAttribute("action"));
352 if message ~= format("%s|%s", tostring(kind), tostring(value)) then
353 self:CallMethod("ActionChanged");
355 self:CallMethod("UpdateState");
359 -- first action bar has possible states based on vehicle/possess etc.
360 secure:SetAttribute("origaction", slot);
361 secure:SetAttribute("_onstate-possess", [=[
362 local oldslot = self:GetAttribute("action");
363 if newstate == "possess" then
365 if HasVehicleActionBar() then
366 slot = (GetVehicleBarIndex()-1)*12+self:GetAttribute("origaction");
367 elseif HasOverrideActionBar() then
368 slot = (GetOverrideBarIndex()-1)*12+self:GetAttribute("origaction");
369 elseif HasTempShapeshiftActionBar() then
370 slot = (GetTempShapeshiftBarIndex()-1)*12+self:GetAttribute("origaction");
372 -- something wrong, just revert to normal
373 print("Possess bar index not found");
374 slot = self:GetAttribute("origaction");
376 self:SetAttribute("action", slot);
377 elseif newstate == "bonusbar1" then
378 self:SetAttribute("action", 72+self:GetAttribute("origaction"));
379 elseif newstate == "bonusbar2" then
380 self:SetAttribute("action", 84+self:GetAttribute("origaction"));
381 elseif newstate == "bonusbar3" then
382 self:SetAttribute("action", 96+self:GetAttribute("origaction"));
383 elseif newstate == "bonusbar4" then
384 --self:SetAttribute("action", 108+self:GetAttribute("origaction"));
385 -- moonkin form, don't change actionbar
386 self:SetAttribute("action", self:GetAttribute("origaction"));
388 self:SetAttribute("action", self:GetAttribute("origaction"));
390 self:CallMethod("ActionChanged", oldslot);
392 RegisterStateDriver(secure, "possess", mainbartoggle);
394 function secure:ShowButton() if HasAction(slot) then activeButtons[slot] = self end end
395 function secure:HideButton() activeButtons[slot] = nil end
396 -- all other action bar are hidden if with overridebar or vehicleui (not shapeshift, possessbar)
397 -- default Bartender4 options
398 secure:SetAttribute("_onstate-possess", [=[
399 if newstate == "possess" then
401 self:CallMethod("HideButton");
404 self:CallMethod("ShowButton");
407 RegisterStateDriver(secure, "possess", "[overridebar][vehicleui] possess; normal");
411 local function createActionBar(parent, config)
414 local bar = CreateFrame("Frame", "OmaBTBar"..config.bar, parent, "SecureFrameTemplate");
415 bar:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", config.x, config.y);
418 if config.hidden then
421 for slot = config.start, config.start+config.length-1 do
422 local secure = CreateFrame("CheckButton", "OmaBT"..slot, bar, inheritedFrames);
424 if slot == config.start then
425 secure:SetPoint("TOPLEFT");
426 elseif config.columns and i % config.columns == 0 then
427 secure:SetPoint("TOPLEFT", _G["OmaBT"..(slot-config.columns)], "BOTTOMLEFT");
429 secure:SetPoint("TOPLEFT", prev, "TOPRIGHT");
431 secure:RegisterForClicks("AnyUp");
432 if not BUTTONLOCK then
433 secure:RegisterForDrag("LeftButton", "RightButton");
435 if config.nomouse then
436 secure:EnableMouse(false);
438 secure:SetWidth(config.size or 32);
439 secure:SetHeight(config.size or 32);
440 secure.base = secure:CreateTexture(nil, "BACKGROUND");
441 secure.base:SetAllPoints();
442 secure.base:SetColorTexture(0, 0, 0, 0.5);
443 secure.iconbase = secure:CreateTexture(nil, "BORDER");
444 secure.iconbase:SetPoint("TOPLEFT", secure.base, "TOPLEFT", 1, -1);
445 secure.iconbase:SetPoint("BOTTOMRIGHT", secure.base, "BOTTOMRIGHT", -1, 1);
446 secure.iconbase:SetColorTexture(0, 0, 0, 0.5);
447 secure.iconbase:Hide();
448 secure.icon = secure:CreateTexture(nil, "ARTWORK");
449 secure.icon:SetPoint("TOPLEFT", secure.iconbase, "TOPLEFT");
450 secure.icon:SetPoint("BOTTOMRIGHT", secure.iconbase, "BOTTOMRIGHT");
451 secure.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93);
452 secure:SetCheckedTexture("Interface\\Buttons\\CheckButtonHilight");
453 secure.autocastable = secure:CreateTexture(nil, "OVERLAY");
454 secure.autocastable:SetPoint("CENTER");
455 secure.autocastable:SetWidth(58);
456 secure.autocastable:SetHeight(58);
457 secure.autocastable:SetTexture("Interface\\Buttons\\UI-AutoCastableOverlay");
458 secure.autocastable:Hide();
459 secure.glow = secure:CreateTexture(nil, "OVERLAY", nil, 1);
460 secure.glow:SetPoint("CENTER");
461 secure.glow:SetWidth(config.size and config.size+20 or 52);
462 secure.glow:SetHeight(config.size and config.size+20 or 52);
463 secure.glow:SetTexture("Interface\\SpellActivationOverlay\\IconAlert");
464 secure.glow:SetTexCoord(0.00781250, 0.50781250, 0.27734375, 0.52634375);
466 secure.hotkey = secure:CreateFontString(nil, "OVERLAY", "NumberFontNormalGray");
467 secure.hotkey:SetPoint("TOPRIGHT", secure, "TOPRIGHT", 2, -1);
468 secure.count = secure:CreateFontString(nil, "OVERLAY", "NumberFontNormal");
469 secure.count:SetPoint("BOTTOMRIGHT", secure, "BOTTOMRIGHT", 2, -1);
470 secure.text = secure:CreateFontString(nil, "OVERLAY", "NumberFontNormal");
471 secure.text:SetPoint("BOTTOMLEFT", secure, "BOTTOMLEFT", 2, -1);
473 secure.cd = CreateFrame("Cooldown", "OmaBTCD"..slot, secure, "CooldownFrameTemplate");
474 secure.cd:SetAllPoints();
475 secure:SetAttribute("type", "action");
476 secure:SetAttribute("action", slot);
477 if config.flyout then
478 secure:SetAttribute("flyoutDirection", config.flyout);
480 function secure:ActionChanged(oldslot)
481 if oldslot then activeButtons[oldslot] = nil end
482 self.slot = self:GetAttribute("action");
483 return updateButton(self, self.slot);
485 secure:ActionChanged(); -- initial update
486 setupSnippets(secure, slot);
487 updateHotkeys(secure);
488 buttons[slot] = secure;
494 local function initialize()
495 local _, class = UnitClass("player");
496 local name, realm = UnitFullName("player");
497 ActionBars:SetFrameStrata("LOW");
498 ActionBars:SetPoint("BOTTOMLEFT");
499 ActionBars:SetWidth(1);
500 ActionBars:SetHeight(1);
501 for _, config in pairs(settings) do
502 if (not usingBonusbars[class] or not usingBonusbars[class][config.bar]) and
503 (not chars[realm] or not chars[realm][name] or chars[realm][name][config.bar]) then
504 createActionBar(ActionBars, config);
509 local function setupBindings()
510 BINDING_HEADER_OmaAB = "Oma Action Bar";
512 _G["BINDING_HEADER_OMAABBLANK"..i] = "Bar "..i;
514 _G[format("BINDING_NAME_CLICK OmaBT%d:LeftButton", (i-1)*12+j)] = format("Bar %d Button %d", i, j);
519 local mounted = false;
520 local throttleCD = false;
521 local function throttleCDDone()
523 -- update CD once more to confirm newest CD change is taken in even with some throttling
524 for _, button in pairs(activeButtons) do
525 updateCooldown(button, button.slot);
530 ["ACTIONBAR_UPDATE_COOLDOWN"] = function()
531 if not throttleCD then -- only update at most once/frame
533 for _, button in pairs(activeButtons) do
534 updateCooldown(button, button.slot);
536 CTimerAfter(0.01, throttleCDDone); -- wait one frame
539 ["SPELL_UPDATE_CHARGES"] = function()
540 for _, button in pairs(activeButtons) do
541 updateCount(button, button.slot);
544 ["ACTIONBAR_SLOT_CHANGED"] = function(slot)
545 if buttons[slot] then buttons[slot]:ActionChanged() end
547 ["ACTIONBAR_SHOWGRID"] = function()
548 for _, button in pairs(buttons) do
550 button.iconbase:Show();
551 if not activeButtons[button.slot] then button.base:Show() end
554 ["ACTIONBAR_HIDEGRID"] = function()
555 for _, button in pairs(buttons) do
557 button.iconbase:Hide();
558 if not activeButtons[button.slot] then button.base:Hide() end
561 ["ACTIONBAR_UPDATE_STATE"] = function()
562 for _, button in pairs(activeButtons) do
563 updateState(button, button.slot);
566 ["ACTIONBAR_UPDATE_USABLE"] = function()
567 for _, button in pairs(activeButtons) do
568 updateUsable(button, button.slot);
571 ["UPDATE_OVERRIDE_ACTIONBAR"] = function()
572 if buttons[1] then -- called before PLAYER_LOGIN
573 for _, button in pairs(buttons) do
574 updateButton(button, button.slot);
578 ["START_AUTOREPEAT_SPELL"] = function()
579 for _, button in pairs(activeButtons) do
580 if IsAutoRepeatAction(button.slot) then
581 button.autorepeating = true;
582 button.icon:SetVertexColor(0, 1, 0.5);
586 ["STOP_AUTOREPEAT_SPELL"] = function()
587 for _, button in pairs(activeButtons) do
588 if button.autorepeating then
589 button.autorepeating = nil;
590 updateUsable(button, button.slot);
594 ["SPELL_ACTIVATION_OVERLAY_GLOW_SHOW"] = function(spell)
595 -- TODO create mapping from spellIDs to buttons
596 for _, button in pairs(activeButtons) do
597 updateGlow(button, button.slot, spell);
598 -- CD update might be throttled, force it
599 updateCooldown(button, button.slot);
602 ["SPELL_ACTIVATION_OVERLAY_GLOW_HIDE"] = function(spell)
603 -- TODO create mapping from spellIDs to buttons
604 for _, button in pairs(activeButtons) do
605 updateGlow(button, button.slot, spell, true);
606 -- CD update might be throttled, force it
607 updateCooldown(button, button.slot);
610 ["UPDATE_BINDINGS"] = function()
611 for _, button in pairs(buttons) do
612 updateHotkeys(button);
615 ["UNIT_AURA"] = function(unit)
616 -- using UNIT_AURA instead of COMPANION_UPDATE to not update every time
617 -- someone mounts, tracking player mount status with COMPANION_UPDATE is
619 if (not mounted and IsMounted()) or (mounted and not IsMounted()) then
620 mounted = not mounted;
621 for _, button in pairs(activeButtons) do
622 updateState(button, button.slot);
626 ["UPDATE_ALL_BUTTONS"] = function()
627 for _, button in pairs(buttons) do
628 updateButton(button, button.slot);
631 ["PLAYER_LOGIN"] = function()
632 GameTooltip = _G["GameTooltip"]; -- TODO use PLAYER_ENTERING_WORLD with MoveAnything
635 ["ADDON_LOADED"] = function(addon)
636 if addon == "OmaAB" then
638 ActionBars:UnregisterEvent("ADDON_LOADED");
642 events["LOSS_OF_CONTROL_ADDED"] = events["ACTIONBAR_UPDATE_COOLDOWN"];
643 events["LOSS_OF_CONTROL_UPDATE"] = events["ACTIONBAR_UPDATE_COOLDOWN"]; -- TODO might change once tooltips are in
644 events["PLAYER_MOUNT_DISPLAY_CHANGED"] = events["ACTIONBAR_UPDATE_USABLE"];
645 events["TRADE_SKILL_SHOW"] = events["ACTIONBAR_UPDATE_STATE"];
646 events["TRADE_SKILL_CLOSE"] = events["ACTIONBAR_UPDATE_STATE"];
647 events["ARCHAEOLOGY_CLOSED"] = events["ACTIONBAR_UPDATE_STATE"];
648 events["PLAYER_ENTERING_WORLD"] = events["UPDATE_ALL_BUTTONS"];
649 events["UPDATE_VEHICLE_ACTIONBAR"] = events["UPDATE_ALL_BUTTONS"];
650 events["UPDATE_SHAPESHIFT_FORM"] = events["UPDATE_ALL_BUTTONS"];
651 events["SPELL_UPDATE_ICON"] = events["UPDATE_ALL_BUTTONS"];
652 events["PET_STABLE_UPDATE"] = events["UPDATE_ALL_BUTTONS"];
653 events["PET_STABLE_SHOW"] = events["UPDATE_ALL_BUTTONS"];
654 events["PLAYER_SPECIALIZATION_CHANGED"] = events["UPDATE_ALL_BUTTONS"];
655 events["UNIT_ENTERED_VEHICLE"] = function(unit)
656 if unit == "player" then events["ACTIONBAR_UPDATE_STATE"]() end
658 events["UNIT_EXITED_VEHICLE"] = events["UNIT_ENTERED_VEHICLE"];
659 -- TODO overlay glow ? don't exactly know what it does, proc highlight?
662 ActionBars:RegisterEvent("ADDON_LOADED");
663 ActionBars:RegisterEvent("PLAYER_LOGIN");
664 ActionBars:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
665 ActionBars:RegisterEvent("ACTIONBAR_UPDATE_USABLE");
666 ActionBars:RegisterEvent("ACTIONBAR_UPDATE_STATE");
667 ActionBars:RegisterEvent("ACTIONBAR_SLOT_CHANGED");
668 ActionBars:RegisterEvent("ACTIONBAR_SHOWGRID");
669 ActionBars:RegisterEvent("ACTIONBAR_HIDEGRID");
670 ActionBars:RegisterEvent("SPELL_UPDATE_ICON");
671 ActionBars:RegisterEvent("SPELL_UPDATE_CHARGES");
672 ActionBars:RegisterEvent("SPELL_ACTIVATION_OVERLAY_GLOW_SHOW");
673 ActionBars:RegisterEvent("SPELL_ACTIVATION_OVERLAY_GLOW_HIDE");
674 ActionBars:RegisterEvent("UPDATE_VEHICLE_ACTIONBAR");
675 ActionBars:RegisterEvent("UPDATE_OVERRIDE_ACTIONBAR");
676 ActionBars:RegisterEvent("PLAYER_MOUNT_DISPLAY_CHANGED");
677 ActionBars:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED");
678 ActionBars:RegisterEvent("UNIT_ENTERED_VEHICLE");
679 ActionBars:RegisterEvent("UNIT_EXITED_VEHICLE");
680 ActionBars:RegisterEvent("PET_STABLE_UPDATE");
681 ActionBars:RegisterEvent("PET_STABLE_SHOW");
682 ActionBars:RegisterEvent("UPDATE_BINDINGS");
683 ActionBars:RegisterUnitEvent("UNIT_AURA", "player");
684 ActionBars:SetScript("OnEvent", function(self, event, arg1)