vanilla-wow-addons – Rev 1
?pathlinks?
--<< ====================================================================== >>--
-- Constants --
--<< ====================================================================== >>--
ACETIMER.COLOR = {
AQUA = {0.0,1.0,1.0},
BLUE = {0.0,0.0,1.0},
FUCHSIA = {1.0,0.0,1.0},
GRAY = {0.5,0.5,0.5},
GREEN = {0.0,0.5,0.0},
LIME = {0.0,1.0,0.0},
MAROON = {0.5,0.0,0.0},
NAVY = {0.0,0.0,0.5},
OLIVE = {0.5,0.5,0.0},
PURPLE = {0.5,0.0,0.5},
RED = {1.0,0.0,0.0},
TEAL = {0.0,0.5,0.5},
WHITE = {1.0,1.0,1.0},
YELLOW = {1.0,1.0,0.0},
}
ACETIMER.COLOR_MAP = {
[0]="OLIVE",[1]="TEAL",[2]="PURPLE",[3]="GREEN",
}
ACETIMER.COMMANDS = {
ACETIMER.CMD_SHORT,
ACETIMER.CMD_LONG,
}
ACETIMER.CMD_OPTIONS = {
{ option = ACETIMER.OPT_ANCHOR, method = "CareOptAnchor", desc = ACETIMER.OPT_ANCHOR_DESC,},
{ option = ACETIMER.OPT_SCALE, method = "CareOptScale", desc = ACETIMER.OPT_SCALE_DESC,},
{ option = ACETIMER.OPT_GROW, method = "CareOptGrow", desc = ACETIMER.OPT_GROW_DESC,},
}
ACETIMER.SPELL = 1
ACETIMER.EVENT = 2
ACETIMER.SKILL = 3
--<< ====================================================================== >>--
-- Class Setup --
--<< ====================================================================== >>--
AceTimer = AceAddon:new({
name = ACETIMER.NAME,
description = ACETIMER.DESCRIPTION, -- Optional; Ace will use the .toc Notes text
version = "R4",
releaseDate = "",
aceCompatible = "102", -- Check ACE_COMP_VERSION in Ace.lua for current.
author = "Rasmus Kromann-Larsen",
email = "rasmus@kromann-larsen.dk",
website = "http://www.rasmuskl.dk",
category = "combat",
--optionsFrame = "AceTimerOptionsFrame",
db = AceDatabase:new("AceTimerDB"),
--defaults = DEFAULT_OPTIONS,
cmd = AceChatCmd:new(ACETIMER.COMMANDS, ACETIMER.CMD_OPTIONS),
modules = {},
})
function AceTimer:Initialize()
-- Helpful closures for accessing the addon's currently loaded profile.
self.GetOpt = function(var) return self.db:get(self.profilePath,var) end
self.SetOpt = function(var,val) self.db:set(self.profilePath,var,val) end
self.TogOpt = function(var) return self.db:toggle(self.profilePath,var) end
self:InitModules()
end
function AceTimer:Enable()
self.groups = {}
self.timers = {}
self.bars = {}
for i = 1, 20 do self.bars[i] = {} end
self.gs_patterns = {}
self.gs_captured = {}
self:InitAnchor()
self:EnableModules()
end
function AceTimer:Disable()
self:DisableModules()
if self.gs_patterns then self.gs_patterns = nil end
if self.gs_captured then self.gs_captured = nil end
if self.bars then self:KillBars(); self.bars = nil end
if self.timers then self.timers = nil end
if self.groups then self.groups = nil end
self:UnregisterAllEvents(self)
self:UnhookAllScripts()
end
--<< ====================================================================== >>--
-- Timer Processing --
--<< ====================================================================== >>--
function AceTimer:AddGroup(id, forall, color)
if color then
self.groups[id] = { fa=forall, cr=ACETIMER.COLOR[color] }
else
self.groups[id] = { fa=forall }
end
end
function AceTimer:AddTimer(kind, name, duration, targeted, isgain, selforselect, extra)
if not self.timers[kind] then self.timers[kind] = {} end
if not self.timers[kind][name] then self.timers[kind][name] = {} end
if not extra then extra = {} end
targeted = (targeted > 0 ) and 1 or nil
isgain = (isgain > 0 ) and 1 or nil
selforselect = (selforselect > 0 ) and 1 or nil
if extra.cr then extra.cr = ACETIMER.COLOR[extra.cr]
elseif extra.gr and self.groups[extra.gr].cr then extra.cr = self.groups[extra.gr].cr
else
local ccode = (targeted and 2 or 0) + (isgain and 1 or 0)
extra.cr = ACETIMER.COLOR[ACETIMER.COLOR_MAP[ccode]]
end
self.timers[kind][name] = { d=duration, k={t=targeted,g=isgain,s=selforselect}, x=extra }
end
function AceTimer:StartTimer(timer, name, target, rank)
if not target then target = "none" end
if not rank then rank = timer.r or 0 end
if timer.x.gr then self:CleanGroup(timer.x.gr, target) end
if timer.x.ea then
for name, valid in timer.x.ea do
local event = self.timers[ACETIMER.EVENT][name]
event.r = rank
event.v = GetTime() + valid
if target ~= "none" then event.t = target end
end
end
if timer.d == 0 then return end
local id, slot = name.."-"..target
for i = 1, 20 do
if self.bars[i].id == id then
TimexBar:StopBar(self.bars[i].id)
self:StopBar(self.bars[i].id)
break
end
end
for i = 1, 20 do if not self.bars[i].id then slot = i; break end end
if not slot or not TimexBar:Get(id) then return end
self.bars[slot].id = id
self.bars[slot].timer = timer
self.bars[slot].name = name
self.bars[slot].rank = rank
self.bars[slot].target = target
self.bars[slot].group = timer.x.gr
self:SetPoint(id, slot)
TimexBar:SetColor(id, unpack(timer.x.cr or ACETIMER.COLOR.GRAY))
TimexBar:SetScale(id, self.GetOpt("Scale"))
TimexBar:SetText(id, target == "none" and name or target)
TimexBar:SetTexture(id, timer.x.tx or self:GetTexture(name, timer.x))
TimexBar:SetFunction(id, self.StopBar, self, id)
TimexBar:SetClickFunction(id, self.OnClick, self, id, timer.x.rc)
TimexBar:Start(id, timer.x.d and self:GetDuration(timer.d, timer.x.d, rank) or timer.d)
end
function AceTimer:GetDuration(duration, record, rank)
if record.rt then duration = record.rt[rank] or duration end
if record.rs then duration = duration + (rank-1) * record.rs end
if record.cp then duration = duration + (GetComboPoints() - 1) * record.cp end
if record.tn then
if type(record.tn) == "string" then record.tn = self:GetTalentPosition(record.tn) end
local _,_,_,_, tr = GetTalentInfo(unpack(record.tn))
if tr > 0 then
local gain = record.tt and record.tt[tr] or (record.tb + (tr-1) * (record.ts or record.tb))
duration = duration + (record.tp and (duration/100) * gain or gain)
end
end
return duration
end
function AceTimer:GetTexture(name, record)
if record.xn then name = record.xn end
local i = 1
while true do
local nm = GetSpellName(i, BOOKTYPE_SPELL)
if not nm then break
elseif nm == name then
record.tx = GetSpellTexture(i, BOOKTYPE_SPELL)
return record.tx
end
i = i + 1
end
local tp = self:GetTalentPosition(name)
if tp then
local _, tx = GetTalentInfo(unpack(tp))
record.tx = tx
return record.tx
end
if HasPetSpells() then
for i =1, NUM_PET_ACTION_SLOTS do
local nm, _, tx = GetPetActionInfo(i)
if nm == name then record.tx = tx; return record.tx end
end
end
end
function AceTimer:GetTalentPosition(name)
for i = 1, GetNumTalentTabs() do
for j = 1, GetNumTalents(i) do
if GetTalentInfo(i, j) == name then return {i, j} end
end
end
end
--<< ====================================================================== >>--
-- Bar Processing --
--<< ====================================================================== >>--
function AceTimer:CleanGroup(group, target)
local forall = self.groups[group].fa
for i = 1, 20 do
if self.bars[i].group and self.bars[i].group == group then
if forall then
TimexBar:StopBar(self.bars[i].id)
self:StopBar(self.bars[i].id)
elseif self.bars[i].target == target then
TimexBar:StopBar(self.bars[i].id)
self:StopBar(self.bars[i].id)
break
end
end
end
end
function AceTimer:SetPointTOP(id, slot)
return TimexBar:SetPoint(id, "TOP", "AceTimerAnchor", "TOP", 0, (slot * 20))
end
function AceTimer:SetPointBOTTOM(id, slot)
return TimexBar:SetPoint(id, "BOTTOM", "AceTimerAnchor", "BOTTOM", 0, (-5 - (slot * 20)))
end
function AceTimer:KillBar(name, unit)
for i = 1, 20 do
if self.bars[i].id then
if self.bars[i].name == name then
if not unit then
if self.bars[i].timer.k.t then unit = UnitName("player") else unit = "none" end
end
if self.bars[i].target == unit then
TimexBar:StopBar(self.bars[i].id)
return self:StopBar(self.bars[i].id)
end
end
else
break
end
end
end
function AceTimer:KillBars(unit)
if unit and UnitExists("target") and UnitName("target") == unit and not UnitIsDeadOrGhost("target") then return end
for i = 1, 20 do
if self.bars[i].id then
if not unit or self.bars[i].target == unit then
TimexBar:StopBar(self.bars[i].id)
self:StopBar(self.bars[i].id)
end
else
break
end
end
end
function AceTimer:StopBar(id)
for i = 1, 20 do
if self.bars[i].id == id then
for k in self.bars[i] do self.bars[i][k] = nil end
end
end
for i = 1, 19 do
if not self.bars[i].id then
local temp = self.bars[i]
for j = i + 1, 20 do
if self.bars[j].id then
self.bars[i] = self.bars[j]; self.bars[j] = temp; temp = nil
self:SetPoint(self.bars[i].id, i)
break
end
end
if temp then break end
end
end
end
function AceTimer:OnClick(id, reactive)
if arg1 == "RightButton" then
TimexBar:StopBar(id)
self:StopBar(id)
elseif arg1 == "LeftButton" and reactive then
for i = 1, 20 do
if self.bars[i].id == id then
if self.bars[i].rank > 0 then
return CastSpellByName(string.format(ACETIMER.FMT_CAST, self.bars[i].name, self.bars[i].rank))
else
return CastSpellByName(self.bars[i].name)
end
end
end
end
end
--<< ====================================================================== >>--
-- Globalstrings Processing --
--<< ====================================================================== >>--
-- self.gs_patterns
-- self.gs_captured
function AceTimer:FindGlobal(text, global)
local gp = self.gs_patterns[global]
if not gp then
self.gs_patterns[global] = {n=0,}
gp = self.gs_patterns[global]
gp.p = string.gsub(global, "([%[%]%(%)])", "%%%1")
gp.p = string.gsub(gp.p, "%.$", "%%%.")
gp.p = string.gsub(gp.p, "%%(%S-)([sd])", function (a1, a2)
gp.n = gp.n + 1
local _,_, found = string.find(a1, "(%d)%$")
if found then gp[gp.n] = tonumber(found) else gp[gp.n] = gp.n end
if a2 == "s" then return "(.+)"
elseif a2 == "d" then return "(%d+)"
end
end)
end
for k in self.gs_captured do self.gs_captured[k] = nil end
return self:OrderCaptured(gp, string.find(text, gp.p))
end
function AceTimer:OrderCaptured(gp, s, e, ...)
if s then
for i = 1, gp.n do self.gs_captured[gp[i]] = arg[i] end
return TRUE
end
end
--<< ====================================================================== >>--
-- Anchor Processing --
--<< ====================================================================== >>--
function AceTimer:InitAnchor()
local test = {d=10, x={cr=ACETIMER.COLOR.GRAY, tx="Interface\\Icons\\INV_Misc_QuestionMark"} }
AceTimerAnchorText:SetText(ACETIMER.NAME)
AceTimerAnchorTest:SetText(ACETIMER.WORD_TEST)
AceTimerAnchorTest:SetScript("OnClick", function () return self:StartTimer(test, ACETIMER.WORD_TEST, "none", 0) end)
AceTimerAnchorHide:SetText(ACETIMER.WORD_HIDE)
AceTimerAnchorHide:SetScript("OnClick", function () return self:CareOptAnchor() end)
if not self.GetOpt("Scale") then self.SetOpt("Scale", 0.80) end
AceTimerAnchorScaleLow:SetText("0.5")
AceTimerAnchorScaleHigh:SetText("1.5")
AceTimerAnchorScale:SetScript("OnValueChanged", function() return self:OnScaleChanged() end)
AceTimerAnchorScale:SetValue(self.GetOpt("Scale"))
self:SetBarGrowth()
if not self.GetOpt("AnchorHidden") then AceTimerAnchor:Show() end
end
function AceTimer:OnScaleChanged()
local scale = AceTimerAnchorScale:GetValue()
AceTimerAnchorScaleText:SetText(string.format("%.2f", scale))
self.SetOpt("Scale", scale)
for i = 1, 20 do
if self.bars[i].id and TimexBar:CheckBar(self.bars[i].id) then
TimexBar:SetScale(self.bars[i].id, scale)
end
end
end
function AceTimer:OnTestClicked()
self:StartBar(ACETIMER.WORD_TEST.." 1", "none", 0, nil, 15, nil, ACETIMER.COLOR.RED)
self:StartBar(ACETIMER.WORD_TEST.." 2", "none", 0, nil, 10, nil, ACETIMER.COLOR.GREEN)
self:StartBar(ACETIMER.WORD_TEST.." 3", "none", 0, nil, 5, nil, ACETIMER.COLOR.BLUE)
end
function AceTimer:SetBarGrowth()
if self.GetOpt("GrowUp") then
self.SetPoint = self.SetPointTOP
else
self.SetPoint = self.SetPointBOTTOM
end
end
--<< ====================================================================== >>--
-- Command Handlers --
--<< ====================================================================== >>--
function AceTimer:CareOptAnchor()
if self.TogOpt("AnchorHidden") then
AceTimerAnchor:Hide() else AceTimerAnchor:Show()
end
end
function AceTimer:CareOptScale(scale)
scale = tonumber(scale)
if not scale then scale = 0.80 else
if scale < 0.50 then scale = 0.50 elseif scale > 1.50 then scale = 1.50 end
end
AceTimerAnchorScale:SetValue(tonumber(string.format("%.2f", scale)))
self.cmd:result(ACETIMER.OPT_SCALE_TEXT, "|cfff5f530" .. string.format("%.2f", self.GetOpt("Scale")) .. "|r")
end
function AceTimer:CareOptGrow()
self.cmd:result(ACETIMER.OPT_GROW_TEXT, ACETIMER.MAP_DOWNUP[self.TogOpt("GrowUp") or 0])
self:SetBarGrowth()
end
function AceTimer:Report()
self.cmd:report({})
self.cmd:result(ACETIMER.OPT_SCALE_TEXT, "|cfff5f530" .. string.format("%.2f", self.GetOpt("Scale")) .. "|r")
self.cmd:result(ACETIMER.OPT_GROW_TEXT, ACETIMER.MAP_DOWNUP[self.GetOpt("GrowUp") or 0])
self:ReportModules()
end
--<< ====================================================================== >>--
-- Register the Addon --
--<< ====================================================================== >>--
AceTimer:RegisterForLoad()