WoWInterface SVN Ara_Broker_Tradeskills

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /trunk
    from Rev 1 to Rev 3
    Reverse comparison

Rev 1 → Rev 3

Ara_Broker_Tradeskills.lua New file
0,0 → 1,1017
-- 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
[26751]= { skill= L.Tailoring, CD= 3*DAY+20*HOUR }, -- Primal Mooncloth
[36686]= { skill= L.Tailoring, CD= 3*DAY+20*HOUR }, -- Shadowcloth
[31373]= { skill= L.Tailoring, CD= 3*DAY+20*HOUR }, -- Spellcloth
[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.TRADESKILLS) 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]
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
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.TRADESKILLS, 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)
 
if IsLoggedIn() then UpdateText() else
f.PLAYER_ENTERING_WORLD = UpdateText
f:RegisterEvent"PLAYER_ENTERING_WORLD"
end
self:UnregisterEvent(event)
self.ADDON_LOADED = nil
 
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)
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"
\ No newline at end of file
libs/CallbackHandler-1.0.lua New file
0,0 → 1,239
--[[ $Id: CallbackHandler-1.0.lua 60697 2008-02-09 16:51:20Z nevcairiel $ ]]
local MAJOR, MINOR = "CallbackHandler-1.0", 3
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
 
if not CallbackHandler then return end -- No upgrade needed
 
local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
 
local type = type
local pcall = pcall
local pairs = pairs
local assert = assert
local concat = table.concat
local loadstring = loadstring
local next = next
local select = select
local type = type
local xpcall = xpcall
 
local function errorhandler(err)
return geterrorhandler()(err)
end
 
local function CreateDispatcher(argCount)
local code = [[
local next, xpcall, eh = ...
 
local method, ARGS
local function call() method(ARGS) end
 
local function dispatch(handlers, ...)
local index
index, method = next(handlers)
if not method then return end
local OLD_ARGS = ARGS
ARGS = ...
repeat
xpcall(call, eh)
index, method = next(handlers, index)
until not method
ARGS = OLD_ARGS
end
 
return dispatch
]]
 
local ARGS, OLD_ARGS = {}, {}
for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end
code = code:gsub("OLD_ARGS", concat(OLD_ARGS, ", ")):gsub("ARGS", concat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler)
end
 
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
 
--------------------------------------------------------------------------
-- CallbackHandler:New
--
-- target - target object to embed public APIs in
-- RegisterName - name of the callback registration API, default "RegisterCallback"
-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
 
function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused)
-- TODO: Remove this after beta has gone out
assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused")
 
RegisterName = RegisterName or "RegisterCallback"
UnregisterName = UnregisterName or "UnregisterCallback"
if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
UnregisterAllName = "UnregisterAllCallbacks"
end
 
-- we declare all objects and exported APIs inside this closure to quickly gain access
-- to e.g. function names, the "target" parameter, etc
 
 
-- Create the registry object
local events = setmetatable({}, meta)
local registry = { recurse=0, events=events }
 
-- registry:Fire() - fires the given event/message into the registry
function registry:Fire(eventname, ...)
if not rawget(events, eventname) or not next(events[eventname]) then return end
local oldrecurse = registry.recurse
registry.recurse = oldrecurse + 1
 
Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...)
 
registry.recurse = oldrecurse
 
if registry.insertQueue and oldrecurse==0 then
-- Something in one of our callbacks wanted to register more callbacks; they got queued
for eventname,callbacks in pairs(registry.insertQueue) do
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
for self,func in pairs(callbacks) do
events[eventname][self] = func
-- fire OnUsed callback?
if first and registry.OnUsed then
registry.OnUsed(registry, target, eventname)
first = nil
end
end
end
registry.insertQueue = nil
end
end
 
-- Registration of a callback, handles:
-- self["method"], leads to self["method"](self, ...)
-- self with function ref, leads to functionref(...)
-- "addonId" (instead of self) with function ref, leads to functionref(...)
-- all with an optional arg, which, if present, gets passed as first argument (after self if present)
target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
if type(eventname) ~= "string" then
error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
end
 
