Compare with Previous | Blame | View Log
-- TODO: save/restore skill filters if window is opened local f = CreateFrame("Frame", "AraSkills", UIParent) local g = CreateFrame("Frame", nil, UIParent) local e = CreateFrame"Frame" local dropdown = CreateFrame("Frame", "AraSkillsDD", nil, "UIDropDownMenuTemplate") local dropdown_init, tipShown, nbEntries, Block_OnEnter local config, realm, options, c local playerName, realmName = GetUnitName"player", GetRealmName() local CDs, shortcuts, workingFrame, prevAltSkill local BUTTON_HEIGHT, ICON_SIZE, GAP, TEXT_OFFSET = 17, 15, 10, 4 local PANEL, PROFESSION, COMBAT_SKILL, LINK, SECONDARY, SPELL_ID = 1, 2, 4, 8, 16, 256 local L = setmetatable( _G.ABTS_T or {}, { __index = function(t,k) return k end, __call = function(t,k) return t[k] end } ) local bit_band, date, format, strmatch, tonumber, wipe, ipairs, tremove, GetSkillLineInfo, GetSpellInfo, GetTradeSkillInfo, GetTradeSkillRecipeLink, tip = bit.band, date, format, strmatch, tonumber, wipe, ipairs, tremove, GetSkillLineInfo, GetSpellInfo, GetTradeSkillInfo, GetTradeSkillRecipeLink local skills = { [L.Alchemy]= PROFESSION + 2259*SPELL_ID + PANEL + LINK, [L.Blacksmithing]= PROFESSION + 2018*SPELL_ID + PANEL + LINK, [L.Cooking]= PROFESSION + 2550*SPELL_ID + PANEL + LINK + SECONDARY, -- campfire [L.Enchanting]= PROFESSION + 7411*SPELL_ID + PANEL + LINK, -- d/e [L.Engineering]= PROFESSION + 4036*SPELL_ID + PANEL + LINK, [L"First Aid"]= PROFESSION + 3273*SPELL_ID + PANEL + LINK + SECONDARY, [L.Fishing]= PROFESSION + 7620*SPELL_ID + SECONDARY, [L.Herbalism]= PROFESSION + 2366*SPELL_ID, -- track herbs [L.Inscription]= PROFESSION + 45357*SPELL_ID + PANEL + LINK, -- mill [L.Jewelcrafting]= PROFESSION + 25229*SPELL_ID + PANEL + LINK, -- prospect [L.Leatherworking]= PROFESSION + 2108*SPELL_ID + PANEL + LINK, [L.Lockpicking]= PROFESSION + 1804*SPELL_ID + SECONDARY, [L.Runeforging]= PROFESSION + 53428*SPELL_ID + PANEL + SECONDARY, [L.Skinning]= PROFESSION + 8613*SPELL_ID, [L.Smelting]= PROFESSION + 2580*SPELL_ID + PANEL, -- track minerals (icons: 2575=mining, 2580=smelting) [L.Tailoring]= PROFESSION + 3908*SPELL_ID + PANEL + LINK, [L.Axes]= COMBAT_SKILL, [L.Bows]= COMBAT_SKILL, [L.Crossbows]= COMBAT_SKILL, [L.Daggers]= COMBAT_SKILL, [L.Defense]= COMBAT_SKILL, [L.Guns]= COMBAT_SKILL, [L.Maces]= COMBAT_SKILL, [L.Polearms]= COMBAT_SKILL, [L.Staves]= COMBAT_SKILL, [L.Swords]= COMBAT_SKILL, [L.Thrown]= COMBAT_SKILL, [L"Two-Handed Swords"]= COMBAT_SKILL, [L"Two-Handed Axes"]= COMBAT_SKILL, [L"Two-Handed Maces"]= COMBAT_SKILL, [L.Unarmed]= COMBAT_SKILL, [L.Wands]= COMBAT_SKILL, None = 0 } local altNames = { [L.Mining] = L.Smelting, [L.RuneforgingDN] = L.Runeforging, } local altIcons = { [L.Axes]= "Interface\\Icons\\INV_Axe_44", [L.Bows]= "Interface\\Icons\\INV_Weapon_Bow_05", [L.Crossbows]= "Interface\\Icons\\INV_Weapon_Crossbow_01", [L.Daggers]= "Interface\\Icons\\Ability_SteelMelee", [L.Defense]= "Interface\\Icons\\INV_Shield_09", [L.Guns]= "Interface\\Icons\\INV_Weapon_Rifle_01", [L.Maces]= "Interface\\Icons\\INV_Mace_04", [L.Polearms]= "Interface\\Icons\\INV_Spear_06", [L.Staves]= "Interface\\Icons\\INV_Staff_08", [L.Swords]= "Interface\\Icons\\INV_Sword_14", [L.Thrown]= "Interface\\Icons\\Ability_Throw", [L"Two-Handed Axes"]= "Interface\\Icons\\INV_Axe_09", [L"Two-Handed Maces"]= "Interface\\Icons\\INV_Hammer_16", [L"Two-Handed Swords"]= "Interface\\Icons\\INV_Sword_27", [L.Unarmed]= "Interface\\Icons\\Ability_Warrior_SecondWind", [L.Wands]= "Interface\\Icons\\INV_Wand_05", } local groupIcons = { ["Transmutes"] = "Interface\\Icons\\Spell_Nature_ElementalPrecision_2" } local HOUR, DAY = 3600, 86400 local TRANSMUTE_G1 = { skill= L.Alchemy, CD=20*HOUR, group= "Transmutes" } local watchedCDs = { [11479]= TRANSMUTE_G1, -- Iron to Gold [11480]= TRANSMUTE_G1, -- Mithril to Truesilver [60350]= TRANSMUTE_G1, -- Titanium [17559]= TRANSMUTE_G1, -- Air to Fire [17566]= TRANSMUTE_G1, -- Earth to Life [17561]= TRANSMUTE_G1, -- Earth to Water [17560]= TRANSMUTE_G1, -- Fire to Earth [17565]= TRANSMUTE_G1, -- Life to Earth [17563]= TRANSMUTE_G1, -- Undeath to Earth [17562]= TRANSMUTE_G1, -- Water to Air [17564]= TRANSMUTE_G1, -- Water to Undeath [28566]= TRANSMUTE_G1, -- Primal Air to Fire [28585]= TRANSMUTE_G1, -- Primal Earth to Life [28567]= TRANSMUTE_G1, -- Primal Earth to Water [28568]= TRANSMUTE_G1, -- Primal Fire to Earth [28583]= TRANSMUTE_G1, -- Primal Fire to Mana [28584]= TRANSMUTE_G1, -- Primal Life to Earth [28582]= TRANSMUTE_G1, -- Primal Mana to Fire [28580]= TRANSMUTE_G1, -- Primal Shadow to Water [28569]= TRANSMUTE_G1, -- Primal Water to Air [28581]= TRANSMUTE_G1, -- Primal Water to Shadow [53777]= TRANSMUTE_G1, -- Eternal Air to Earth [52776]= TRANSMUTE_G1, -- Eternal Air to Water [53781]= TRANSMUTE_G1, -- Eternal Earth to Air [53782]= TRANSMUTE_G1, -- Eternal Earth to Shadow [53775]= TRANSMUTE_G1, -- Eternal Fire to Life [53774]= TRANSMUTE_G1, -- Eternal Fire to Water [53773]= TRANSMUTE_G1, -- Eternal Life to Fire [53771]= TRANSMUTE_G1, -- Eternal Life to Shadow [54020]= TRANSMUTE_G1, -- Eternal Might [53779]= TRANSMUTE_G1, -- Eternal Shadow to Earth [52780]= TRANSMUTE_G1, -- Eternal Shadow to Life [53783]= TRANSMUTE_G1, -- Eternal Water to Air [53784]= TRANSMUTE_G1, -- Eternal Water to Fire [28027]= { skill= L.Enchanting, CD= 2*DAY }, -- Prismatic Sphere [28028]= { skill= L.Enchanting, CD= 2*DAY }, -- Void Sphere [47280]= { skill= L.Jewelcrafting, CD= 20*HOUR }, -- Brilliant Glass [62242]= { skill= L.Jewelcrafting, CD= 20*HOUR }, -- Icy Prism -- NEW 3.0.8 [56002]= { skill= L.Tailoring, CD= 3*DAY+20*HOUR }, -- Ebonweave [56003]= { skill= L.Tailoring, CD= 3*DAY+20*HOUR }, -- Spellweave [56001]= { skill= L.Tailoring, CD= 3*DAY+20*HOUR }, -- Moonshroud [61288]= { skill= L.Inscription, CD= 20*HOUR }, -- Minor Glyph RS [61177]= { skill= L.Inscription, CD= 20*HOUR }, -- Major Glyph RS [55208]= { skill= L.Smelting, CD= 20*HOUR }, -- Smelt Titansteel [60893]= { skill= L.Alchemy, CD= 2*DAY+20*HOUR }, -- Alchemy Research } local watchedIndex, watchedSpell, watchedID, watchedIcon local orgDoTradeSkill = _G.DoTradeSkill function DoTradeSkill(index, ...) watchedID = tonumber( strmatch( GetTradeSkillRecipeLink(index), "enchant:(%d+)" ) ) if watchedCDs[watchedID] then watchedIndex, watchedSpell, watchedIcon = index, GetTradeSkillInfo(index), GetTradeSkillIcon(index) f:RegisterEvent"UNIT_SPELLCAST_SUCCEEDED" f:RegisterEvent"UNIT_SPELLCAST_STOP" end return orgDoTradeSkill(index, ...) end function f:UNIT_SPELLCAST_STOP(event, unit, spell) if unit ~= "player" or spell ~= watchedSpell then return end self:UnregisterEvent"UNIT_SPELLCAST_SUCCEEDED" self:UnregisterEvent"UNIT_SPELLCAST_STOP" if event ~= "UNIT_SPELLCAST_SUCCEEDED" then return end local cd = watchedCDs[watchedID] char[watchedID] = time() + cd.CD if cd.group then config.names[cd.group] = watchedID end config.icons[cd.group or watchedID] = watchedIcon if config.displayCDs then e.timer = 0 end if tipShown then Block_OnEnter(tipShown) end end f.UNIT_SPELLCAST_SUCCEEDED = f.UNIT_SPELLCAST_STOP local tables = {} local function new(...) local t = tremove(tables) or {} for i = 1, select("#", ...), 2 do local k, v = select(i, ...) t[k] = v end return t end local function del(t) tables[#tables+1] = wipe(t) end local md, mx, xx, dd = 20*HOUR, 3*DAY+20*HOUR, { 86400, 3600, 60, 1 }, { L.d, L.h, L.m, L.s } local function SecondsToTime(s) local p = s<md and s/md*.5 or s<mx and (s-md)/(mx-md)*.5+.5 or 1 local i = s>=86400 and 1 or s>=3600 and 2 or 3 return format( "|cff%.2x%.2x40%i%s %.2i%s|r", p<.5 and 64+p*382 or 255, p<.5 and 255 or 446-p*382, floor(s/xx[i]), dd[i], floor((s%xx[i])/xx[i+1]), dd[i+1] ) end local function ColorCurMax(cur,max,isProfession) local pMax = isProfession and min(max/450,1) or 1 local pCur = isProfession and 1-min(sqrt(max-cur)/10,1) or 2/sqrt(max-cur+4) return format( "|cff%.2x%.2x00%.3i|r / |cff%.2x%.2x00%.3i|r", pCur<.5 and 255 or 510-pCur*510, pCur<.5 and pCur*510 or 255, cur, pMax<.5 and 255 or 510-pMax*510, pMax<.5 and pMax*510 or 255, max ) end local function SortSkills(a, b) if not a.isProfession == not b.isProfession then if a.primary == b.primary then return a.displayName < b.displayName else return a.primary end else return a.isProfession end end local function SortCooldowns(a, b) if a.group and a.group == b.group then return a.timeLeft > b.timeLeft else return a.name < b.name end end local function SortShortcuts(a, b) if a.skill == b.skill then return a.name < b.name else return a.skill < b.skill end end local function SortAltSkills(a, b) local primA = bit_band( skills[a], SECONDARY ) == 0 local primB = bit_band( skills[b], SECONDARY ) == 0 if primA == primB then return a < b else return primA end end local function SortAlts(a, b) return a.name < b.name end local function UpdateText() f.block.icon = select(3, GetSpellInfo(char.skill or 0)) or "Interface\\Icons\\Achievement_Halloween_Witch_01" if not config.displayCDs then f.block.text = " " .. (char.skill or _G.TRADE_SKILLS) end end local orgAbandonSkill = _G.AbandonSkill function AbandonSkill(...) if char.skill == GetSkillLineInfo(...) then char.skill=nil UpdateText() end return orgAbandonSkill(...) end local function CreateHL(frame) local hl = frame:CreateTexture() hl:SetTexture"Interface\\QuestFrame\\UI-QuestLogTitleHighlight" hl:SetBlendMode"ADD" hl:SetAlpha(0) return hl end local highlight = CreateHL(f) local altLight = CreateHL(g) local function Tradeskill_OnClick(button, click) if IsShiftKeyDown() and bit_band( skills[button.skill], LINK ) > 0 then f.getLink = true if TradeSkillFrame and TradeSkillFrame:IsShown() then f.keepOpen = true CloseTradeSkill() end f:RegisterEvent"TRADE_SKILL_SHOW" elseif click == "RightButton" then f.learnCD = true if TradeSkillFrame and TradeSkillFrame:IsShown() then f.keepOpen = true CloseTradeSkill() end f:RegisterEvent"TRADE_SKILL_SHOW" elseif click == "MiddleButton" then char.show[button.skill] = not char.show[button.skill] return Block_OnEnter(tipShown) elseif bit_band( skills[button.skill], PANEL ) > 0 then char.skill = button.skill UpdateText() button.fontLeft:SetTextColor(unpack(config.colors.selected)) if f.selected and f.selected ~= button then f.selected.fontLeft:SetTextColor(unpack(config.colors.activeName)) end f.selected = button else return end CastSpellByName(button.skill) end local function Cooldown_OnClick(button, click) local group = watchedCDs[button.spellID].group if click == "MiddleButton" then local char = realm[button.owner] if group then -- remove group for k, v in next, watchedCDs do if v.group == group then char[k] = nil end end else char[button.spellID] = nil end Block_OnEnter(tipShown) elseif click == "LeftButton" and IsControlKeyDown() then f.alias, f.aliasID = button.fontLeft:GetText(), group or button.spellID StaticPopup_Show("SET_ALIAS", config.names[button.spellID] or group) else f.doTradeSkill = click == "LeftButton" and not IsModifierKeyDown() f.searchedSpellID = button.spellID if TradeSkillFrame and TradeSkillFrame:IsShown() then CloseTradeSkill() end f:RegisterEvent"TRADE_SKILL_SHOW" CastSpellByName(button.skill) end end local function Shortcut_OnClick(button, click) if IsControlKeyDown() then f.alias, f.aliasID = button.fontLeft:GetText(), button.spellID StaticPopup_Show("SET_ALIAS", config.names[button.spellID]) elseif click == "MiddleButton" then char.shortcuts[button.spellID] = nil Block_OnEnter(tipshown) else f.doTradeSkill = click == "LeftButton" and not IsModifierKeyDown() f.searchedSpellID = button.spellID f.shortcut = true if TradeSkillFrame and TradeSkillFrame:IsShown() then CloseTradeSkill() end f:RegisterEvent"TRADE_SKILL_SHOW" CastSpellByName(button.skill) end end local function Link_OnClick(button, click) if not button.link then return end if IsModifierKeyDown() then if not ChatEdit_InsertLink(button.link) then ChatFrameEditBox:Show() ChatEdit_InsertLink(button.link) end elseif click == "LeftButton" then if button.skill == prevAltSkill and TradeSkillFrame and TradeSkillFrame:IsShown() then return CloseTradeSkill() end prevAltSkill = button.skill SetItemRef(button.link:match"|H([^|]+)") end end local function ProfessionsBook_OnClick() ProfessionsBook:ShowFrame() end local function Alt_OnEnter(self) if self and self.light then altLight:SetAllPoints(self) altLight:SetAlpha(1) if config.hideTips then return end local hasLink = bit_band( skills[self.skill], LINK ) > 0 if not( self.link or hasLink ) then return end tip:SetOwner(g, "ANCHOR_NONE") local showRight = f:GetCenter() > UIParent:GetWidth()/2 and "RIGHT" or "LEFT" local showBelow = select(2, g:GetCenter()) > UIParent:GetHeight()/2 and "TOP" or "BOTTOM" tip:SetPoint(showBelow..showRight, g, (showBelow == "TOP" and "BOTTOM" or "TOP")..showRight ) tip:AddLine(L.Hints) if self.link then tip:AddLine(L"|cffff8020Click|r to toggle panel.", .2,1,.2) tip:AddLine(L"|cffff8020Shift+Click|r to link in chat.", .2,1,.2) elseif hasLink then tip:AddLine(L"No link available. Open a character\ntradeskill panel to be able to access\nit from your other characters.", 1, .6, .2) end tip:Show() end end local function Alt_OnLeave(self) altLight:ClearAllPoints() if self and self.light then altLight:SetAlpha(0) tip:Hide() end if not MouseIsOver(f) and not MouseIsOver(g) then tipShown = nil f:Hide() g:Hide() tip:Hide() end end local function Menu_OnEnter(self) if self and self.light then highlight:SetAllPoints(self) highlight:SetAlpha(1) if config.hideTips or self.skill == "None" then return end tip:SetOwner(f, "ANCHOR_NONE") local showRight = f:GetCenter() > UIParent:GetWidth()/2 and "LEFT" or "RIGHT" local showBelow = select(2, f:GetCenter()) > UIParent:GetHeight()/2 and "TOP" or "BOTTOM" tip:SetPoint(showBelow..showRight, f, (showBelow == "TOP" and "BOTTOM" or "TOP")..showRight ) tip:AddLine(L.Hints) if self.shortcut then tip:AddLine(L"|cffff8020Click|r to craft.", .2,1,.2) tip:AddLine(L"|cffff8020Right-Click|r to show in panel.", .2,1,.2) tip:AddLine(L"|cffff8020Control+Click|r to set an alias.", .2, 1, .2) elseif self.spellID then tip:AddDoubleLine(L"Belongs to:", self.owner, 1,1,1,1,1,1) if self.owner == playerName and self.ready then tip:AddLine(L"|cffff8020Click|r to craft.", .2,1,.2) tip:AddLine(L"|cffff8020Right-Click|r to show CD in panel.", .2,1,.2) elseif char.show[watchedCDs[self.spellID].skill] ~= nil then tip:AddLine(L"|cffff8020Click|r to show CD in panel.", .2,1,.2) end tip:AddLine(L"|cffff8020Control+Click|r to set an alias.", .2, 1, .2) else local hasPanel = bit_band( skills[self.skill], PANEL ) > 0 local hasLink = bit_band( skills[self.skill], LINK ) > 0 if hasPanel then tip:AddLine(L"|cffff8020Click|r to toggle panel.", .2,1,.2) end if hasLink then tip:AddLine(L"|cffff8020Shift+Click|r to link in chat.", .2,1,.2) end if hasPanel then tip:AddLine(L"|cffff8020Right-Click|r to scan for CDs.", .2,1,.2) end end tip:AddLine(L"|cffff8020Middle-Click|r to remove from list.", .2, 1, .2) tip:Show() end end local function Menu_OnLeave(self) highlight:ClearAllPoints() if self and self.light then highlight:SetAlpha(0) tip:Hide() end if not MouseIsOver(f) and ( InCombatLockdown() or not MouseIsOver(g) ) then tipShown = nil f:Hide() g:Hide() tip:Hide() end end local metatable = { __index = function(table, key) local button = CreateFrame("Button", nil, workingFrame) rawset(table, key, button) button:RegisterForClicks"AnyUp" button:SetHeight(BUTTON_HEIGHT) button:SetPoint("TOPLEFT", workingFrame, "TOPLEFT", GAP, BUTTON_HEIGHT * (1-key) - GAP) button:SetScript("OnEnter", workingFrame == f and Menu_OnEnter or Alt_OnEnter) button:SetScript("OnLeave", workingFrame == f and Menu_OnLeave or Alt_OnLeave) button.icon = button:CreateTexture(nil, "OVERLAY") button.icon:SetWidth(ICON_SIZE) button.icon:SetHeight(ICON_SIZE) button.icon:SetPoint("LEFT", button, "LEFT") button.fontLeft = button:CreateFontString(nil, "OVERLAY", "SystemFont_Shadow_Med1") button.fontLeft:SetPoint("LEFT", button, "LEFT", ICON_SIZE + TEXT_OFFSET, 0) button.fontRight = button:CreateFontString(nil, "OVERLAY", "SystemFont_Shadow_Med1") button.fontRight:SetPoint("RIGHT", button, "RIGHT") return button end } local buttons = setmetatable( {}, metatable ) local altButtons = setmetatable( {}, metatable ) local function AddEntry( buttons, icon, leftText, leftTextColor, rightText, rightTextColor, highlight ) nbEntries = nbEntries + 1 local button = buttons[nbEntries] button.icon:SetTexture(icon or "") if icon then button.icon:SetTexCoord(0.075, 0.925, 0.075, 0.925) end button.fontLeft:SetText(leftText or "") if leftTextColor then button.fontLeft:SetTextColor(unpack(leftTextColor)) end button.fontRight:SetText(rightText or "") if rightTextColor then button.fontRight:SetTextColor(unpack(rightTextColor)) end button.light = highlight button:Show() return button, ICON_SIZE + TEXT_OFFSET + (leftText and button.fontLeft:GetStringWidth() or 0), rightText and button.fontRight:GetStringWidth() or 0 end local function UpdateCDs() local readyCDs = 0 local temp = new() local dups = new() local now = time() for i, v in next, CDs do del(v) CDs[i] = nil end for char, data in next, realm do for spellID, expireTime in next, data do if type(spellID)=="number" then local cd = watchedCDs[spellID] if cd then temp[#temp+1] = new( "name", cd.group and (config.aliases[cd.group] or cd.group) or config.aliases[spellID] or config.names[spellID] or GetSpellInfo(spellID), "timeLeft", expireTime-now, "char", char, "spellID", spellID, "skill", cd.skill, "group", cd.group) end end end end sort(temp, SortCooldowns) for i=1, #temp do local cd = temp[i] if not dups[cd.group] then CDs[#CDs+1] = cd if cd.timeLeft <= 0 then readyCDs = readyCDs + 1 end end if cd.group then dups[cd.group] = true end end del(temp) del(dups) if config.displayCDs then -- local perc = readyCDs/totalCDs -- f.block.text = format(" |cff%.2x%.2x00%i/%i|r CD%s", perc<.5 and 255 or 510-perc*510, perc<.5 and perc*510 or 255, readyCDs, totalCDs, totalCDs>0 and "s" or "") f.block.text = format(" %i/%i CD%s", readyCDs, #CDs, #CDs>1 and "s" or "") end end local function SetMainPoint() end local function ShowAlts() workingFrame = g nbEntries = 0 altLight:SetVertexColor(unpack(config.colors.highlight)) local firstEntry, button = true local itemLeftWidth, itemRightWidth, colRightWidth, colLeftWidth = 0, 0, 0, 0 local list, subList = new(), new() for charName, charData in next, realm do if charName ~= playerName and charData.curSkills and next(charData.curSkills) then list[#list+1] = new("name",charName,"curSkills",charData.curSkills,"maxSkills",charData.maxSkills,"links",charData.links) end end sort(list,SortAlts) for _, char in ipairs(list) do if firstEntry then firstEntry = false else AddEntry(altButtons) end AddEntry( altButtons, "", char.name, config.colors.header ) for skill, value in next, char.maxSkills do if value > 1 then subList[#subList+1] = skill end end -- sort(subList) sort(subList, SortAltSkills) for _, skill in ipairs(subList) do local bitSkill = skills[skill] if not config.primaryOnly or bit_band(bitSkill, SECONDARY) == 0 then local hasLink = bit_band(bitSkill, LINK) > 0 local color = hasLink and config.colors.activeName or config.colors.infoName local icon = select(3,GetSpellInfo(floor(bitSkill/SPELL_ID))) local strValues = ColorCurMax( char.curSkills[skill], char.maxSkills[skill], true ) button, itemLeftWidth, itemRightWidth = AddEntry( altButtons, icon, skill, color, strValues, nil, hasLink) button:SetScript("OnClick", Link_OnClick) button.link = char.links and char.links[skill] button.skill = skill if itemLeftWidth > colLeftWidth then colLeftWidth = itemLeftWidth + GAP end if itemRightWidth > colRightWidth then colRightWidth = itemRightWidth end end end wipe(subList) end del(list) del(subList) g:Show() if _G.Skinner then _G.Skinner:applySkin(g) end if InCombatLockdown() then return end local maxWidth = colLeftWidth + colRightWidth for i=1, nbEntries do altButtons[i]:SetWidth(maxWidth) end g:SetWidth(maxWidth + GAP*2) g:SetHeight(BUTTON_HEIGHT * nbEntries + GAP*2) local horiz = f:GetCenter() > UIParent:GetWidth()/2 and "RIGHT" or "LEFT" local verti = select(2, f:GetCenter()) > UIParent:GetHeight()/2 and "TOP" or "BOTTOM" g:ClearAllPoints() g:SetPoint(verti..horiz, f, verti..(horiz=="LEFT"and"RIGHT"or"LEFT")) for i=nbEntries+1, #altButtons do altButtons[i]:Hide() end if nbEntries == 0 then g:Hide() end end Block_OnEnter = function(self) workingFrame = f highlight:SetVertexColor(unpack(config.colors.highlight)) f:Show() if InCombatLockdown() then return else CloseDropDownMenus() end tipShown = tipShown or self Menu_OnEnter(tipShown) nbEntries = 0 local char = realm[playerName] -- dirty fix local firstCombatSkill, button, selectedSkillExists = true local itemLeftWidth, itemRightWidth, colRightWidth, colLeftWidth, skillWidth, cdWidth = 0, 0, 0, 0 UpdateCDs() local showCDs, showProfessions, showCombatSkills, showShortcuts = min(#CDs,1), 0, 0, next(char.shortcuts) and 1 or 0 for k,v in next,f.skills do del(v) f.skills[k]=nil end ExpandSkillHeader(0) for i=1, GetNumSkillLines() do local displayName, skill, skillName, value, _, _, valueMax = GetSkillLineInfo(i) skillName = altNames[displayName] or displayName skill = skills[skillName] if skill then local hasPanel, isProfession = bit_band(skill,PANEL)>0, bit_band(skill,PROFESSION)>0 if char.show[skillName] == nil then char.show[skillName] = hasPanel end local show = (isProfession and not char.hideProfessions or not isProfession and not char.hideCombatSkills) and char.show[skillName] if show then if isProfession then showProfessions=1 else showCombatSkills=1 end end f.skills[#f.skills+1] = new( "displayName", displayName, "skillName", skillName, "isProfession", isProfession and floor(skill/SPELL_ID), "isCombatSkill",not isProfession, "hasPanel", hasPanel, "color", skillName==char.skill and config.colors.selected or hasPanel and config.colors.activeName or config.colors.infoName, "strValue", valueMax <= 1 and "" or ColorCurMax(value,valueMax,isProfession), "show", show, "primary", bit_band(skill,SECONDARY) == 0) if isProfession then char.curSkills[skillName], char.maxSkills[skillName] = value, valueMax end end end local nbHeaders = showProfessions + showCombatSkills + showCDs + showShortcuts sort(f.skills, SortSkills) for i, v in ipairs(f.skills) do if v.show then if nbEntries == 0 and showProfessions == 1 and nbHeaders > 1 then AddEntry(buttons, "", _G.TRADE_SKILLS, config.colors.header) end if v.isCombatSkill and firstCombatSkill and nbHeaders > 1 then firstCombatSkill = false if nbEntries > 0 then AddEntry(buttons) end AddEntry(buttons, "", L"Combat Skills", config.colors.header) end local texture = altIcons[v.skillName] or select(3,GetSpellInfo(v.isProfession)) or "" button, itemLeftWidth, itemRightWidth = AddEntry( buttons, texture, v.displayName, v.color, v.strValue, nil, true) button:SetScript("OnClick", Tradeskill_OnClick) button.skill, button.spellID, button.shortcut = v.skillName if v.color == config.colors.selected then f.selected = button end if itemLeftWidth > colLeftWidth then colLeftWidth = itemLeftWidth end if itemRightWidth > colRightWidth then colRightWidth = itemRightWidth end end end skillWidth = colLeftWidth + colRightWidth colRightWidth, colLeftWidth = 0, 0, 0, 0 -- Cooldowns local dups = new() for index, data in ipairs(CDs) do local group = data.group if not group or not dups[group] then if group then dups[group] = true end if index == 1 then if nbEntries>0 then AddEntry(buttons) end if nbHeaders>1 then AddEntry(buttons, "", L.Cooldowns, config.colors.header) end end button, itemLeftWidth, itemRightWidth = AddEntry( buttons, config.icons[group or data.spellID] or config.names[group] and select(3,GetSpellInfo(config.names[group])) or groupIcons[group], data.name, data.char == playerName and config.colors.ownCD or config.colors.foreignCD, data.timeLeft<=0 and L"|cff20ff20Ready!|r" or SecondsToTime(data.timeLeft), nil, true ) button:SetScript("OnClick", Cooldown_OnClick) button.skill, button.spellID, button.ready, button.owner, button.shortcut = data.skill, group and config.names[group] or data.spellID, data.timeLeft<=0, data.char if itemLeftWidth > colLeftWidth then colLeftWidth = itemLeftWidth end if itemRightWidth > colRightWidth then colRightWidth = itemRightWidth end end end del(dups) cdWidth = colLeftWidth + colRightWidth colLeftWidth = 0 -- Shortcuts local shortcuts = new() for spellID, skill in next, char.shortcuts do shortcuts[#shortcuts+1] = new( "skill", skill, "name", config.aliases[spellID] or config.names[spellID], "spellID", spellID) end sort(shortcuts, SortShortcuts) local firstShortcut = true for _, shortcut in ipairs(shortcuts) do if firstShortcut then firstShortcut = false if nbEntries>0 then AddEntry(buttons) end if nbHeaders>1 then AddEntry(buttons, "", L.Shortcuts, config.colors.header) end end button, itemLeftWidth = AddEntry( buttons, config.icons[shortcut.spellID], shortcut.name, config.colors.activeName, nil, nil, true ) if itemLeftWidth > colLeftWidth then colLeftWidth = itemLeftWidth end button:SetScript("OnClick", Shortcut_OnClick) button.skill, button.spellID, button.ready, button.shortcut = shortcut.skill, shortcut.spellID, true, true end del(shortcuts) -- ProfessionsBook if ProfessionsBook then if nbEntries>0 then AddEntry(buttons) end if nbHeaders>1 then AddEntry(buttons, "", L"Miscellaneous", config.colors.header) end button, itemLeftWidth = AddEntry( buttons, "Interface\\Spellbook\\Spellbook-Icon", "ProfessionsBook", config.colors.activeName, nil, nil, true ) button:SetScript("OnClick", ProfessionsBook_OnClick) button.skill, button.spellID, button.ready, button.shortcut = "None" end local maxWidth = math.max(skillWidth, cdWidth, colLeftWidth, itemLeftWidth) + GAP for i=1, nbEntries do buttons[i]:SetWidth(maxWidth) end f:SetWidth(maxWidth + GAP*2) f:SetHeight(BUTTON_HEIGHT * nbEntries + GAP*2) if _G.Skinner then _G.Skinner:applySkin(f) end local showBelow = select(2, tipShown:GetCenter()) > ( UIParent:GetHeight() / 2) f:ClearAllPoints() f:SetPoint(showBelow and "TOP" or "BOTTOM", tipShown, showBelow and "BOTTOM" or "TOP") for i=nbEntries+1, #buttons do buttons[i]:Hide() end if nbEntries == 0 then f:Hide() elseif not config.hideAlts then return InCombatLockdown() and g:Show() or ShowAlts() end end local function Block_OnClick(self, click) if click == "LeftButton" then if skills[char.skill] then CastSpellByName(char.skill) end elseif click == "RightButton" then f:Hide() tip:Hide() g:Hide() UIDropDownMenu_Initialize(dropdown, dropdown_init, "MENU") ToggleDropDownMenu(1, nil, dropdown, self, 0, 0) end end f.block = LibStub("LibDataBroker-1.1"):NewDataObject("|cFFFFB366Ara|r Tradeskills", { type = "data source", text = _G.TRADESKILLS, icon = "", OnEnter = Block_OnEnter, OnLeave = Menu_OnLeave, OnClick = Block_OnClick, } ) function f:TRADE_SKILL_SHOW() self:UnregisterEvent"TRADE_SKILL_SHOW" if self.getLink then self.getLink = nil local link = GetTradeSkillListLink() if not ChatEdit_InsertLink(link) then ChatFrameEditBox:Show() ChatEdit_InsertLink(link) end if self.keepOpen then self.keepOpen = nil else CloseTradeSkill() end return end ExpandTradeSkillSubClass(0) SetTradeSkillSubClassFilter(0,1,1) SetTradeSkillInvSlotFilter(0,1,1) TradeSkillOnlyShowMakeable(false) if TradeSkillFrameAvailableFilterCheckButton then TradeSkillFrameAvailableFilterCheckButton:SetChecked(false) end for i=1, GetNumTradeSkills() do local itemName, itemType = GetTradeSkillInfo(i) if itemType ~= "header" then local spellID = tonumber(strmatch(GetTradeSkillRecipeLink(i), "enchant:(%d+)")) local cd = watchedCDs[spellID] if spellID == self.searchedSpellID and (cd or self.shortcut) then SelectTradeSkill(i) TradeSkillFrame_SetSelection(i) if self.doTradeSkill and not GetTradeSkillCooldown(i) then DoTradeSkill(i) CloseTradeSkill() -- TODO: don't close if it was open else TradeSkillListScrollFrame:SetVerticalScroll(max(i-5,0)*TradeSkillSkill1:GetHeight()) end self.searchedSpellID, self.doTradeSkill, self.shortcut = nil break end if cd and self.learnCD then local timeLeft = GetTradeSkillCooldown(i) or 0 if timeLeft>0 or config.addReadyCD then char[spellID] = time() + timeLeft if not cd.group then config.icons[spellID] = GetTradeSkillIcon(i) config.names[spellID] = itemName end end end end end if self.learnCD then if self.keepOpen then self.keepOpen = nil else CloseTradeSkill() end self.learnCD = nil end if tipShown then Block_OnEnter(tipShown) end end function f:SetAlias(alias) config.aliases[self.aliasID] = alias ~= "" and alias or nil if tipShown then Block_OnEnter(tipShown)end end function f:PLAYER_LOGOUT() for i=1, GetNumSkillLines() do local displayName, skill, skillName, value, _, _, valueMax = GetSkillLineInfo(i) skillName = altNames[displayName] or displayName skill = skills[skillName] if skill then if bit_band(skill,PROFESSION) == 0 then break end char.curSkills[skillName], char.maxSkills[skillName] = value, valueMax end end end ------------------------------[[ options ]]------------------------------ local function DisplayCD_OnUpdate(self, elapsed) self.timer = self.timer - elapsed if self.timer > 0 then return end self.timer = 60 UpdateCDs() end local function SetOption(self, t, v, c) t[v] = not t[v] end local function ColorPickerChange() c[1], c[2], c[3] = ColorPickerFrame:GetColorRGB() end local function ColorPickerCancel(prev) c[1], c[2], c[3] = unpack(prev) end local function OpenColorPicker(self, col) c = config.colors[col] ColorPickerFrame.func = ColorPickerChange ColorPickerFrame.cancelFunc = ColorPickerCancel ColorPickerFrame.previousValues = {unpack(c)} ColorPickerFrame:SetColorRGB( c[1], c[2], c[3] ) ColorPickerFrame:Show() end local function RemoveChar(self, char) realm[char] = nil print( "|cFFFFB366Ara|cffffff00BrokerTradeskills: "..format(L"|cff8080ff%s|r has been removed.",char) ) end function f:ADDON_LOADED(event, addon) if addon ~= "Ara_Broker_Tradeskills" then return end AraTradeskillsDB = AraTradeskillsDB or {icons={},names={},aliases={},colors={ header={1,1,1}, activeName={1,.82,0}, infoName={.6,.5,0}, selected={.9,0.45,.1}, highlight={1,.8,0}, ownCD={1,.82,0}, foreignCD={.6,.5,0} }} config = AraTradeskillsDB config.colors.activeVal, config.colors.infoVal = nil -- get rid of old config values if not config[realmName] then config[realmName] = {} end realm = config[realmName] if not realm[playerName] then realm[playerName] = {show={}} end char = realm[playerName] if not char.shortcuts then char.shortcuts = {} end -- r14 if not char.curSkills then char.curSkills, char.maxSkills = {}, {} end if not char.links then char.links = {} end -- r25 CDs = new() if config.displayCDs then e.timer = 0 e:SetScript("OnUpdate", DisplayCD_OnUpdate) end options = { { text = format("|cFFFFB366Ara|r Broker Tradeskills (%s)", GetAddOnMetadata("Ara_Broker_Tradeskills", "Version")), isTitle = true }, { text = _G.TRADE_SKILLS, submenu = "isProfession", scope=char, var="hideProfessions", inv=true }, { text = L"Combat Skills", submenu = "isCombatSkill", scope=char, var="hideCombatSkills", inv=true }, { text = L"Include |cff20ff20Ready!|r CDs when scanning", scope=config, var="addReadyCD" }, { text = L"Show hints", scope=config, var="hideTips", inv=true }, { text = L"Show alt. skills", scope=config, var="hideAlts", inv=true }, { text = L"Show alt. primary skills only", scope=config, var="primaryOnly" }, { text = L"Remove an alt.", submenu="alts" }, { text = L"Display number of Ready CD", func= function() config.displayCDs = not config.displayCDs e.timer = 0 e:SetScript("OnUpdate", config.displayCDs and DisplayCD_OnUpdate or nil) UpdateText() end, checked=function() return config.displayCDs end }, { text = L.Colors, submenu = { { text = L"Header", colorPick = "header" }, { text = L"Interactive skill name", colorPick = "activeName" }, { text = L"Last selected skill", colorPick = "selected" }, { text = L"Informative skill name", colorPick = "infoName" }, { text = L"Player CD", colorPick = "ownCD" }, { text = L"Other player CD", colorPick = "foreignCD" }, { text = L"Highlight", colorPick = "highlight" }, }, }, } dropdown_init = function(self, level) level = level or 1 local options = level>1 and UIDROPDOWNMENU_MENU_VALUE or options if options == "alts" then for char in next, realm do if char ~= playerName then local info = UIDropDownMenu_CreateInfo() info.text, info.notCheckable = char, true info.func, info.arg1 = RemoveChar, char UIDropDownMenu_AddButton( info, level ) end end return end local custom = type(options)~="table" for i, v in ipairs(custom and f.skills or options) do if not custom or v[options] then local info = UIDropDownMenu_CreateInfo() info.text = custom and format("|cff%.2x%.2x%.2x%s|r", v.color[1]*255, v.color[2]*255, v.color[3]*255, v.displayName) or v.text info.isTitle, info.value, info.hasArrow = v.isTitle, v.submenu, v.submenu ~= nil if custom then info.checked = char.show[v.skillName] info.func, info.arg1, info.arg2 = SetOption, char.show, v.skillName elseif v.scope then info.checked = v.inv and not v.scope[v.var] or not v.inv and v.scope[v.var] info.func, info.arg1, info.arg2, info.tooltipText = SetOption, v.scope, v.var, v.inv elseif v.colorPick then info.hasColorSwatch, info.notCheckable = true, true info.r, info.g, info.b = unpack(config.colors[v.colorPick]) info.func, info.arg1 = OpenColorPicker, v.colorPick else info.func, info.checked = v.func, v.checked end info.keepShownOnClick = info.func UIDropDownMenu_AddButton( info, level ) end end end local popup = { text = L"Set an alias for \"%s\".\nLeave blank to reset.", OnAccept = function(self) AraSkills:SetAlias(self.wideEditBox:GetText()) end, OnShow = function(self) self.wideEditBox:SetText(AraSkills.alias) self.wideEditBox:SetFocus() end, EditBoxOnEnterPressed = function(self) local parent = self:GetParent() AraSkills:SetAlias(parent.wideEditBox:GetText()) parent:Hide() end, } for k, v in next, StaticPopupDialogs.SET_FRIENDNOTE do if not popup[k] then popup[k] = v end end StaticPopupDialogs.SET_ALIAS = popup tip = _G.GameTooltip self.skills = {} self:SetFrameStrata"TOOLTIP" self:SetClampedToScreen(true) self:EnableMouse(true) self:SetScript("OnEnter", Menu_OnEnter) self:SetScript("OnLeave", Menu_OnLeave) self:RegisterEvent"PLAYER_LOGOUT" g:SetFrameStrata"TOOLTIP" g:EnableMouse(true) g:SetScript("OnEnter", Alt_OnEnter) g:SetScript("OnLeave", Alt_OnLeave) local backdrop = { bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Tooltips\\UI-Tooltip-Border", tile=true, tileSize=12, edgeSize=12, insets = { left=2, right=2, top=2, bottom=2 } } self:SetBackdrop(backdrop) self:SetBackdropColor(0, 0, 0, .75) g:SetBackdrop(backdrop) g:SetBackdropColor(0, 0, 0, .75) if IsLoggedIn() then UpdateText() else f.PLAYER_ENTERING_WORLD = UpdateText f:RegisterEvent"PLAYER_ENTERING_WORLD" end self:UnregisterEvent(event) self.ADDON_LOADED = nil end e:RegisterEvent"TRADE_SKILL_SHOW" e:SetScript("OnEvent", function() LoadAddOn"Blizzard_TradeSkillUI" local b = TradeSkillSkillIcon local TS_OnEnter = b:GetScript"OnEnter" local TS_OnLeave = b:GetScript"OnLeave" local TS_OnClick = b:GetScript"OnClick" local OrgSetItem = GameTooltip.SetTradeSkillItem local function NewSetItem(...) OrgSetItem(...) GameTooltip:AddLine("\n"..L"|cffff8040Click|r to create a shortcut.", .2, 1, .2) GameTooltip:Show() end b:SetScript("OnEnter", function(self, ...) GameTooltip.SetTradeSkillItem = NewSetItem TS_OnEnter(self, ...) end) b:SetScript("OnLeave", function(...) TS_OnLeave(...) GameTooltip.SetTradeSkillItem = OrgSetItem end) b:SetScript("OnClick", function(self,button,...) TS_OnClick(self,button,...) if not IsModifierKeyDown() and button == "LeftButton" then local index = TradeSkillFrame.selectedSkill local spellID = tonumber(strmatch(GetTradeSkillRecipeLink(index), "enchant:(%d+)")) local skill = GetTradeSkillLine() char.shortcuts[spellID] = altNames[skill] or skill config.names[spellID] = GetTradeSkillInfo(index) config.icons[spellID] = GetTradeSkillIcon(index) print("|cFFFFB366Ara|cffffff00BrokerTradeskills: "..format(L"|cff8080ff%s|r|cffffff00 added to shortcuts.",config.names[spellID])) end end) local function OnEvent() if not IsTradeSkillLinked() then local skill = GetTradeSkillLine() char.links[ altNames[skill] or skill ] = GetTradeSkillListLink() end end e:SetScript("OnEvent", OnEvent) OnEvent() end) f:SetScript("OnEvent", function(self, event, ...) return self[event](self, event, ...) end) f:RegisterEvent"ADDON_LOADED"