WoWInterface SVN Blessed

[/] [Blessed.lua] - Rev 2

Compare with Previous | Blame | View Log

--[[
        Blessed
        by Ailae of Emeriss-EU
        
        Credits to zork (of Roth UI) for texture.
]]

local ADDON, ns = ...
local pguid
local locked = true

-- default position
local defaults = {
        framePoint = "CENTER",
        xOfs = 0,
        yOfs = -150,
}
local db

-- cosmetics
local font = SystemFont_Shadow_Med1
local fontTimer = SystemFont_Shadow_Large
local iconSize = 36

local Blessed = CreateFrame("Frame", "Blessed_Anchor", UIParent)
Blessed:RegisterEvent("ADDON_LOADED")

Blessed:SetScript("OnEvent", function(self, event, ...)
    self[event](self, ...)
end)

-- Add a prefix
local function Print(output)
        print("|cff00aaffBlessed:|r " .. output)
end

-- Format: [spell] = (duration) 
local spells = {
        [1044] = 6, -- Hand of Freedom
        [1022] = 10, -- Hand of Protection
        [6940] = 12, -- Hand of Sacrifice
        [1038] = 10, -- Hand of Salvation
        [53563] = 300, -- Light's Beacon
        [54428] = 15, -- Divine Plea
        [53657] = 60, -- Judgement of the Pure (Rank 3, but who hasn't got 3/3 in this?)
        [87342] = 20, -- Holy Shield
        [84963] = 12, -- Inquisition 
        [82327] = 10, -- Holy Radiance
        -- [88819] = 12, -- Daybreak
        [85433] = 15, -- Sacred Duty
        [94686] = 15, -- Crusader
        [54149] = 15, -- Infusion of Light
}

-- Empty tables for our frames
local frames = {}
local framePool = {}

function Blessed:Init()
        self:SetBackdrop({
                bgFile = [=[Interface\ChatFrame\ChatFrameBackground]=],
                insets = {top = 0, left = 0, bottom = 0, right = 0},
        })
        self:SetBackdropColor(1, 1, 1, 0)

        self:SetWidth(iconSize)
        self:SetHeight(iconSize)
        self:SetPoint(db.framePoint, db.xOfs, db.yOfs)

        self:SetMovable(true)

        -- yeh bebe, move it!
        self:SetScript("OnMouseDown", function()
                if(IsShiftKeyDown() and not locked) then
                        self:ClearAllPoints()
                        self:StartMoving()
                end
        end)

        self:SetScript("OnMouseUp", function()
                self:StopMovingOrSizing()
                db.framePoint, _, _, db.xOfs, db.yOfs = self:GetPoint()
        end)

        local text = self:CreateFontString(nil, "OVERLAY")
        text:SetFontObject(font)
        text:SetPoint("TOP", self, "TOP", 0, 16)
        text:SetTextColor(1, 0.82, 0)
        text:SetText("")
        self.header = text
end

function Blessed:ADDON_LOADED(name)
        if name ~= "Blessed" then return end
        self:UnregisterEvent("ADDON_LOADED")
        
        BlessedDB = BlessedDB or defaults
        db = BlessedDB
        
        local class = select(2, UnitClass("player"))
        if class == "PALADIN" then -- only do stuff if player is a paladin
                self:RegisterEvent("PLAYER_ENTERING_WORLD")
                self:Init()
                
                SLASH_Blessed1 = "/blessed"
                SlashCmdList.Blessed = function(input)
                        local input = string.lower(input)
                        if (input == "test") then
                                self:SetupIcon(54428, "Test Icon", pguid, pguid)
                                Print("Showing test-timer.")
                        elseif (input == "lock") then
                                if locked then
                                        self:EnableMouse(true)
                                        locked = false
                                        self.header:SetText("Blessed")
                                        self:SetBackdropColor(1, 1, 1, 0.25)
                                        Print("Unlocked. Press down SHIFT and drag the square to move.")
                                else 
                                        self:EnableMouse(false)
                                        locked = true
                                        self.header:SetText("")
                                        self:SetBackdropColor(1, 1, 1, 0)
                                        Print("Locked.")
                                end
                        elseif (input == "debug") then
                                Print("Number of frames in the pool: " .. (#framePool or 0))
                                Print("Current durations:")
                                for k, v in pairs(spells) do
                                        local name, _, _, _, _, _, _, _, _ = GetSpellInfo(k)
                                        if not name then Print("No value for key: " .. k) end
                                        Print(name .. ": " .. v)
                                end
                        else
                                Print("Incorrect or no command given. Please use '/blessed test' (display a test-timer) or '/blessed lock' (to toggle lock).")
                        end
                end
        else
                print("This addon has no use for any other class than a Paladin, you should consider disabling it for this character.")
        end     
end

-- Only activate buff-tracking if the player is a paladin
function Blessed:PLAYER_ENTERING_WORLD()
        self:UnregisterEvent("PLAYER_ENTERING_WORLD")
        self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
        
        pguid = UnitGUID("player")
        
        -- this is to make sure talents are loaded or if we need
        -- to delay the check
        if (GetNumTalentTabs() == 0) then
                self:RegisterEvent("PLAYER_ALIVE")
        else
                self:UpdateDurations()
        end     
        
        self:RegisterEvent("CHARACTER_POINTS_CHANGED")
        self:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED")
end

-- Talents are only available at this point when you're logging in
-- so we need to update durations.
function Blessed:PLAYER_ALIVE()
        self:UpdateDurations()
        self:UnregisterEvent("PLAYER_ALIVE")
end

-- Check talents for updates
function Blessed:UpdateDurations()
        -- Hand of Freedom
        local _, _, _, _, rank, maxRank, _, _ = GetTalentInfo(3, 4)
        if rank == maxRank then
                spells[1044] = 10
        else
                spells[1044] = 6
        end
end

-- Perform checks for all these events
Blessed.CHARACTER_POINTS_CHANGED = Blessed.UpdateDurations
Blessed.ACTIVE_TALENT_GROUP_CHANGED = Blessed.UpdateDurations

-- Handle stuff, plx
function Blessed:COMBAT_LOG_EVENT_UNFILTERED(timestamp, combatEvent, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags, ...)
        if sourceGUID and sourceGUID ~= pguid then return end
        
        if (combatEvent == "SPELL_AURA_REMOVED") then
                local spellID, _, _, _ = select(1, ...)
                if spells[spellID] then
                        self:RemoveFrame(spellID .. sourceGUID .. destGUID)
                end
        elseif (combatEvent == "SPELL_AURA_APPLIED") then
                local spellID, spellName, _, _ = select(1, ...)
                if (spells[spellID]) then
                        -- special handling for Inquisition, sigh
                        if spellID == 84963 and spellName then 
                                local duration, expirationTime = select(6, UnitAura("player", spellName))
                                spells[84963] = duration
                        end
                        self:SetupIcon(spellID, destName, sourceGUID, destGUID)
                end
        elseif (combatEvent == "SPELL_AURA_REFRESH") then
                local spellID, spellName, _, _ = select(1, ...)
                if (spells[spellID]) then
                        self:RemoveFrame(spellID .. sourceGUID .. destGUID)
                        -- special handling for Inquisition, sigh
                        if spellID == 84963 and spellName then 
                                local duration, expirationTime = select(6, UnitAura("player", spellName))
                                spells[84963] = duration
                        end                     
                        self:SetupIcon(spellID, destName, sourceGUID, destGUID)
                end
        end
end

-- Reanchor frames
-- If it's frame #1, anchor it to anchorframe (teehee). If it's frame #n (!1) anchor it to the right of frame #n-1.
function Blessed:UpdateFrames()
        if #frames == 0 then return end
        
        for i, frame in ipairs(frames) do
                frame:ClearAllPoints()
                if i > 1 then
                        frame:SetPoint("LEFT", frames[i - 1], "RIGHT", 15, 0)
                else
                        frame:SetPoint("CENTER", self, "CENTER")
                end
        end
end

-- Remove bar
function Blessed:RemoveFrame(id)
        if #frames == 0 then return end
        
        for i, frame in pairs(frames) do
                if frame.id == id then
                        frame:Hide()
                        table.remove(frames, i)
                        table.insert(framePool, frame)
                        self:UpdateFrames() -- reanchor frames
                end
        end
end

-- Update barinfo
local function update(self, elapsed)
        self.time = GetTime()
        if self.time - self.lastUpdate < 1 then return end
        
        self.duration = self.duration - (self.time - self.lastUpdate)
        self.lastUpdate = self.time
        self.timer:SetTextColor(1, 1, 1)
        if self.duration > 60 then
                self.timer:SetFormattedText("%.0fm", ceil(self.duration/60))
        else
                self.timer:SetFormattedText("%.0f", floor(self.duration))
        end
        
        
        if self.duration <= 0 then              
                Blessed:RemoveFrame(self.id) 
        elseif self.duration <= 5 then -- indicate that there is equalorless than 5 secs left
                self.timer:SetTextColor(1, 0, 0)
        end
end

-- Framemananger, return a new frame if there's no old frame available 
function Blessed:GetFrame()
        if (#framePool > 0) then
                return table.remove(framePool, 1)
        end
        
        local frame = CreateFrame("Frame", nil, UIParent)
        frame:SetHeight(iconSize)
        frame:SetWidth(iconSize)
        frame:SetPoint("CENTER", self)
        
        -- Icon
        frame.icon = frame:CreateTexture(nil, "ARTWORK")
        frame.icon:SetHeight(iconSize)
        frame.icon:SetWidth(iconSize)
        frame.icon:SetTexCoord(0.03, 0.97, 0.02, 0.97)
        frame.icon:SetAllPoints(frame)
        
        -- Targettext
        frame.target = frame:CreateFontString(nil, "OVERLAY")
        frame.target:SetFontObject(font)
        frame.target:SetPoint("BOTTOM", frame, "TOP", 0, 5)
        frame.target:SetTextColor(1, 1, 1) 
        frame.target:SetShadowOffset(1, -1)
        
        -- Timertext
        frame.timer = frame:CreateFontString(nil, "OVERLAY")
        frame.timer:SetFontObject(fontTimer)
        frame.timer:SetPoint("TOP", frame, "BOTTOM", 0, -5)
        frame.timer:SetTextColor(1, 1, 1)
        frame.timer:SetShadowOffset(1, -1)      
        
        -- Cooldown-model (beta)
        frame.cd = CreateFrame("Cooldown", nil, frame, "CooldownFrameTemplate")
        frame.cd:SetHeight(iconSize)
        frame.cd:SetWidth(iconSize)
        frame.cd:SetPoint("TOPLEFT", frame, "TOPLEFT", 2, -2)
        frame.cd:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -2, 2)
        frame.cd.noCooldownCount = true -- prevent OmniCC if present
        
        -- Overlay
        frame.overlay = CreateFrame("Frame", nil, frame)
        frame.overlay:SetAllPoints(frame)
        frame.overlay:SetParent(frame)
        
        -- Border
        frame.border = frame.overlay:CreateTexture(nil, "OVERLAY")
        frame.border:SetParent(frame)
        frame.border:SetTexture('Interface\\AddOns\\Blessed\\simplesquare_roth')
        frame.border:SetPoint('TOPRIGHT', frame, 2, 2)
        frame.border:SetPoint('BOTTOMLEFT', frame, -2, -2)
        frame.border:SetVertexColor(0.3, 0.3, 0.3)
        
        return frame
end

-- Setup a timer
local color = {}
function Blessed:SetupIcon(spellID, targetName, sourceGUID, targetGUID)
        local frame = self:GetFrame()
        local duration = spells[spellID]
        local icon = select(3, GetSpellInfo(spellID))
        
        targetName = string.sub(targetName, 0, 3)
        local class = select(2, GetPlayerInfoByGUID(targetGUID))
        
        if targetGUID == pguid then
                targetName = "You!"
                class = "PALADIN"
        end     
        
        frame.icon:SetTexture(icon)
        
        color = RAID_CLASS_COLORS[class] or { r = 1, g = 1, b =1 }
        frame.target:SetTextColor(color.r, color.g, color.b)
        frame.target:SetText(targetName or "Unknown")

        if duration > 60 then
                frame.timer:SetFormattedText("%.0fm", ceil(duration/60))
        else
                frame.timer:SetFormattedText("%.0f", floor(duration))
        end     
        frame.timer:SetTextColor(1, 1, 1)
        
        -- Nifty stuff
        frame.duration = duration
        frame.id = spellID .. sourceGUID .. targetGUID
        frame.lastUpdate = GetTime()
        frame.cd:SetCooldown(GetTime(), duration)
        table.insert(frames, frame)

        frame:SetScript("OnUpdate", update)     
        
        -- when a frame is shown, reanchor all the frames accordingly
        self:UpdateFrames()
        
        frame:Show()
end

Compare with Previous | Blame