method = method or eventname
 
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
 
if type(method) ~= "string" and type(method) ~= "function" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
end
 
local regfunc
 
if type(method) == "string" then
-- self["method"] calling style
if type(self) ~= "table" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
elseif self==target then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
elseif type(self[method]) ~= "function" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
end
 
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
local arg=select(1,...)
regfunc = function(...) self[method](self,arg,...) end
else
regfunc = function(...) self[method](self,...) end
end
else
-- function ref with self=object or self="addonId"
if type(self)~="table" and type(self)~="string" then
error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string expected.", 2)
end
 
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
local arg=select(1,...)
regfunc = function(...) method(arg,...) end
else
regfunc = method
end
end
 
 
if events[eventname][self] or registry.recurse<1 then
-- if registry.recurse<1 then
-- we're overwriting an existing entry, or not currently recursing. just set it.
events[eventname][self] = regfunc
-- fire OnUsed callback?
if registry.OnUsed and first then
registry.OnUsed(registry, target, eventname)
end
else
-- we're currently processing a callback in this registry, so delay the registration of this new entry!
-- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
registry.insertQueue = registry.insertQueue or setmetatable({},meta)
registry.insertQueue[eventname][self] = regfunc
end
end
 
-- Unregister a callback
target[UnregisterName] = function(self, eventname)
if not self or self==target then
error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
end
if type(eventname) ~= "string" then
error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
end
if rawget(events, eventname) and events[eventname][self] then
events[eventname][self] = nil
-- Fire OnUnused callback?
if registry.OnUnused and not next(events[eventname]) then
registry.OnUnused(registry, target, eventname)
end
end
if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
registry.insertQueue[eventname][self] = nil
end
end
 
-- OPTIONAL: Unregister all callbacks for given selfs/addonIds
if UnregisterAllName then
target[UnregisterAllName] = function(...)
if select("#",...)<1 then
error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
end
if select("#",...)==1 and ...==target then
error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
end
 
 
for i=1,select("#",...) do
local self = select(i,...)
if registry.insertQueue then
for eventname, callbacks in pairs(registry.insertQueue) do
if callbacks[self] then
callbacks[self] = nil
end
end
end
for eventname, callbacks in pairs(events) do
if callbacks[self] then
callbacks[self] = nil
-- Fire OnUnused callback?
if registry.OnUnused and not next(callbacks) then
registry.OnUnused(registry, target, eventname)
end
end
end
end
end
end
 
return registry
end
 
 
-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
-- try to upgrade old implicit embeds since the system is selfcontained and
-- relies on closures to work.
 
libs/LibDataBroker-1.1.lua New file
0,0 → 1,66
 
assert(LibStub, "LibDataBroker-1.1 requires LibStub")
assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
 
local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 3)
if not lib then return end
oldminor = oldminor or 0
 
 
lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {}
local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
 
if oldminor < 2 then
lib.domt = {
__metatable = "access denied",
__index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
}
end
 
if oldminor < 3 then
lib.domt.__newindex = function(self, key, value)
if not attributestorage[self] then attributestorage[self] = {} end
if attributestorage[self][key] == value then return end
attributestorage[self][key] = value
local name = namestorage[self]
if not name then return end
callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self)
end
end
 
if oldminor < 2 then
function lib:NewDataObject(name, dataobj)
if self.proxystorage[name] then return end
 
if dataobj then
assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
self.attributestorage[dataobj] = {}
for i,v in pairs(dataobj) do
self.attributestorage[dataobj][i] = v
dataobj[i] = nil
end
end
dataobj = setmetatable(dataobj or {}, self.domt)
self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
return dataobj
end
end
 
if oldminor < 1 then
function lib:DataObjectIterator()
return pairs(self.proxystorage)
end
 
function lib:GetDataObjectByName(dataobjectname)
return self.proxystorage[dataobjectname]
end
 
