vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
local tablet = AceLibrary("Tablet-2.0")
local abacus = AceLibrary("Abacus-2.0")

local L = AceLibrary("AceLocale-2.2"):new("FuBar_ToFu")
ToFu = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceHook-2.0", "AceConsole-2.0", "AceDB-2.0", "FuBarPlugin-2.0")

ToFu:RegisterDB("ToFuDB")
ToFu:RegisterDefaults('account', {
        paths = {
                Alliance = {['*']={}},
                Horde = {['*']={}},
        },
})
ToFu:RegisterDefaults('profile', {
        hook = {
                oCD = false,
                oCB = false,
                BigWigs = false,
                Chronometer = false,
        },
})
local optionsTable = {
        handler = ToFu,
        type = 'group',
        args = {
                hook = {
                        type = 'group', name = L['Hooks'],
                        desc = L['Other addons to hook into'],
                        args = {
                                oCD = {
                                        type = 'toggle', name = 'oCD',
                                        desc = 'otravi_CoolDown',
                                        get = function() return ToFu.db.profile.hook.oCD end,
                                        set = function(t) ToFu.db.profile.hook.oCD = t end,
                                        disabled = function()
                                                if oCD then return false
                                                else return true end
                                        end,
                                },
                                oCB = {
                                        type = 'toggle', name = 'oCB',
                                        desc = 'otravi_CastBar',
                                        get = function() return ToFu.db.profile.hook.oCB end,
                                        set = function(t) ToFu.db.profile.hook.oCB = t end,
                                        disabled = function()
                                                if oCB then return false
                                                else return true end
                                        end,
                                },
                                BigWigs = {
                                        type = 'toggle', name = 'BigWigs',
                                        desc = 'BigWigs_CustomBar',
                                        get = function() return ToFu.db.profile.hook.BigWigs end,
                                        set = function(t) ToFu.db.profile.hook.BigWigs = t end,
                                        disabled = function()
                                                if BigWigs and BigWigsCustomBar then return false
                                                else return true end
                                        end,
                                },
                                Chronometer = {
                                        type = 'toggle', name = 'Chronometer',
                                        desc = 'Chronometer',
                                        get = function() return ToFu.db.profile.hook.Chronometer end,
                                        set = function(t) ToFu.db.profile.hook.Chronometer = t end,
                                        disabled = function()
                                                if Chronometer then return false
                                                else return true end
                                        end,
                                },
                        },
                },
                data = {
                        type = 'group', name = L['Data'],
                        desc = L["Various options to do with saved flight data"],
                        args = {
                                clear = {
                                        type = 'execute', name = L['Clear Data'],
                                        desc = L["Delete *ALL* saved flight path data for your faction."],
                                        func = "ClearData",
                                },
                                default = {
                                        type = 'execute', name = L['Default Data'],
                                        desc = L["Load the default flight-time dataset."],
                                        func = function() ToFu:LoadDefaults() end, disabled = function() return type(ToFu.LoadDefaults) ~= 'function' end,
                                },
                        },
                },
        },
}

ToFu:RegisterChatCommand({"/tofu",}, optionsTable)
ToFu.OnMenuRequest = optionsTable

ToFu.version = "2.0." .. string.sub("$Revision: 15647 $", 12, -3)
ToFu.date = string.sub("$Date: 2006-10-31 20:34:49 -0500 (Tue, 31 Oct 2006) $", 8, 17)
ToFu.hasIcon = "Interface\\TaxiFrame\\UI-Taxi-Icon-Green"
ToFu.hideWithoutStandby = true

