mirror of
https://github.com/OldManAlpha/Puppeteer.git
synced 2025-11-28 23:48:35 +00:00
644 lines
20 KiB
Lua
644 lines
20 KiB
Lua
PTUtil.SetEnvironment(Puppeteer)
|
|
local _G = getfenv(0)
|
|
local compost = AceLibrary("Compost-2.0")
|
|
local util = PTUtil
|
|
local colorize = util.Colorize
|
|
local GetSpellID = util.GetSpellID
|
|
local GetClass = util.GetClass
|
|
|
|
BindingClipboard = nil
|
|
|
|
function GetBindings()
|
|
return PTBindings.Loadouts[PTBindings.SelectedLoadout]
|
|
end
|
|
|
|
function GetBindingsFor(unit)
|
|
local bindings = GetBindings().Bindings
|
|
if not UnitCanAttack("player", unit) or bindings.UseFriendlyForHostile then
|
|
return bindings.Friendly
|
|
end
|
|
return bindings.Hostile
|
|
end
|
|
|
|
function GetBinding(friendlyOrHostile, modifier, button)
|
|
local bindings = GetBindings()
|
|
if bindings.UseFriendlyForHostile and friendlyOrHostile == "Hostile" then
|
|
friendlyOrHostile = "Friendly"
|
|
end
|
|
local l1 = bindings.Bindings[friendlyOrHostile]
|
|
if not l1 then
|
|
return
|
|
end
|
|
local l2 = l1[modifier]
|
|
if not l2 then
|
|
return
|
|
end
|
|
return l2[button]
|
|
end
|
|
|
|
function GetBindingFor(unit, modifier, button)
|
|
return GetBinding(not UnitCanAttack("player", unit) and "Friendly" or "Hostile", modifier, button)
|
|
end
|
|
|
|
function GetSelectedBindingsLoadoutName()
|
|
return PTBindings.SelectedLoadout
|
|
end
|
|
|
|
function SetSelectedBindingsLoadout(name)
|
|
PTBindings.SelectedLoadout = name
|
|
PTSettingsGui.LoadBindings()
|
|
InitBindingDisplayCache()
|
|
end
|
|
|
|
function GetBindingLoadouts()
|
|
return PTBindings.Loadouts
|
|
end
|
|
|
|
function NewBindingsLoadout(name, baseLoadout)
|
|
local loadouts = GetBindingLoadouts()
|
|
if loadouts[name] then
|
|
return
|
|
end
|
|
local loadout = baseLoadout and util.CloneTable(baseLoadout, true) or CreateEmptyBindingsLoadout()
|
|
loadouts[name] = loadout
|
|
end
|
|
|
|
function CreateEmptyBindingsLoadout()
|
|
return {
|
|
UseFriendlyForHostile = false,
|
|
Bindings = {
|
|
Friendly = {},
|
|
Hostile = {}
|
|
}
|
|
}
|
|
end
|
|
|
|
local SORT_DESCENDING = function(a, b) return a < b end
|
|
function GetBindingLoadoutNames()
|
|
local loadouts = GetBindingLoadouts()
|
|
local names = {}
|
|
for name, _ in pairs(loadouts) do
|
|
table.insert(names, name)
|
|
end
|
|
table.sort(names, SORT_DESCENDING)
|
|
return names
|
|
end
|
|
|
|
function PruneLoadout(loadout, copy)
|
|
if copy then
|
|
loadout = util.CloneTable(loadout, true)
|
|
end
|
|
for targetName, target in pairs(loadout.Bindings) do
|
|
for modifierName, modifier in pairs(target) do
|
|
for button, binding in pairs(modifier) do
|
|
local shouldRemove = PruneBinding(binding)
|
|
if shouldRemove then
|
|
modifier[button] = nil
|
|
end
|
|
end
|
|
if util.IsTableEmpty(modifier) then
|
|
target[modifierName] = nil
|
|
end
|
|
end
|
|
end
|
|
return loadout
|
|
end
|
|
|
|
function PruneBinding(binding)
|
|
if not binding.Type then
|
|
return true
|
|
end
|
|
if binding.Tooltip then
|
|
local tooltip = binding.Tooltip
|
|
if tooltip.Type ~= "DEFAULT" and (tooltip.Data == nil or tooltip.Data == "") then
|
|
tooltip.Type = nil
|
|
tooltip.Data = nil
|
|
end
|
|
|
|
if util.IsTableEmpty(tooltip) then
|
|
binding.Tooltip = nil
|
|
end
|
|
end
|
|
-- Empty spells are default and don't need to be stored
|
|
if binding.Type == "SPELL" and (not binding.Data or binding.Data == "") then
|
|
return true
|
|
end
|
|
if binding.Type == "MULTI" then
|
|
if binding.Data.Title == "" then
|
|
binding.Data.Title = nil
|
|
end
|
|
for _, subBinding in ipairs(binding.Data.Bindings) do
|
|
PruneBinding(subBinding)
|
|
end
|
|
end
|
|
end
|
|
|
|
local stringDataBindings = util.ToSet({"SPELL", "ACTION", "ITEM", "MACRO", "SCRIPT"})
|
|
function ExpandBinding(binding)
|
|
if not binding.Type then
|
|
binding.Type = "SPELL"
|
|
end
|
|
if not binding.Data then
|
|
if stringDataBindings[binding.Type] then
|
|
binding.Data = ""
|
|
elseif binding.Type == "MULTI" then
|
|
binding.Data = {Bindings = {}}
|
|
end
|
|
end
|
|
if not binding.Tooltip then
|
|
binding.Tooltip = {}
|
|
end
|
|
end
|
|
|
|
function LoadoutEquals(loadout1, loadout2, noCopy)
|
|
return util.TableEquals(PruneLoadout(loadout1, not noCopy), PruneLoadout(loadout2, not noCopy))
|
|
end
|
|
|
|
-- Returns a copy of the clipboard
|
|
function GetBindingClipboard()
|
|
return util.CloneTable(BindingClipboard, true)
|
|
end
|
|
|
|
function HasBindingClipboard()
|
|
return BindingClipboard ~= nil
|
|
end
|
|
|
|
-- Copies the binding to the clipboard
|
|
function SetBindingClipboard(binding)
|
|
BindingClipboard = util.CloneTable(binding, true)
|
|
end
|
|
|
|
|
|
function GetBindingTooltipText(binding)
|
|
if binding.Tooltip and binding.Tooltip.Type == "CUSTOM" then
|
|
return binding.Tooltip.Data
|
|
end
|
|
end
|
|
|
|
function GenerateDefaultBindings()
|
|
_G.PTBindings = {}
|
|
PTBindings["SelectedLoadout"] = "Primary"
|
|
local loadouts = {}
|
|
PTBindings["Loadouts"] = loadouts
|
|
loadouts["Primary"] = CreateEmptyBindingsLoadout()
|
|
|
|
local queuedBestSpellTasks = {}
|
|
local frame = CreateFrame("Frame")
|
|
frame:RegisterEvent("SPELLS_CHANGED")
|
|
frame:SetScript("OnEvent", function()
|
|
frame:UnregisterAllEvents()
|
|
for _, task in ipairs(queuedBestSpellTasks) do
|
|
task()
|
|
end
|
|
end)
|
|
|
|
local friendlyOrHostile = "Friendly"
|
|
local modifier
|
|
local function setContext(a, b)
|
|
friendlyOrHostile = a
|
|
modifier = b
|
|
end
|
|
local function setBinding(button, binding)
|
|
local bindings = GetBindings()
|
|
local l1 = bindings.Bindings[friendlyOrHostile]
|
|
if not l1 then
|
|
l1 = {}
|
|
bindings.Bindings[friendlyOrHostile] = l1
|
|
end
|
|
local l2 = l1[modifier]
|
|
if not l2 then
|
|
l2 = {}
|
|
l1[modifier] = l2
|
|
end
|
|
l2[button] = binding
|
|
end
|
|
local function setSpell(button, spell)
|
|
setBinding(button, {Type = "SPELL", Data = spell})
|
|
end
|
|
local function setBestSpell(button, spells)
|
|
local friendlyOrHostile = friendlyOrHostile
|
|
local modifier = modifier
|
|
table.insert(queuedBestSpellTasks, function()
|
|
for _, spell in ipairs(spells) do
|
|
if util.GetSpellID(spell) then
|
|
setContext(friendlyOrHostile, modifier)
|
|
setSpell(button, spell)
|
|
SetSelectedBindingsLoadout(GetSelectedBindingsLoadoutName())
|
|
return
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
local function setMulti(button, tooltip, spells)
|
|
local bindings = {}
|
|
for i, spell in ipairs(spells) do
|
|
bindings[i] = {Type = "SPELL", Data = spell}
|
|
end
|
|
setBinding(button, {
|
|
Type = "MULTI",
|
|
Tooltip = {
|
|
Type = "CUSTOM",
|
|
Data = tooltip
|
|
},
|
|
Data = {
|
|
Bindings = bindings
|
|
}
|
|
})
|
|
end
|
|
local function setAction(button, action)
|
|
setBinding(button, {Type = "ACTION", Data = action})
|
|
end
|
|
local function addHealerControls()
|
|
setContext("Friendly", "Shift")
|
|
setAction("LeftButton", "Target")
|
|
setAction("MiddleButton", "Role")
|
|
setAction("RightButton", "Menu")
|
|
end
|
|
|
|
local class = GetClass("player")
|
|
if class == "PRIEST" then
|
|
setContext("Friendly", "None")
|
|
setSpell("LeftButton", "Power Word: Shield")
|
|
setSpell("MiddleButton", "Renew")
|
|
setBestSpell("RightButton", {"Greater Heal", "Heal", "Lesser Heal"})
|
|
|
|
addHealerControls()
|
|
|
|
setContext("Friendly", "Control")
|
|
setMulti("LeftButton", "Buffs", {"Power Word: Fortitude", "Divine Spirit", "Shadow Protection"})
|
|
setSpell("RightButton", "Dispel Magic")
|
|
|
|
setContext("Hostile", "None")
|
|
setSpell("RightButton", "Dispel Magic")
|
|
|
|
setContext("Hostile", "Control")
|
|
setSpell("RightButton", "Dispel Magic")
|
|
elseif class == "DRUID" then
|
|
setContext("Friendly", "None")
|
|
setSpell("LeftButton", "Rejuvenation")
|
|
setSpell("RightButton", "Healing Touch")
|
|
|
|
addHealerControls()
|
|
|
|
setContext("Friendly", "Control")
|
|
setMulti("LeftButton", "Buffs", {"Mark of the Wild", "Thorns"})
|
|
setSpell("RightButton", "Remove Curse")
|
|
elseif class == "PALADIN" then
|
|
setContext("Friendly", "None")
|
|
setSpell("LeftButton", "Flash of Light")
|
|
setSpell("RightButton", "Holy Light")
|
|
|
|
addHealerControls()
|
|
|
|
setContext("Friendly", "Control")
|
|
setMulti("LeftButton", "Blessings", {"Blessing of Might", "Blessing of Wisdom", "Blessing of Salvation", "Blessing of Kings"})
|
|
setBestSpell("RightButton", {"Cleanse", "Purify"})
|
|
elseif class == "SHAMAN" then
|
|
setContext("Friendly", "None")
|
|
setBestSpell("LeftButton", {"Healing Wave", "Lesser Healing Wave"})
|
|
setSpell("RightButton", "Chain Heal")
|
|
|
|
addHealerControls()
|
|
|
|
setContext("Friendly", "Control")
|
|
setSpell("RightButton", "Cure Disease")
|
|
else
|
|
-- Non-healer classes can use this addon like traditional raid frames
|
|
setContext("Friendly", "None")
|
|
setAction("LeftButton", "Target")
|
|
setAction("MiddleButton", "Role")
|
|
setAction("RightButton", "Menu")
|
|
|
|
setContext("Hostile", "None")
|
|
setAction("LeftButton", "Target")
|
|
setAction("RightButton", "Menu")
|
|
end
|
|
end
|
|
|
|
PVPProtectOverrideTime = 0
|
|
|
|
PVPProtectMenu = PTGuiLib.Get("dropdown", UIParent)
|
|
PVPProtectMenu:SetOptions({
|
|
{
|
|
text = colorize("PVP Flag Protection", 0.3, 1, 0.3),
|
|
textHeight = 11,
|
|
notCheckable = true,
|
|
disabled = true
|
|
},
|
|
{
|
|
notCheckable = true,
|
|
disabled = true
|
|
},
|
|
{
|
|
text = colorize("Whoops, thanks for the save!", 0.8, 1, 0.8),
|
|
notCheckable = true,
|
|
func = function()
|
|
if UIErrorsFrame then
|
|
UIErrorsFrame:AddMessage(colorize("No problem, stay safe", 0.2, 1, 0.2))
|
|
end
|
|
end
|
|
},
|
|
{
|
|
notCheckable = true,
|
|
disabled = true
|
|
},
|
|
{
|
|
text = colorize("Disable protection for 5 min", 1, 0.8, 0.8),
|
|
notCheckable = true,
|
|
func = function()
|
|
PVPProtectOverrideTime = GetTime() + (5 * 60)
|
|
if UIErrorsFrame then
|
|
UIErrorsFrame:AddMessage(colorize("Protection disabled for 5 min", 1, 0, 0))
|
|
end
|
|
end
|
|
},
|
|
{
|
|
text = colorize("Disable protection this session", 1, 0.6, 0.6),
|
|
notCheckable = true,
|
|
func = function()
|
|
PVPProtectOverrideTime = GetTime() + (1000 * 60)
|
|
if UIErrorsFrame then
|
|
UIErrorsFrame:AddMessage(colorize("Protection disabled this session", 1, 0, 0))
|
|
end
|
|
end
|
|
}
|
|
})
|
|
|
|
local Sound_Disabled = function() end
|
|
|
|
function RunTargetedAction(binding, unit, actionFunc, mustTempTarget)
|
|
local hasTarget = UnitExists("target")
|
|
local changeTarget = (mustTempTarget or binding.TargetWhileCasting or PTOptions.TargetWhileCasting)
|
|
and not UnitIsUnit("target", unit)
|
|
|
|
if changeTarget then
|
|
local Sound_Enabled = PlaySound
|
|
_G.PlaySound = Sound_Disabled
|
|
TargetUnit(unit)
|
|
_G.PlaySound = Sound_Enabled
|
|
end
|
|
|
|
actionFunc()
|
|
|
|
local targetAfterCasting = binding.TargetAfterCasting or
|
|
(binding.TargetAfterCasting == nil and PTOptions.TargetAfterCasting)
|
|
if targetAfterCasting then
|
|
TargetUnit(unit)
|
|
elseif changeTarget then
|
|
if hasTarget then
|
|
TargetLastTarget()
|
|
else
|
|
local Sound_Enabled = PlaySound
|
|
_G.PlaySound = Sound_Disabled
|
|
ClearTarget()
|
|
_G.PlaySound = Sound_Enabled
|
|
end
|
|
end
|
|
end
|
|
|
|
local targetedSpell
|
|
local targetedSpellUnit
|
|
local function targetedCastFunc()
|
|
if util.IsSuperWowPresent() then
|
|
CastSpellByName(targetedSpell, targetedSpellUnit)
|
|
else
|
|
CastSpellByName(targetedSpell)
|
|
end
|
|
end
|
|
local function setupTargetedCast(spell, unit)
|
|
targetedSpell = spell
|
|
targetedSpellUnit = unit
|
|
return targetedCastFunc
|
|
end
|
|
function RunBinding_Spell(binding, unit)
|
|
local spell = binding.Data
|
|
|
|
if PTOptions.AutoResurrect and util.IsDeadFriend(unit) then
|
|
if PTUnit.Get(unit):HasBuffIDOrName(45568, "Holy Champion") and GetSpellID("Revive Champion")
|
|
and UnitAffectingCombat("player") then
|
|
spell = "Revive Champion"
|
|
else
|
|
spell = ResurrectionSpells[GetClass("player")] or spell
|
|
end
|
|
end
|
|
|
|
RunTargetedAction(binding, unit, setupTargetedCast(spell, unit), not util.IsSuperWowPresent())
|
|
end
|
|
|
|
function RunBinding_Action(binding, unit, unitFrame)
|
|
local action = ActionBindsMap[binding.Data]
|
|
if not action then
|
|
return
|
|
end
|
|
action.Script(unit, unitFrame)
|
|
end
|
|
|
|
function RunBinding_Item(binding, unit)
|
|
RunTargetedAction(binding, unit, function()
|
|
util.UseItem(binding.Data)
|
|
end, true)
|
|
end
|
|
|
|
function RunBinding_Macro(binding, unit)
|
|
RunTargetedAction(binding, unit, function()
|
|
util.RunMacro(binding.Data, unit)
|
|
end)
|
|
end
|
|
|
|
BindingScriptAPI = {
|
|
EnsureBuffs = function(unit, ...)
|
|
local unitData = PTUnit.Get(unit)
|
|
for _, buff in ipairs(arg) do
|
|
if not unitData:HasBuff(buff) then
|
|
if util.IsSuperWowPresent() then
|
|
CastSpellByName(buff, unit)
|
|
else
|
|
CastSpellByName(buff)
|
|
end
|
|
return buff
|
|
end
|
|
end
|
|
end
|
|
}
|
|
|
|
local preScript = "local unit = PTScriptUnit;"..
|
|
"local unresolvedUnit = PTScriptUnitUnresolved;"..
|
|
"local unitData = PTUnit.Get(unit);"..
|
|
"local unitFrame = PTScriptUnitFrame;"
|
|
BindingScriptCache = {}
|
|
BindingEnvironment = setmetatable({_G = _G, api = BindingScriptAPI}, {__index = PTUnitProxy or _G})
|
|
local targetedScript
|
|
local function targetedScriptFunc()
|
|
local ok, result = pcall(targetedScript)
|
|
if not ok then
|
|
DEFAULT_CHAT_FRAME:AddMessage(colorize("[Puppeteer] Error occurred while running custom script binding:", 1, 0.5, 0.5))
|
|
DEFAULT_CHAT_FRAME:AddMessage(colorize(result, 1, 0.5, 0.5))
|
|
end
|
|
end
|
|
local function setupTargetedScript(script)
|
|
targetedScript = script
|
|
return targetedScriptFunc
|
|
end
|
|
function RunBinding_Script(binding, unit, unitFrame)
|
|
local scriptString = binding.Data
|
|
if not BindingScriptCache[scriptString] then
|
|
local func, err = loadstring(preScript..scriptString, scriptString)
|
|
if not func then
|
|
DEFAULT_CHAT_FRAME:AddMessage(colorize("[Puppeteer] Failed to load binding function:", 1, 0.5, 0.5))
|
|
DEFAULT_CHAT_FRAME:AddMessage(colorize(err, 1, 0.5, 0.5))
|
|
return
|
|
end
|
|
setfenv(func, BindingEnvironment)
|
|
BindingScriptCache[scriptString] = func
|
|
end
|
|
BindingEnvironment.PTScriptUnit = PTUnitProxy and PTUnitProxy.CustomUnitGUIDMap[unit] or unit
|
|
BindingEnvironment.PTScriptUnitUnresolved = unit
|
|
BindingEnvironment.PTScriptUnitFrame = unitFrame
|
|
RunTargetedAction(binding, unit, setupTargetedScript(BindingScriptCache[scriptString]))
|
|
end
|
|
|
|
MultiMenu = PTGuiLib.Get("dropdown", UIParent)
|
|
|
|
local function RunMultiBindingElement(self)
|
|
local binding = self.binding
|
|
this.checked = not this.checked
|
|
self.checked = not self.checked -- Done to counter keepShownOnClick check toggle
|
|
if not binding.Data.KeepOpen then
|
|
MultiMenu:SetToggleState(false)
|
|
end
|
|
|
|
|
|
-- Hacks to make sure any dropdown menus that open while running the binding stay open
|
|
-- The root issue is that since the click function isn't finished running when another dropdown opens,
|
|
-- it tries to close the newly opened dropdown
|
|
local button
|
|
local buttonKeepShownOnClick -- The intended value
|
|
local realAddButton = _G.UIDropDownMenu_AddButton
|
|
if binding.Type ~= "SPELL" and binding.Type ~= "ITEM" then -- Spells and items can't possibly run into an issue
|
|
local selfIndex = util.IndexOf(self.siblings, self)
|
|
_G.UIDropDownMenu_AddButton = function(info, level)
|
|
realAddButton(info, level)
|
|
level = level or 1
|
|
if level ~= 1 then
|
|
return
|
|
end
|
|
local listFrame = _G["DropDownList"..level]
|
|
local index = listFrame.numButtons
|
|
|
|
if index == selfIndex then
|
|
button = _G[listFrame:GetName().."Button"..index]
|
|
buttonKeepShownOnClick = button.keepShownOnClick
|
|
button.keepShownOnClick = 1
|
|
end
|
|
end
|
|
end
|
|
|
|
-- It's rather important that we don't raise an error here
|
|
local ok, result = pcall(RunBinding, self.subBinding, self.unit, self.unitFrame)
|
|
if not ok then
|
|
DEFAULT_CHAT_FRAME:AddMessage("Error while running binding: "..result)
|
|
end
|
|
|
|
-- Restore state to what it should be
|
|
_G.UIDropDownMenu_AddButton = realAddButton
|
|
if button then
|
|
util.RunLater(function()
|
|
button.keepShownOnClick = buttonKeepShownOnClick
|
|
if button.checked then
|
|
_G[button:GetName().."Check"]:Hide()
|
|
button.checked = nil
|
|
else
|
|
_G[button:GetName().."Check"]:Show()
|
|
button.checked = 1
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
|
|
function RunBinding_Multi(binding, unit, unitFrame)
|
|
if MultiMenu.Options ~= nil then
|
|
compost:Reclaim(MultiMenu.Options, 1)
|
|
end
|
|
MultiMenu:SetToggleState(false)
|
|
local options = compost:GetTable()
|
|
local title = binding.Data.Title ~= "" and binding.Data.Title -- or GetBindingTooltipText(binding)
|
|
if title then
|
|
local titleColor = binding.Data.TitleColor or BindTypeTooltipColors[binding.Type]
|
|
table.insert(options, compost:AcquireHash(
|
|
"text", colorize(title, titleColor),
|
|
"isTitle", true,
|
|
"notCheckable", true,
|
|
"textHeight", 12
|
|
))
|
|
end
|
|
local list = binding.Data.Bindings
|
|
for _, subBinding in ipairs(list) do
|
|
local subBinding = subBinding
|
|
local display = compost:GetTable()
|
|
_UpdateBindingDisplay(subBinding, display)
|
|
table.insert(options, compost:AcquireHash(
|
|
"text", display.Normal,
|
|
"notCheckable", true,
|
|
"keepShownOnClick", true, -- This is used so that dropdowns shown during the func call don't get immediately hidden
|
|
"func", RunMultiBindingElement,
|
|
"binding", binding,
|
|
"subBinding", subBinding,
|
|
"unit", unit,
|
|
"unitFrame", unitFrame
|
|
))
|
|
compost:Reclaim(display)
|
|
end
|
|
if binding.Data.KeepOpen then
|
|
table.insert(options, compost:AcquireHash(
|
|
"notCheckable", true,
|
|
"disabled", true
|
|
))
|
|
table.insert(options, compost:AcquireHash(
|
|
"text", colorize("Close Menu", NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b),
|
|
"notCheckable", true,
|
|
"keepShownOnClick", true,
|
|
"func", function(self)
|
|
MultiMenu:SetToggleState(false)
|
|
end
|
|
))
|
|
end
|
|
MultiMenu:SetOptions(options)
|
|
local container = unitFrame:GetRootContainer()
|
|
MultiMenu:SetToggleState(true, container, container:GetWidth(), container:GetHeight())
|
|
MultiMenu:SetKeepOpen(true)
|
|
PlaySound("GAMESPELLBUTTONMOUSEDOWN")
|
|
end
|
|
|
|
function RunBinding(binding, unit, unitFrame)
|
|
if binding.Data == nil then
|
|
return
|
|
end
|
|
local targetCastable = UnitExists(unit) and UnitIsConnected(unit) and UnitIsVisible(unit)
|
|
local bindingType = binding.Type
|
|
if bindingType == "SPELL" then
|
|
if targetCastable then
|
|
if PTOptions.PVPFlagProtection and not IsInInstance() and UnitIsPVP(unit) and UnitIsPlayer(unit)
|
|
and not UnitIsPVP("player") and PVPProtectOverrideTime < GetTime() then
|
|
PVPProtectMenu:SetToggleState(false)
|
|
local frame = unitFrame:GetRootContainer()
|
|
PVPProtectMenu:SetToggleState(true, frame, frame:GetWidth(), frame:GetHeight())
|
|
PVPProtectMenu:SetKeepOpen(true)
|
|
PlaySound("igMainMenuOpen")
|
|
return
|
|
end
|
|
RunBinding_Spell(binding, unit)
|
|
end
|
|
elseif bindingType == "ACTION" then
|
|
RunBinding_Action(binding, unit, unitFrame)
|
|
elseif bindingType == "ITEM" then
|
|
if targetCastable then
|
|
RunBinding_Item(binding, unit)
|
|
end
|
|
elseif bindingType == "MACRO" then
|
|
RunBinding_Macro(binding, unit)
|
|
elseif bindingType == "SCRIPT" then
|
|
RunBinding_Script(binding, unit, unitFrame)
|
|
elseif bindingType == "MULTI" then
|
|
RunBinding_Multi(binding, unit, unitFrame)
|
|
end
|
|
end |