function lib:GetNameByDataObject(dataobject)
return self.namestorage[dataobject]
end
end
libs/LibStub.lua New file
0,0 → 1,30
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
local LibStub = _G[LIBSTUB_MAJOR]
 
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
LibStub = LibStub or {libs = {}, minors = {} }
_G[LIBSTUB_MAJOR] = LibStub
LibStub.minor = LIBSTUB_MINOR
 
function LibStub:NewLibrary(major, minor)
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
 
local oldminor = self.minors[major]
if oldminor and oldminor >= minor then return nil end
self.minors[major], self.libs[major] = minor, self.libs[major] or {}
return self.libs[major], oldminor
end
 
function LibStub:GetLibrary(major, silent)
if not self.libs[major] and not silent then
error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
end
return self.libs[major], self.minors[major]
end
 
function LibStub:IterateLibraries() return pairs(self.libs) end
setmetatable(LibStub, { __call = LibStub.GetLibrary })
end
Ara_Broker_Tradeskills.toc New file
0,0 → 1,18
## Interface: 30100
## Title: |cFFFFB366Ara|r - Broker - Tradeskills
## Version: r26
## Author: Ara
## Notes: Provides easy access to tradeskills and tracked tradeskill CDs. Can also display combat skills.
## OptionalDeps: SharedMedia, Skinner
## SavedVariables: AraTradeskillsDB
 
## LoadManagers: AddonLoader, SupplyAndDemand, ForkliftGnome
## X-LoadOn-Always: delayed
## X-S&D-Always: true
 
libs\LibStub.lua
libs\CallbackHandler-1.0.lua
libs\LibDataBroker-1.1.lua
 
Translations.lua
Ara_Broker_Tradeskills.lua
\ No newline at end of file
Translations.lua New file
0,0 → 1,322
--[[ Weapon skill translations can be found in your skill window:
 
-- weapon skills
"Axes", "",
"Bows", "",
"Crossbows", "",
"Daggers", "",
"Defense", "",
"Guns", "",
"Maces", "",
"Polearms", "",
"Staves", "",
"Swords", "",
"Thrown", "",
"Two-Handed Swords", "",
"Two-Handed Axes", "",
"Two-Handed Maces", "",
"Unarmed", "",
"Wands", "",
 
-- misc / UI
"Combat Skills", "",
"Cooldowns", "",
"|cff20ff20Ready!|r", "",
"d", "", -- abrev. for "day"
"h", "", -- abrev. for "hour"
"m", "", -- abrev. for "minute"
"s", "", -- abrev. for "seconde"
 
"Hints", "",
"Belongs to:", "",
"Set an alias for \"%s\".\nLeave blank to reset.", ""
 
"|cffff8020Click|r to craft.", "",
"|cffff8020Right-Click|r to show CD in panel.", "",
"|cffff8020Click|r to show CD in panel.", "",
"|cffff8020Control+Click|r to set an alias.", "",
"|cffff8020Click|r to toggle panel.", "",
"|cffff8020Right-Click|r to scan for CDs.", "",
"|cffff8020Middle-Click|r to remove from list.","",
 
"Include |cff20ff20Ready!|r CDs when scanning", "",
"Show hints", "",
"Colors", "",
"Header", "",
"Interactive skill name", "",
"Last selected skill", "",
"Informative skill name", "",
"Player CD", "",
"Other player CD", "",
"Highlight", "",
 
-- ADDED in r6:
"Show alt. skills", "",
 
-- ADDED in r7-14:
"Remove an alt.", "",
"|cff8080ff%s|r has been removed.", "", -- %s: character's name
"Display number of Ready CD", "",
"Shortcuts", "",
"|cffff8040Click|r to create a shortcut.", "",
"|cff8080ff%s|r|cffffff00 added to shortcuts.", "", -- %s: tradeskill's name
"|cffff8020Right-Click|r to show in panel.", "",
 
-- ADDED in r15:
"Show alt. primary skills only", "",
 
-- ADDED in r25:
"No link available. Open a character\ntradeskill panel to be able to access\nit from your other characters.", ""
 
--]]
 
_G.ABTS_T = {}
local L = _G.ABTS_T
 