function ToFu:OnInitialize()
        self.start = nil
        self.destination = nil
        self.inFlight = false
        self.timeFlown = 0
        self.avgTime = nil
        self.last, self.nodes, self.steps = {}, {}, {}

        --Stolen from AceDB
        local _,race = UnitRace("player")
        if race == "Orc" or race == "Scourge" or race == "Troll" or race == "Tauren" then
                self.faction = 'Horde'
        else
                self.faction = 'Alliance'
        end

        if not self.db.account.version then
                self:ScheduleEvent(function()
                        --Check to see whether we need to shrink the database.
                        for faction, data in self.db.account.paths do
                                self:Print('Upgrading', faction, 'flight data')
                                --Convert the old data to the new format, and clear out the old DB in the process.
                                if type(data) ~= 'table' then data = nil
                                else
                                        local newdata = {}
                                        for start,dests in pairs(data) do
                                                local newstart = self:LessName(start)
                                                newdata[newstart] = {}
                                                if type(dests) == 'table' then
                                                        for dest, info in pairs(dests) do
                                                                newdata[newstart][self:LessName(dest)] = info
                                                                data[start][dest] = nil
                                                        end
                                                end
                                                data[start] = nil
                                        end
                                        --Now apply the new data to the DB.
                                        --(Can't merge this with the previous step, as it would be editing the table while looping over it.)
                                        for start, dests in pairs(newdata) do
                                                for dest, info in pairs(dests) do
                                                        if not self.db.account.paths[start] then self.db.account.paths[start] = {} end
                                                        self.db.account.paths[start][dest] = info
                                                end
                                        end
                                end
                        end
                        
                        self.db.account.version = 1
                end, 1)
        end
end

function ToFu:OnEnable()
        self:RegisterEvent("TAXIMAP_OPENED")
        self:Hook("TakeTaxiNode")
        self:Hook("TaxiNodeOnButtonEnter")
end


function ToFu:OnTextUpdate()
        if self.inFlight then
                if self.timeAvg ~= 0 then
                        --Time remaining, if we've taken this path before.
                        self:SetText(abacus:FormatDurationCondensed(self.timeAvg - self.timeFlown, true))
                else
                        --Time flown so far.
                        self:SetText(abacus:FormatDurationCondensed(self.timeFlown, true))
                end
        else
                self:SetText('')
        end
end

function ToFu:OnTooltipUpdate()
        local cat = tablet:AddCategory(
                'columns', 2,
                'text', L["Current Flight"],
                'child_textR', 1, 'child_textG', 0.82, 'child_textB', 0,
                'child_text2R', 1, 'child_text2G', 1, 'child_text2B', 1
        )
        if self.inFlight then
                cat:AddLine('text', L["From"], 'text2', self.start)
                cat:AddLine('text', L["To"], 'text2', self.destination)
                cat:AddLine('text', L["Time Taken"], 'text2', abacus:FormatDurationCondensed(self.timeFlown, true))
                cat:AddLine('text', L["Average Time"], 'text2', abacus:FormatDurationCondensed(self.timeAvg, true))
                cat:AddLine('text', L["Cost"], 'text2', abacus:FormatMoneyCondensed(self.cost, true))
        else
                cat:AddLine('text', L["Not in flight"])
        end

        cat = tablet:AddCategory(
                'columns', 2,
                'text', L["Previous Flight"],
                'child_textR', 1, 'child_textG', 0.82, 'child_textB', 0,
                'child_text2R', 1, 'child_text2G', 1, 'child_text2B', 1
        )
        if self.last.start ~= nil then
                cat:AddLine('text', L["From"], 'text2', self.last.start)
                cat:AddLine('text', L["To"], 'text2', self.last.destination)
                cat:AddLine('text', L["Time Taken"], 'text2', abacus:FormatDurationCondensed(self.last.time, true))
                cat:AddLine('text', L["Cost"], 'text2', abacus:FormatMoneyCondensed(self.last.cost, true))
        else
                cat:AddLine('text', L["No previous flight"])
        end

        if self.inFlight then
                tablet:SetHint(L["Click to copy the time remaining in flight to the chatbox."])
        end
end

function ToFu:OnClick()
        -- Paste time remaining to chatbox.
        if ChatFrameEditBox:IsVisible() and self.inFlight then
                local text = ""
                local _, time = self:GetFlightData(self.start, self.destination)

                if time ~= 0 then
                        --Time remaining, if we've taken this path before.
                        text = abacus:FormatDurationFull(time - self.timeFlown, false)
                else
                        --Time flown so far.
                        text = string.format("??? (%s %s)", abacus:FormatDurationFull(self.timeFlown, false), L["So Far"])
                end

                ChatFrameEditBox:Insert(text)
        end
end


function ToFu:OnUpdate(timeSinceLast)
        self.timeFlown = self.timeFlown + timeSinceLast
        if (UnitOnTaxi("player") ~= 1) and (self.timeFlown > 5) then
                -- Cheap test to make sure that we don't do all this right at the beginning of a flight
                self:CancelScheduledEvent(self.name)
                self.inFlight = false

                local cost, time, taken = self:GetFlightData(self.start, self.destination)

                --Average time this route has taken (there's a chance we'll be getting inaccuracies, etc.):
                if time ~= 0 then
                        time = (time + self.timeFlown) / 2
                        
                        if self.db.profile.hook.oCB and oCB then
                                oCB:SpellStop(true)
                        end
                else
                        time = self.timeFlown
                end

                self:SaveFlightData(self.start, self.destination, cost, time, taken + 1)

                self.last.start = self.start
                self.last.destination = self.destination
                self.last.time = self.timeFlown
                self.last.cost = cost

                self.start = nil
                self.destination = nil
                self.timeFlown = nil
        end
        self:UpdateDisplay()
end


function ToFu:TAXIMAP_OPENED()
        local numNodes = NumTaxiNodes()
        -- Have to scan all the slots first to get the "CURRENT" slot.
        for i=1, numNodes do
                if TaxiNodeGetType(i) == "CURRENT" then
                        self.start = TaxiNodeName(i)
                else
                        local x,y = TaxiNodePosition(i)
                        self.nodes[x..':'..y] = i
                end
        end
end

function ToFu:TakeTaxiNode(slot)
        if TaxiNodeGetType(slot) == "REACHABLE" then
                self.destination = TaxiNodeName(slot)
                self.timeFlown = 0
                self.inFlight = true

                self.cost, self.timeAvg = self:GetFlightData(self.start, self.destination)

                if self.timeAvg ~= 0 then
                        if self.db.profile.hook.oCD and oCD then
                                --oCD:StartBar(id, time, text, icon)
                                oCD:StartBar('ToFu', self.timeAvg, self:LessName(self.destination), "Interface\\TaxiFrame\\UI-Taxi-Icon-Green")
                        end
                        if self.db.profile.hook.oCB and oCB then
                                --oCB:SpellStart(text, time, inSeconds, dontRegister)
                                oCB:SpellStart(self:LessName(self.destination), self.timeAvg, true, true)
                        end
                        if self.db.profile.hook.BigWigs and BigWigs and BigWigsCustomBar then
                                --BWCB(seconds, message)
                                BWLCB(self.timeAvg, "Flying to "..self:LessName(self.destination))
                        end
                        if self.db.profile.hook.Chronometer and Chronometer then
                                -- Chronometer:AddTimer(kind, name, duration, targeted, isgain, selforselect, extra)
                                if not Chronometer.timers[Chronometer.SPELL]['ToFu'] then Chronometer:AddTimer(Chronometer.SPELL, 'ToFu', self.timeAvg, 0, 0, 0) end
                                Chronometer:StartTimer(Chronometer.timers[Chronometer.SPELL]['ToFu'], self:LessName(self.destination))
                        end
                end

                for key in pairs(self.nodes) do self.nodes[key] = nil end

                self:ScheduleRepeatingEvent(self.name, self.OnUpdate, 1, self, 1)
        end
        self.hooks["TakeTaxiNode"].orig(slot)
end

function ToFu:TaxiNodeOnButtonEnter(button)
        self.hooks["TaxiNodeOnButtonEnter"].orig(button)

        local index = button:GetID()
        if TaxiNodeGetType(index) == "REACHABLE" then
                local destination, cost = TaxiNodeName(index), TaxiNodeCost(index)
                local oldcost, time, taken = self:GetFlightData(self.start, destination)
                if oldcost ~= cost then self:SaveFlightData(self.start, destination, cost, time, taken) end

                local estimate = ''
                if time == 0 then
                        --Try to estimate.  This is mainly stolen from Blizzard's TaxiFrame.lua, which uses a much more in-depth version of this to draw the lines.
                        local _,reversetime = self:GetFlightData(destination, self.start)
                        if reversetime > 0 then
                                time = reversetime
                                estimate = L['reversed']
                        else
                                local numRoutes = GetNumRoutes(index)
                                if numRoutes > 1 then
                                        TaxiNodeSetCurrent(index) --This is magic -- it renumbers the 'hops' between index and current so the for loop below works.
                                        self.steps[1] = self.start

                                        local length = 0
                                        for i=1, numRoutes do
                                                local l, dx, dy = self:LineLength(index, i)
                                                length = length + l 
                                                
                                                self.steps[i+1] = TaxiNodeName(self.nodes[dx..':'..dy])
                                        end

                                        local skipped = 0
                                        local node = 1
                                        while node <= numRoutes do
                                                --self.steps[node] is the 'current' node.
                                                --Step backwards through self.steps to find the longest interval that gives us a time.
                                                local nnode = numRoutes+1
                                                while nnode > node do
                                                        local _,t = self:GetFlightData(self.steps[node], self.steps[nnode])
                                                        if t==0 then _,t = self:GetFlightData(self.steps[nnode], self.steps[node]) end
                                                        nnode = nnode - 1
                                                        if t > 0 then
                                                                -- We know this!  Add it to the time and skip the rest of the loops.
                                                                time = time + t
                                                                break
                                                        elseif nnode == node then
                                                                -- We have no idea.  Mark down that we skipped this.
                                                                skipped = skipped + self:LineLength(index, node-1) -- Is 'node-1' right here?
                                                                break
                                                        end
                                                end
                                                node = nnode + 1
                                        end
                                        if time > 0 then
                                                if skipped > 0 then time = time + ((time/(length-skipped)) * skipped) end
                                                estimate = ' '..L['estimated']
                                        end

                                        for key in pairs(self.steps) do self.steps[key] = nil end
                                end
                        end
                end

                GameTooltip:AddLine(L["Takes"]..": "..abacus:FormatDurationCondensed(time)..estimate, 1, 1, 1)
                GameTooltip:AddLine(string.format(L["Flown %s times"], taken), 1, 1, 1)
                GameTooltip:SetHeight(GameTooltip:GetHeight() + 28)
        end
end

function ToFu:LessName(s)
        --For "Thelsamar, Loch Modan" return "Thelsamar".
    if not s then return '' end
        if ( GetLocale() ~= "koKR" ) then
                local c = string.find(s, ', ')
                if c then s = string.sub(s, 1, c-1) end
        else
                local c = string.find(s, ' %(')
                if c then _,_,s = string.find(s, "(.-) %(") end
        end
        return s
end

-- Data in format: ":1000:120:3:"
-- Means: "cost 1000 copper, taking 120 seconds, taken 3 times."

function ToFu:GetFlightData(start, destination, faction)
        -- cost, time, taken = ToFu:GetFlightData(start, destination, faction)
        -- Fetches the saved information about a flight path, from [start] to [destination].
        -- If any arguments are left as nil, the current value of self.<<argument>> will be used.
        local s = self.db.account.paths[faction or self.faction][self:LessName(start or self.start)][self:LessName(destination or self.destination)]
        if type(s) ~= 'string' then return 0,0,0 end
        local _, _, cost, time, taken = string.find(s, ":(%d+):(%d+):(%d+):")
        return (tonumber(cost) or 0), (tonumber(time) or 0), (tonumber(taken) or 0), self:LessName(start or self.start), self:LessName(destination or self.destination)
end

function ToFu:SaveFlightData(start, destination, cost, time, taken, faction)
        self.db.account.paths[faction or self.faction][self:LessName(start)][self:LessName(destination)] = ':'..(cost or 0)..':'..math.floor((time and tonumber(time) or 0))..':'..(taken or 0)..':'
        return true
end

function ToFu:ClearData()
        self.db.account.paths[self.faction] = {}
end

function ToFu:LineLength(index, i)
        --Start node:
        local sx = TaxiGetSrcX(index, i)
        local sy = TaxiGetSrcY(index, i)
        --End node:
        local ex = TaxiGetDestX(index, i)
        local ey = TaxiGetDestY(index, i)
        -- Determine dimensions
        local dx,dy = ex - sx, ey - sy;
        -- Normalize direction if necessary
        if (dx < 0) then
                dx,dy = -dx,-dy;
        end
        -- Return length and endpoint coords.
        return sqrt((dx * dx) + (dy * dy)), ex, ey
end

Generated by GNU Enscript 1.6.5.90.