--[[ ############################################################################## _____/\\\\\\\\\\\____/\\\________/\\\__/\\\________/\\\__/\\\\\\\\\\\_ # ___/\\\/////////\\\_\/\\\_______\/\\\_\/\\\_______\/\\\_\/////\\\///__ # __\//\\\______\///__\//\\\______/\\\__\/\\\_______\/\\\_____\/\\\_____ # ___\////\\\__________\//\\\____/\\\___\/\\\_______\/\\\_____\/\\\_____ # ______\////\\\________\//\\\__/\\\____\/\\\_______\/\\\_____\/\\\_____ # _________\////\\\______\//\\\/\\\_____\/\\\_______\/\\\_____\/\\\_____ # __/\\\______\//\\\______\//\\\\\______\//\\\______/\\\______\/\\\_____ # _\///\\\\\\\\\\\/________\//\\\________\///\\\\\\\\\/____/\\\\\\\\\\\_# ___\///////////___________\///___________\/////////_____\///////////_# ############################################################################## S U P E R - V I L L A I N - U I By: Munglunch # ############################################################################## ########################################################## LOCALIZED LUA FUNCTIONS ########################################################## ]]-- local SV = select(2, ...) --[[ GLOBALS ]]-- local _G = _G; local unpack = _G.unpack; local select = _G.select; local pairs = _G.pairs; local ipairs = _G.ipairs; local type = _G.type; local tinsert = _G.tinsert; local string = _G.string; --TABLE local table = _G.table; local tsort = table.sort; local tconcat = table.concat; local tinsert = _G.tinsert; local tremove = _G.tremove; local SVLib = LibSuperVillain("Registry") --[[ ########################################################## Simple click2cast spell SpellBinder(sBinder by Fernir) ########################################################## ]]-- local ClickCastFrames do _G.ClickCastFrames = _G.ClickCastFrames or {} ClickCastFrames = _G.ClickCastFrames end local UnitParseListing = { "PlayerFrame", "PetFrame", "TargetFrame", "TargetFrameToT", "FocusFrame", "FocusFrameToT", "Boss1TargetFrame", "Boss2TargetFrame", "Boss3TargetFrame", "Boss4TargetFrame", "ArenaEnemyFrame1", "ArenaEnemyFrame2", "ArenaEnemyFrame3", "ArenaEnemyFrame4", "ArenaEnemyFrame5", "PartyMemberFrame1", "PartyMemberFrame2", "PartyMemberFrame3", "PartyMemberFrame4", "PartyMemberFrame5", "PartyMemberFrame1PetFrame", "PartyMemberFrame2PetFrame", "PartyMemberFrame3PetFrame", "PartyMemberFrame4PetFrame", "PartyMemberFrame5PetFrame", "CompactPartyFrameMemberSelf", "CompactPartyFrameMemberSelfBuff1", "CompactPartyFrameMemberSelfBuff2", "CompactPartyFrameMemberSelfBuff3", "CompactPartyFrameMemberSelfDebuff1", "CompactPartyFrameMemberSelfDebuff2", "CompactPartyFrameMemberSelfDebuff3", "CompactPartyFrameMember1Buff1", "CompactPartyFrameMember1Buff2", "CompactPartyFrameMember1Buff3", "CompactPartyFrameMember1Debuff1", "CompactPartyFrameMember1Debuff2", "CompactPartyFrameMember1Debuff3", "CompactPartyFrameMember2Buff1", "CompactPartyFrameMember2Buff2", "CompactPartyFrameMember2Buff3", "CompactPartyFrameMember2Debuff1", "CompactPartyFrameMember2Debuff2", "CompactPartyFrameMember2Debuff3", "CompactPartyFrameMember3Buff1", "CompactPartyFrameMember3Buff2", "CompactPartyFrameMember3Buff3", "CompactPartyFrameMember3Debuff1", "CompactPartyFrameMember3Debuff2", "CompactPartyFrameMember3Debuff3", "CompactPartyFrameMember4Buff1", "CompactPartyFrameMember4Buff2", "CompactPartyFrameMember4Buff3", "CompactPartyFrameMember4Debuff1", "CompactPartyFrameMember4Debuff2", "CompactPartyFrameMember4Debuff3", "CompactPartyFrameMember5Buff1", "CompactPartyFrameMember5Buff2", "CompactPartyFrameMember5Buff3", "CompactPartyFrameMember5Debuff1", "CompactPartyFrameMember5Debuff2", "CompactPartyFrameMember5Debuff3" } for _, gName in pairs(UnitParseListing) do local frame = _G[gName] if(frame) then ClickCastFrames[frame] = true end end local SpellBinder = CreateFrame("Frame", "SVUI_SpellBinder", SpellBookFrame, "ButtonFrameTemplate") SpellBinder:SetPoint("TOPLEFT", SpellBookFrame, "TOPRIGHT", 100, 0) SpellBinder:SetSize(300, 400) SpellBinder:Hide() SpellBinder.title = SpellBinder:CreateFontString(nil, "OVERLAY", "GameFontNormal") SpellBinder.title:SetPoint("TOP", SpellBinder, "TOP", 0, -5) SpellBinder.title:SetText("Click-Cast Bindings") SpellBinder.sbOpen = false SpellBinder.spellbuttons = {} SpellBinder.list = CreateFrame("ScrollFrame", "SVUI_SpellBinderSpellList", _G["SVUI_SpellBinderInset"], "UIPanelScrollFrameTemplate") SpellBinder.list.child = CreateFrame("Frame", nil, SpellBinder.list) SpellBinder.list:SetPoint("TOPLEFT", _G["SVUI_SpellBinderInset"], "TOPLEFT", 0, -5) SpellBinder.list:SetPoint("BOTTOMRIGHT", _G["SVUI_SpellBinderInset"], "BOTTOMRIGHT", -30, 5) SpellBinder.list:SetScrollChild(SpellBinder.list.child) --[[ ########################################################## SCRIPT HANDLERS ########################################################## ]]-- local BoundSpell_OnEnter = function(self) self.delete:GetNormalTexture():SetVertexColor(1, 0, 0) self:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8x8"}) self:SetBackdropColor(0.2, 0.2, 0.2, 0.7) end local BoundSpell_OnLeave = function(self) self.delete:GetNormalTexture():SetVertexColor(0.8, 0, 0) self:SetBackdrop(nil) end local Temp_OnUpdate = function(self) self:UpdateAll() if self.updated then self:UnregisterEvent("PLAYER_REGEN_ENABLED") end end local SpellBindTab_OnEnter = function(self) GameTooltip:ClearLines() GameTooltip:SetOwner(self, "ANCHOR_RIGHT") GameTooltip:AddLine("Click-Cast Binding") GameTooltip:Show() end local SpellBindTab_OnLeave = function(self) GameTooltip:Hide() end local SpellBindTab_OnShow = function(self) if SpellBinder:IsVisible() then self:SetChecked(true) end local num = GetNumSpellTabs() local lastTab = _G["SpellBookSkillLineTab"..num] self:ClearAllPoints() self:SetPoint("TOPLEFT", lastTab, "BOTTOMLEFT", 0, -17) self:SetScript("OnEnter", SpellBindTab_OnEnter) self:SetScript("OnLeave", SpellBindTab_OnLeave) end local SpellBindTab_OnClick = function(self) if InCombatLockdown() then SpellBinder:Hide() return end if SpellBinder:IsVisible() then SpellBinder:Hide() SpellBinder.sbOpen = false else SpellBinder:Show() SpellBinder.sbOpen = true end SpellBinder:ToggleButtons() end local SpellBindClose_OnClick = function(self) SpellBinder:Hide() SpellBinder.sbOpen = false SpellBinder:ToggleButtons() end local SpellBindMask_OnClick = function(self, button) if SpellBinder.sbOpen then local slot = SpellBook_GetSpellBookSlot(self:GetParent()) local spellname, subtype = GetSpellBookItemName(slot, SpellBookFrame.bookType) local texture = GetSpellBookItemTexture(slot, SpellBookFrame.bookType) if spellname ~= 0 and ((SpellBookFrame.bookType == BOOKTYPE_PET) or (SpellBookFrame.selectedSkillLine > 1)) then local originalbutton = button local modifier = "" if IsShiftKeyDown() then modifier = "Shift-"..modifier end if IsControlKeyDown() then modifier = "Ctrl-"..modifier end if IsAltKeyDown() then modifier = "Alt-"..modifier end if IsHarmfulSpell(slot, SpellBookFrame.bookType) then button = ("%s%d"):format("harmbutton", SecureButton_GetButtonSuffix(button)) originalbutton = "|cffff2222(harm)|r "..originalbutton else button = SecureButton_GetButtonSuffix(button) end for i, v in pairs(SV.cache.SpellBinder.spells) do if v.spell == spellname then return end end tinsert(SV.cache.SpellBinder.spells, {["id"] = slot, ["modifier"] = modifier, ["button"] = button, ["spell"] = spellname, ["rank"] = "", ["texture"] = texture, ["origbutton"] = originalbutton,}) SpellBinder:BuildSpells(false) end end end local SpellBindDelete_OnClick = function(self) local spell = self.spell for j, k in ipairs(SV.cache.SpellBinder.spells) do if k ~= spell.spell then k.checked = false _G[j.."_cbs"]:SetBackdropColor(0, 0, 0, 0) end end spell.checked = not spell.checked SpellBinder:DeleteSpell() end --[[ ########################################################## EVENT HANDLERS ########################################################## ]]-- local SpellBind_OnEvent = function(self) self:UpdateAll() end --[[ ########################################################## METHODS ########################################################## ]]-- function SpellBinder:BuildSpells(delete) if(not SV.cache.SpellBinder) then return end if(not SV.cache.SpellBinder.spells) then SV.cache.SpellBinder.spells = {} SV.cache.SpellBinder.frames = {} SV.cache.SpellBinder.keys = {} end local oldb, spellName local scroll = self.list.child scroll:SetPoint("TOPLEFT") scroll:SetSize(270, 300) if delete then local i = 1 while _G[i.."_cbs"] do _G[i.."_fs"]:SetText("") _G[i.."_texture"]:SetTexture(0,0,0,0) _G[i.."_cbs"].checked = false _G[i.."_cbs"]:ClearAllPoints() _G[i.."_cbs"]:Hide() i = i + 1 end end for i, spell in ipairs(SV.cache.SpellBinder.spells) do spellName = spell.spell if spellName then local bf = _G[i.."_cbs"] or CreateFrame("Button", i.."_cbs", scroll) spell.checked = spell.checked or false if i == 1 then bf:SetPoint("TOPLEFT", scroll, "TOPLEFT", 10, -10) bf:SetPoint("BOTTOMRIGHT", scroll, "TOPRIGHT", -10, -34) else bf:SetPoint("TOPLEFT", oldb, "BOTTOMLEFT", 0, -2) bf:SetPoint("BOTTOMRIGHT", oldb, "BOTTOMRIGHT", 0, -26) end bf:EnableMouse(true) bf.tex = bf.tex or bf:CreateTexture(i.."_texture", "OVERLAY") bf.tex:SetSize(22, 22) bf.tex:SetPoint("LEFT") bf.tex:SetTexture(spell.texture) bf.tex:SetTexCoord(0.1, 0.9, 0.1, 0.9) bf.delete = bf.delete or CreateFrame("Button", i.."_delete", bf) bf.delete:SetSize(16, 16) bf.delete:SetPoint("RIGHT") bf.delete:SetNormalTexture("Interface\\BUTTONS\\UI-GroupLoot-Pass-Up") bf.delete:GetNormalTexture():SetVertexColor(0.8, 0, 0) bf.delete:SetPushedTexture("Interface\\BUTTONS\\UI-GroupLoot-Pass-Up") bf.delete:SetHighlightTexture("Interface\\BUTTONS\\UI-GroupLoot-Pass-Up") bf.delete.spell = spell bf.delete:SetScript("OnClick", SpellBindDelete_OnClick) bf:SetScript("OnEnter", BoundSpell_OnEnter) bf:SetScript("OnLeave", BoundSpell_OnLeave) bf.fs = bf.fs or bf:CreateFontString(i.."_fs", "OVERLAY", "GameFontNormal") bf.fs:SetText(spell.modifier..spell.origbutton) bf.fs:SetPoint("RIGHT", bf.delete, "LEFT", -4, 0) for frame,_ in pairs(ClickCastFrames) do if frame and SV.cache.SpellBinder.frames[frame] then if frame:CanChangeAttribute() or frame:CanChangeProtectedState() then if frame:GetAttribute(spell.modifier.."type"..spell.button) ~= "menu" then --frame:RegisterForClicks("AnyDown") if spell.button:find("harmbutton") then frame:SetAttribute(spell.modifier..spell.button, spell.spell) frame:SetAttribute(spell.modifier.."type-"..spell.spell, "spell") frame:SetAttribute(spell.modifier.."spell-"..spell.spell, spell.spell) SV.cache.SpellBinder.keys[spell.modifier..spell.button] = spell.spell SV.cache.SpellBinder.keys[spell.modifier.."type-"..spell.spell] = "spell" SV.cache.SpellBinder.keys[spell.modifier.."spell-"..spell.spell] = spell.spell else frame:SetAttribute(spell.modifier.."type"..spell.button, "spell") frame:SetAttribute(spell.modifier.."spell"..spell.button, spell.spell) SV.cache.SpellBinder.keys[spell.modifier.."type"..spell.button] = "spell" SV.cache.SpellBinder.keys[spell.modifier.."spell"..spell.button] = spell.spell end end end end end bf:Show() oldb = bf end end end function SpellBinder:BuildList() if(SV.cache.SpellBinder and SV.cache.SpellBinder.frames) then for frame,_ in pairs(ClickCastFrames) do SV.cache.SpellBinder.frames[frame] = SV.cache.SpellBinder.frames[frame] or true end end end function SpellBinder:ToggleButtons() for i = 1, SPELLS_PER_PAGE do if(self.spellbuttons[i]) then self.spellbuttons[i]:Hide() if self.sbOpen and SpellBookFrame.bookType ~= BOOKTYPE_PROFESSION then local slot = SpellBook_GetSpellBookSlot(self.spellbuttons[i]:GetParent()) if slot then local spellname, subtype = GetSpellBookItemName(slot, SpellBookFrame.bookType) if spellname then self.spellbuttons[i]:Show() end end end end end self:BuildList() self:BuildSpells(true) if self:IsVisible() then self.tab:SetChecked(true) else self.tab:SetChecked(false) end end function SpellBinder:DeleteSpell() local count = table.getn(SV.cache.SpellBinder.spells) for i, spell in ipairs(SV.cache.SpellBinder.spells) do if spell.checked then for frame,_ in pairs(ClickCastFrames) do local f if frame and type(frame) == "table" then f = frame:GetName() end if f then if frame:CanChangeAttribute() or frame:CanChangeProtectedState() then if frame:GetAttribute(spell.modifier.."type"..spell.button) ~= "menu" then if spell.button:find("harmbutton") then frame:SetAttribute(spell.modifier..spell.button, nil) frame:SetAttribute(spell.modifier.."type-"..spell.spell, nil) frame:SetAttribute(spell.modifier.."spell-"..spell.spell, nil) else frame:SetAttribute(spell.modifier.."type"..spell.button, nil) frame:SetAttribute(spell.modifier.."spell"..spell.button, nil) end end end end end tremove(SV.cache.SpellBinder.spells, i) end end self:BuildSpells(true) end function SpellBinder:UpdateAll() if InCombatLockdown() then self:SheduleUpdate() return end self:BuildList() self:BuildSpells(true) end function SpellBinder:SheduleUpdate() self.updated = false if InCombatLockdown() then self:RegisterEvent("PLAYER_REGEN_ENABLED") self:SetScript("OnEvent", Temp_OnUpdate) else self:UpdateAll() end end --[[ ########################################################## SET HOOKS ########################################################## ]]-- local _hook_CreateFrame = function(self, name, parent, template) if template and template:find("SecureUnitButtonTemplate") then ClickCastFrames[_G[name]] = true end end local _hook_CompactUnitFrame_SetUpFrame = function(self, ...) ClickCastFrames[self] = true end local _hook_SpellBookFrame_OnUpdate = function(self) if SpellBinder.sbOpen then SpellBinder:ToggleButtons() end end local _hook_SpellBookFrame_OnHide = function(self) if not SpellBinder then return end SpellBinder:Hide() SpellBinder.sbOpen = false SpellBinder:ToggleButtons() end hooksecurefunc("CreateFrame", _hook_CreateFrame) hooksecurefunc("CompactUnitFrame_SetUpFrame", _hook_CompactUnitFrame_SetUpFrame) hooksecurefunc("SpellBookFrame_Update", _hook_SpellBookFrame_OnUpdate) hooksecurefunc(SpellBookFrame, "Hide", _hook_SpellBookFrame_OnHide) --[[ ########################################################## LOADER ########################################################## ]]-- SVUI_SpellBinderCloseButton:SetScript("OnClick", SpellBindClose_OnClick) SpellBinder.tab = CreateFrame("CheckButton", nil, _G["SpellBookSkillLineTab1"], "SpellBookSkillLineTabTemplate") SpellBinder.tab:SetScript("OnShow", SpellBindTab_OnShow) SpellBinder.tab:SetScript("OnClick", SpellBindTab_OnClick) SpellBinder.tab:Show() SpellBinder:RegisterEvent("GROUP_ROSTER_UPDATE") SpellBinder:RegisterEvent("PLAYER_ENTERING_WORLD") SpellBinder:RegisterEvent("PLAYER_LOGIN") SpellBinder:RegisterEvent("ZONE_CHANGED_NEW_AREA") SpellBinder:RegisterEvent("ZONE_CHANGED") local function LoadSpellBinder() SV.cache.SpellBinder = SV.cache.SpellBinder or {} SV.cache.SpellBinder.spells = SV.cache.SpellBinder.spells or {} SV.cache.SpellBinder.frames = SV.cache.SpellBinder.frames or {} SV.cache.SpellBinder.keys = SV.cache.SpellBinder.keys or {} SpellBinder:RemoveTextures() SVUI_SpellBinderInset:RemoveTextures() SpellBinder:SetPanelTemplate("Action") SpellBinder.Panel:SetPoint("TOPLEFT", -18, 0) SpellBinder.Panel:SetPoint("BOTTOMRIGHT", 0, 0) SpellBinder.list:RemoveTextures() SpellBinder.list:SetPanelTemplate("Inset") SpellBinder.tab:RemoveTextures() SpellBinder.tab:SetButtonTemplate() SpellBinder.tab:SetNormalTexture("Interface\\ICONS\\Achievement_Guild_Doctorisin") SpellBinder.tab:GetNormalTexture():ClearAllPoints() SpellBinder.tab:GetNormalTexture():SetPoint("TOPLEFT", 2, -2) SpellBinder.tab:GetNormalTexture():SetPoint("BOTTOMRIGHT", -2, 2) SpellBinder.tab:GetNormalTexture():SetTexCoord(0.1, 0.9, 0.1, 0.9) SpellBinder:BuildList() SpellBinder:BuildSpells(true) for i = 1, SPELLS_PER_PAGE do local parent = _G["SpellButton"..i] local button = CreateFrame("Button", "SpellButtonMask"..i, parent) button:SetID(parent:GetID()) button:RegisterForClicks("AnyDown") button:SetAllPoints(parent) button:SetScript("OnClick", SpellBindMask_OnClick) if(not button.shine) then button.shine = SpellBook_GetAutoCastShine() button.shine:Show() button.shine:SetParent(button) button.shine:SetAllPoints() end AutoCastShine_AutoCastStart(button.shine) button:Hide() SpellBinder.spellbuttons[i] = button end SpellBinder:SetScript("OnEvent", SpellBind_OnEvent) end SV:NewScript(LoadSpellBinder)