local function SetTranslations(...)
for i=1, select("#",...), 2 do
local k,v = select(i,...)
L[k] = v
end
end
 
SetTranslations(
"Alchemy", GetSpellInfo(2259),
"Blacksmithing", GetSpellInfo(2018),
"Cooking", GetSpellInfo(2550),
"Enchanting", GetSpellInfo(7411),
"Engineering", GetSpellInfo(4036),
"First Aid", GetSpellInfo(3273),
"Fishing", GetSpellInfo(7620),
"Herbalism", GetSpellInfo(13614),
"Inscription", GetSpellInfo(45357),
"Jewelcrafting", GetSpellInfo(25229),
"Leatherworking", GetSpellInfo(2108),
"Lockpicking", GetSpellInfo(1809),
"Mining", GetSpellInfo(2575),
"Runeforging", GetSpellInfo(53428),
"Skinning", GetSpellInfo(8613),
"Smelting", GetSpellInfo(2656),
"Tailoring", (GetSpellInfo(3908))
)
 
local l = GetLocale()
if l == "frFR" then
SetTranslations(
-- Special case where names doesnt match (like Mining --> Smelting):
-- The skill window display "Runeforger" whereas the spell returned by GetSpellInfo is "Runeforge".
-- "SmeltingDN", "Mining", ***SAMPLE***
"RuneforgingDN", "Runeforger",
 
"Axes", "Haches",
"Bows", "Arcs",
"Crossbows", "Arbalètes",
"Daggers", "Dagues",
"Defense", "Défense",
"Guns", "Armes à feu",
"Maces", "Masse",
"Polearms", "Armes d'hast",
"Staves", "Bâtons",
"Swords", "Epées",
"Thrown", "Armes de jet",
"Two-Handed Swords", "Epées à deux mains",
"Two-Handed Axes", "Haches à deux mains",
"Two-Handed Maces", "Masses à deux mains",
"Unarmed", "Mains nues",
"Wands", "Baguettes",
 
"Combat Skills", "Compétences de combat",
"Cooldowns", nil,
"|cff20ff20Ready!|r", "|cff20ff20Prêt!|r",
"d", "j",
 
"Hints", "Notice",
"Belongs to:", "Appartient à:",
"Set an alias for \"%s\".\nLeave blank to reset.", "Définissez un alias pour \"%s\".\nLaissez vide pour revenir au nom d'origine.",
 
"|cffff8020Click|r to craft.", "|cffff8020Click|r pour craft.",
"|cffff8020Right-Click|r to show CD in panel.", "|cffff8020Click-Droit|r affiche la page du CD.",
"|cffff8020Click|r to show CD in panel.", "|cffff8020Click|r pour aller au CD.",
"|cffff8020Control+Click|r to set an alias.", "|cffff8020Control+Click|r pour définir un alias.",
"|cffff8020Click|r to toggle panel.", "|cffff8020Click|r pour ouvrir/fermer le panneau.",
"|cffff8020Right-Click|r to scan for CDs.", "|cffff8020Click-Droit|r pour chercher des CDs.",
"|cffff8020Middle-Click|r to remove from list.","|cffff8020Click-Molette|r pour retirer de la liste.",
 
"Include |cff20ff20Ready!|r CDs when scanning", "Inclure les CDs |cff20ff20Prêt!|r pendant la recherche",
"Show hints", "Afficher la notice",
"Colors", "Couleurs",
"Header", "En-tête de catégorie",
"Interactive skill name", "Nom de compétence interactive",
"Last selected skill", "Dernière compétence selectionnée",
"Informative skill name", "Nom de compétence passive",
"Player CD", "CD du personnage actuel",
"Other player CD", "CD d'un autre personnage",
"Highlight", "Surbrillance",
 
"Show alt. skills", "Afficher les compétences des rerolls.",
"Remove an alt.", "Supprimer les info d'un reroll.",
"|cff8080ff%s|r has been removed.", "|cff8080ff%s|r a été supprimé.",
"Display number of Ready CD", "Afficher le nombre de CD prêt.",
"Shortcuts", "Raccourcis",
"|cffff8040Click|r to create a shortcut.", "|cffff8040Click|r pour créer un raccourcis.",
"|cff8080ff%s|r|cffffff00 added to shortcuts.", "Raccourcis |cff8080ff%s|cffffff00 ajouté.",
"|cffff8020Right-Click|r to show in panel.", "|cffff8020Click-Droit|r pour y aller."
 
)
elseif l == "deDE" then
SetTranslations(
"Axes", "Äxte",
"Bows", "Bogen",
"Crossbows", "Armbrüste",
"Daggers", "Dolche",
"Defense", "Verteidigung",
"Guns", "Schusswaffen",
"Maces", "Streitkolben",
"Polearms", "Stangenwaffen",
"Staves", "Stäbe",
"Swords", "Schwerter",
"Thrown", "Wurfwaffe",
"Two-Handed Swords", "Zweihandschwerter",
"Two-Handed Axes", "Zweihandäxte",
"Two-Handed Maces", "Zweihandstreitkolben",
"Unarmed", "Unbewaffnet",
"Wands", "Zauberstäbe"
)
--elseif l == "zhCN" then
-- SetTranslations( )
elseif l == "zhTW" then
-- weapon skills 武器技能
SetTranslations(
"Axes", "斧",
"Bows", "弓",
"Crossbows", "弩",
"Daggers", "匕首",
"Defense", "防禦",
"Guns", "槍",
"Maces", "錘",
"Polearms", "長柄武器",
"Staves", "法杖",
"Swords", "劍",
"Thrown", "投擲武器",
"Two-Handed Swords", "雙手劍",
"Two-Handed Axes", "雙手斧",
"Two-Handed Maces", "雙手錘",
"Unarmed", "徒手戰鬥",
"Wands", "魔杖",
-- misc / UI
"Combat Skills", "武器技能",
"Cooldowns", "冷卻",
"|cff20ff20Ready!|r", "|cff20ff20準備好!|r",
"d", "天",
"h", "時",
"m", "分",
"s", "秒",
 
"Hints", "提示",
"Belongs to:", "屬於",
"Set an alias for \"%s\".\nLeave blank to reset.", "為 \"%s\" 設置別名。\n留下空白?重新設置。",
 
"|cffff8020Click|r to craft.", "|cffff8020直接點擊|r 製造該項",
"|cffff8020Right-Click|r to show CD in panel.", "|cffff8020右鍵點擊|r 在面板視窗中顯示該項冷卻.",
"|cffff8020Click|r to show CD in panel.", "|cffff8020點擊|r 在面板視窗中顯示該項冷卻.",
"|cffff8020Control+Click|r to set an alias.", "|cffff8020Ctrl-點擊|r 為該項設置一個別名",
"|cffff8020Click|r to toggle panel.", "|cffff8020直接點擊|r 打開面板視窗",
"|cffff8020Right-Click|r to scan for CDs.", "|cffff8020右鍵-點擊|r 掃描冷卻時間",
"|cffff8020Middle-Click|r to remove from list.","|cffff8020中鍵-點擊|r 從列表中移除該項",
 
"Include |cff20ff20Ready!|r CDs when scanning", "當掃描時,包含|cff20ff20準備好!|r的冷卻",
"Show hints", "顯示提示",
"Colors", "色彩",
"Header", "標題",
"Interactive skill name", "交易技能名稱",
"Last selected skill", "最後點選技能",
"Informative skill name", "武器技能名稱",
"Player CD", "本身玩家冷卻",
"Other player CD", "其他角色冷卻",
"Highlight", "高亮",
 
-- ADDED in r6:
"Show alt. skills", "顯示分身",
 
-- ADDED in r7-14:
"Remove an alt.", "移除一個分身",
"|cff8080ff%s|r has been removed.", "|cff8080ff%s|r 已經被移除.", -- %s: character's name
"Display number of Ready CD", "顯示就緒冷卻數",
"Shortcuts", "捷徑",
"|cffff8040Click|r to create a shortcut.", "建立一個捷徑.",
"|cff8080ff%s|r|cffffff00 added to shortcuts.", "增加到捷徑.", -- %s: tradeskill's name
"|cffff8020Right-Click|r to show in panel.", "顯示在面板."
)
elseif l == "koKR" then
-- KOREA by shwy73
-- Modified by mrgyver(강호미인 of KR-윈드러너) for WotLK, 09.05.24
-- weapon skills
SetTranslations(
"Axes", "도끼류",
"Bows", "활류",
"Crossbows", "석궁류",
"Daggers", "단검",
"Defense", "방어",
"Guns", "총기류",
"Maces", "둔기류",
"Polearms", "장창류",
"Staves", "지팡이류",
"Swords", "도검류",
"Thrown", "투척무기",
"Two-Handed Swords", "양손 도검류",
"Two-Handed Axes", "양손 도끼류",
"Two-Handed Maces", "양손 둔기류",
"Unarmed", "맨손 전투",
"Wands", "마법봉류",
-- misc / UI
"Combat Skills", "전투 기술",
"Cooldowns", "재사용 대기시간",
"|cff20ff20Ready!|r", "|cff20ff20준비 완료!|r",
"d", "일",
"h", "시간",
"m", "분",
"s", "초",
 
"Hints", "도움말",
"Belongs to:", "해당 캐릭터:",
"Set an alias for \"%s\".\nLeave blank to reset.", "\"%s\"에 대한 별칭 설정.\n빈 공백으로 초기화.",
 
"|cffff8020Click|r to craft.", "|cffff8020클릭|r 으로 만들기.",
"|cffff8020Right-Click|r to show CD in panel.", "|cffff8020우-클릭|r 으로 쿨다운 패널 보기.",
"|cffff8020Click|r to show CD in panel.", "|cffff8020클릭|r 으로 쿨다운 패널 보기.",
"|cffff8020Control+Click|r to set an alias.", "|cffff8020컨트롤-클릭|r 으로 별칭 설정",
"|cffff8020Click|r to toggle panel.", "|cffff8020클릭|r 으로 패널 토글.",
"|cffff8020Right-Click|r to scan for CDs.", "|cffff8020우-클릭|r 으로 쿨다운 스캔 하기.",
"|cffff8020Middle-Click|r to remove from list.","|cffff8020중-클릭|r 으로 목록 제거.",
 
"Include |cff20ff20Ready!|r CDs when scanning", "쿨다운 스캐닝때 |cff20ff20준비 완료!|r 포함",
"Show hints", "도움말 보기",
"Colors", "색상",
"Header", "해더",
"Interactive skill name", "스킬 이름",
"Last selected skill", "마지막 선택 스킬",
"Informative skill name", "무기 스킬 이름",
"Player CD", "캐릭터 쿨다운",
"Other player CD", "다른 캐릭터 쿨다운",
"Highlight", "강조",
 
-- ADDED in r6:
"Show alt. skills", "다른 케릭 전문(보조)기술 보기",
 
-- ADDED in r7-14:
"Remove an alt.", "다른 케릭 제거하기",
"|cff8080ff%s|r has been removed.", "|cff8080ff%s|r 제거하기", -- %s: character's name
"Display number of Ready CD", "준비완료된 쿨다운의 갯수 표시",
"Shortcuts", "간단하게",
"|cffff8040Click|r to create a shortcut.", "|cffff8040클릭|r하면 간단하게 만들어 집니다.",
"|cff8080ff%s|r|cffffff00 added to shortcuts.", "|cff8080ff%s|r|cffffff00 간단하게 추가", -- %s: tradeskill's name
"|cffff8020Right-Click|r to show in panel.", "|cffff8020우-클릭|r으로 패널보기",
 
-- ADDED in r15:
"Show alt. primary skills only", "다른 케릭 전문기술만 보기"
)
--elseif l == "esES" then
-- SetTranslations( )
--elseif l == "ruRU" then
-- SetTranslations( )
end
\ No newline at end of file