vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
----------------------------------------------------------------------------
--  TomTom: A navigational assistant for World of Warcraft
--  CrazyTaxi: A crazy-taxi style arrow used for waypoint navigation.
--  concept taken from MapNotes2 (Thanks to Mery for the idea, along
--  with the artwork.)
----------------------------------------------------------------------------
local function log(msg) DEFAULT_CHAT_FRAME:AddMessage(msg) end -- alias for convenience
---------------------------------------------------------------------------------------------------
math.modf = function(number)
    local fractional = Questie:Modulo(number, 1)
    local integral = number - fractional
    return integral, fractional
end
---------------------------------------------------------------------------------------------------
function GetPlayerFacing()
    local p = Minimap
    local m = ({p:GetChildren()})[9]
    return m:GetFacing()
end
---------------------------------------------------------------------------------------------------
local sformat = string.format
local function ColorGradient(perc, tablee)
    local num = table.getn(tablee)
    local hexes = tablee[1] == "string"
    if perc == 1 then
        return tablee[num-2], tablee[num-1], tablee[num]
    end
    num = num / 3
    local segment, relperc = math.modf(perc*(num-1))
    local r1, g1, b1, r2, g2, b2
    r1, g1, b1 = tablee[(segment*3)+1], tablee[(segment*3)+2], tablee[(segment*3)+3]
    r2, g2, b2 = tablee[(segment*3)+4], tablee[(segment*3)+5], tablee[(segment*3)+6]
    if not r1 then return end
    if not r2 or not g2 or not b2 then
        return r1, g1, b1
    else
        return r1 + (r2-r1)*relperc,
            g1 + (g2-g1)*relperc,
            b1 + (b2-b1)*relperc
    end
end
---------------------------------------------------------------------------------------------------
local twopi = math.pi * 2
function WayFrame_OnClick()
    if (MouseIsOver(TomTomCrazyArrow) ~= nil) and (arg1 == "RightButton") then
        TomTomCrazyArrow:Hide()
    end
end
---------------------------------------------------------------------------------------------------
local wayframe = CreateFrame("Button", "TomTomCrazyArrow", UIParent)
wayframe:SetHeight(42)
wayframe:SetWidth(56)
wayframe:SetPoint("CENTER", 0, 0)
wayframe:EnableMouse(true)
wayframe:SetMovable(true)
wayframe:Hide()
-- Frame used to control the scaling of the title and friends
local titleframe = CreateFrame("Frame", nil, wayframe)
wayframe.title = titleframe:CreateFontString("OVERLAY", nil, "GameFontHighlightSmall")
wayframe.status = titleframe:CreateFontString("OVERLAY", nil, "GameFontNormalSmall")
wayframe.tta = titleframe:CreateFontString("OVERLAY", nil, "GameFontNormalSmall")
wayframe.title:SetPoint("TOP", wayframe, "BOTTOM", 0, 0)
wayframe.status:SetPoint("TOP", wayframe.title, "BOTTOM", 0, 0)
wayframe.tta:SetPoint("TOP", wayframe.status, "BOTTOM", 0, 0)
---------------------------------------------------------------------------------------------------
local function OnDragStart(self, button)
    if IsControlKeyDown() and IsShiftKeyDown() then
        this:StartMoving()
        wayframe:SetClampedToScreen(true);
    end
end
---------------------------------------------------------------------------------------------------
local function OnDragStop(self, button)
    this:StopMovingOrSizing()
end
---------------------------------------------------------------------------------------------------
local function OnEvent(self, event, ...)
    if event == "ZONE_CHANGED_NEW_AREA" then
        self:Show()
    end
end
---------------------------------------------------------------------------------------------------
wayframe:SetScript("OnDragStart", OnDragStart)
wayframe:SetScript("OnDragStop", OnDragStop)
wayframe:RegisterForDrag("LeftButton")
wayframe:RegisterEvent("ZONE_CHANGED_NEW_AREA")
wayframe:SetScript("OnEvent", OnEvent)
wayframe.arrow = wayframe:CreateTexture("OVERLAY")
wayframe.arrow:SetTexture("Interface\\AddOns\\!Questie\\Images\\Arrow")
wayframe.arrow:SetAllPoints()
---------------------------------------------------------------------------------------------------
local active_point, arrive_distance, showDownArrow, point_title, arrow_objective, isHide
function SetCrazyArrow(point, dist, title)
    active_point = point
    arrive_distance = dist
    point_title = title
    if active_point and not isHide then
        wayframe.title:SetText(point_title or "Unknown waypoint")
        wayframe:Show()
    else
        wayframe:Hide()
    end
end
---------------------------------------------------------------------------------------------------
function SetArrowFromIcon(icon)
    local targetPoint = {
        ["c"] = icon.data.continent,
        ["z"] = icon.data.zoneid,
        ["x"] = icon.averageX,
        ["y"] = icon.averageY
    }
    local quest = QuestieHashMap[icon.data.questHash]
    local data = {
        ["point"] = targetPoint,
        ["questName"] = quest.name,
        ["questLevel"] = quest.questLevel
    }
    SetArrowFromData(data)
end
---------------------------------------------------------------------------------------------------
function SetArrowFromData(data)
    local colorString = "|c" .. QuestieTracker:GetDifficultyColor(data.questLevel)
    local title = colorString
    title = title .. "[" .. data.questLevel .. "] "
    if QuestieConfig.boldColors then
        title = title .. "|r|cFFFFFFFF" .. data.questName .. "|r"
    else
        title = title .. data.questName .. "|r"
    end
    SetCrazyArrow(data.point, 0, title)
    arrow_objective = nil
    arrow_data = data
end
---------------------------------------------------------------------------------------------------
function SetArrowObjective(hash)
    if arrow_objective == hash then
        wayframe:Hide();
        arrow_objective = 0;
        return;
    end
    arrow_objective = hash
    arrow_data = nil
    if not QuestieCachedQuests[hash] or not QuestieCachedQuests[hash]["arrowPoint"] then return end
    local objective = QuestieCachedQuests[hash]["arrowPoint"]
    SetCrazyArrow(objective, objective.dist, objective.title)
end
---------------------------------------------------------------------------------------------------
function RemoveCrazyArrow(hash)
    if hash then
        if (TomTomCrazyArrow:IsVisible() ~= nil) and (arrow_objective == hash or arrow_data) then
            TomTomCrazyArrow:Hide()
        end
    end
    if (QuestieConfig.arrowEnabled == false) then
        TomTomCrazyArrow:Hide()
    end
end
---------------------------------------------------------------------------------------------------
local status = wayframe.status;
local tta = wayframe.tta;
local arrow = wayframe.arrow;
local arrowLastUpdate = 0;
local LastPlayerPosition = {};
local count = 0;
local last_distance = 0;
local tta_throttle = 0;
local speed = 0;
local speed_count = 0;
local function OnUpdate(self, elapsed)
    local self = this
    local elapsed = 1/GetFramerate()
    local dist,x,y
    if not UnitIsDeadOrGhost("player") then
        if arrow_objective then
            if QuestieCachedQuests[arrow_objective] then
                local objective = QuestieCachedQuests[arrow_objective]["arrowPoint"]
                if objective then
                    SetCrazyArrow(objective, objective.dist, objective.title)
                end
            else
                 self:Hide()
            end
        elseif arrow_data then
            SetArrowFromData(arrow_data)
        end
        if not active_point then
            self:Hide()
            return
        end
    end
    --While dead this maintains the corpseArrow
    if UnitIsDeadOrGhost("player") and (UnitIsDead("player") ~= 1) and (bgactive == false) then
        Questie:OnUpdate(elapsed)
    end
    local dist,x,y = GetDistanceToIcon(active_point)
    if GetTime() - arrowLastUpdate >= .04 then
        if (TomTomCrazyArrow:IsVisible() ~= nil) then
            if not dist or IsInInstance() then
                if not active_point.x and not active_point.y then
                    active_point = nil
                end
                self:Hide()
                return
            end
            status:SetText(sformat("%d yards", dist))
            local cell
            -- Showing the arrival arrow?
            if dist <= 5 then
                if not showDownArrow then
                    arrow:SetHeight(70)
                    arrow:SetWidth(53)
                    arrow:SetTexture("Interface\\AddOns\\!Questie\\Images\\Arrow-UP")
                    arrow:SetVertexColor(0, 1, 0)
                    showDownArrow = true
                end
                count = count + 1
                if count >= 55 then
                    count = 0
                end
                cell = count
                local column = Questie:Modulo(cell, 9)
                local row = floor(cell / 9)
                local xstart = (column * 53) / 512
                local ystart = (row * 70) / 512
                local xend = ((column + 1) * 53) / 512
                local yend = ((row + 1) * 70) / 512
                arrow:SetTexCoord(xstart,xend,ystart,yend)
            else
                if showDownArrow then
                    arrow:SetHeight(56)
                    arrow:SetWidth(42)
                    arrow:SetTexture("Interface\\AddOns\\!Questie\\Images\\Arrow")
                    showDownArrow = false
                end
                local degtemp = GetDirectionToIcon(active_point);
                if degtemp < 0 then degtemp = degtemp + 360; end
                local angle = math.rad(degtemp)
                local player = GetPlayerFacing() + 0.1
                angle = angle - player
                local perc = 1-  math.abs(((math.pi - math.abs(angle)) / math.pi))
                local gr,gg,gb = 1, 1, 1
                local mr,mg,mb = 0.75, 0.75, 0.75
                local br,bg,bb = 0.5, 0.5, 0.5
                local tablee = {};
                table.insert(tablee, gr)
                table.insert(tablee, gg)
                table.insert(tablee, gb)
                table.insert(tablee, mr)
                table.insert(tablee, mg)
                table.insert(tablee, mb)
                table.insert(tablee, br)
                table.insert(tablee, bg)
                table.insert(tablee, bb)
                local r,g,b = ColorGradient(perc,tablee)
                if not g then
                    g = 0;
                end
                arrow:SetVertexColor(1-g,-1+g*2,0)
                cell = Questie:Modulo(floor(angle / twopi * 108 + 0.5), 108);
                local column = Questie:Modulo(cell, 9)
                local row = floor(cell / 9)
                local xstart = (column * 56) / 512
                local ystart = (row * 42) / 512
                local xend = ((column + 1) * 56) / 512
                local yend = ((row + 1) * 42) / 512
                arrow:SetTexCoord(xstart,xend,ystart,yend)
            end
            arrowLastUpdate = GetTime()
        end
    end
    if (QuestieConfig.arrowTime == true) then
        -- Calculate the TTA every second  (%01d:%02d)
        tta_throttle = tta_throttle + elapsed
        if tta_throttle >= 1 then
            -- Calculate the speed in yards per sec at which we're moving
            local current_speed = (last_distance - dist) / tta_throttle
            if last_distance == 0 then
                current_speed = 0
            end
            if speed_count < 2 then
                speed = (speed + current_speed) / 2
                speed_count = speed_count + 1
            else
                speed_count = 0
                speed = current_speed
            end
            if speed > 0 then
                local eta = math.abs(dist / speed)
                local text = string.format("%01d:%02d", eta / 60, Questie:Modulo(eta, 60))
                tta:SetText(text)
            else
                tta:SetText("***")
            end
            last_distance = dist
            tta_throttle = 0
        end
    end
end
---------------------------------------------------------------------------------------------------
function ShowHideCrazyArrow()
    if wayframe:IsShown() then
        wayframe:Show()
        if true then
            wayframe:EnableMouse(false)
        else
            wayframe:EnableMouse(true)
        end
        -- Set the scale and alpha
        wayframe:SetScale(1)
        wayframe:SetAlpha(1)
        local width = 80
        local height = 80
        local scale = 1
        wayframe.title:SetWidth(width)
        wayframe.title:SetHeight(height)
        titleframe:SetScale(scale)
        titleframe:SetAlpha(1)
                if true then
                        tta:Show()
                else
                        tta:Hide()
        end
    else
        wayframe:Hide()
    end
end
---------------------------------------------------------------------------------------------------
function ArrowHidden()
    isHide = true
end
---------------------------------------------------------------------------------------------------
function ArrowShown()
    isHide = false
end
---------------------------------------------------------------------------------------------------
wayframe:SetScript("OnUpdate", OnUpdate)
wayframe:RegisterForClicks("RightButtonUp")
wayframe:SetScript("OnClick", WayFrame_OnClick)
local function getCoords(column, row)
    local xstart = (column * 56) / 512
    local ystart = (row * 42) / 512
    local xend = ((column + 1) * 56) / 512
    local yend = ((row + 1) * 42) / 512
    return xstart, xend, ystart, yend
end
---------------------------------------------------------------------------------------------------
--this is where texcoords are extracted incorrectly (I think), leading the arrow to not point in the correct direction
local texcoords = setmetatable({}, {__index = function(t, k)
    -- this was k:match("(%d+):(%d+)") - so we need string.match, but that's not in Lua 5.0
    local fIndex, lIndex = string.find(k, "(%d+)")
    local col = string.sub(k, fIndex, lIndex)
    fIndex2, lIndex2 = string.find(k, ":(%d+)")
    local row = string.sub(k, fIndex2+1, lIndex2)
    col,row = tonumber(col), tonumber(row)
    local obj = {getCoords(col, row)}
    rawset(t, k, obj)
    return obj
end})
---------------------------------------------------------------------------------------------------
wayframe:RegisterEvent("ADDON_LOADED")
local runonce = true
wayframe:SetScript("OnEvent", function(self, event, arg1, ...)
    if runonce == true then
        local feed_crazy = CreateFrame("Frame")
        local crazyFeedFrame = CreateFrame("Frame")
        local throttle = 1
        local counter = 0
        crazyFeedFrame:SetScript("OnUpdate", function(self, elapsed)
            elapsed = 1/GetFramerate()
            counter = counter + elapsed
            if counter < throttle then
                return
            end
            counter = 0
            local angle = GetDirectionToIcon(active_point)
            local player = GetPlayerFacing()
            if not angle or not player then
                feed_crazy.iconCoords = texcoords["1:1"]
                feed_crazy.iconR = 0.2
                feed_crazy.iconG = 1.0
                feed_crazy.iconB = 0.2
                feed_crazy.text = "No waypoint"
                return
            end
            angle = angle - player
            local perc = math.abs((math.pi - math.abs(angle)) / math.pi)
            local gr,gg,gb = 1, 1, 1
            local mr,mg,mb = 0.75, 0.75, 0.75
            local br,bg,bb = 0.5, 0.5, 0.5
            local tablee = {};
            table.insert(tablee, gr)
            table.insert(tablee, gg)
            table.insert(tablee, gb)
            table.insert(tablee, mr)
            table.insert(tablee, mg)
            table.insert(tablee, mb)
            table.insert(tablee, br)
            table.insert(tablee, bg)
            table.insert(tablee, bb)
            local r,g,b = ColorGradient(perc, tablee)
            feed_crazy.iconR = r
            feed_crazy.iconG = g
            feed_crazy.iconB = b
            cell = Questie:Modulo(floor(angle / twopi * 108 + 0.5) ,108)
            local column = Questie:Modulo(cell, 9)
            local row = floor(cell / 9)
            local key = column .. ":" .. row
            feed_crazy.iconCoords = texcoords[key]
            feed_crazy.text = point_title or "Unknown waypoint"
        end)
    end
    runonce = false
end)
---------------------------------------------------------------------------------------------------
-- calculations have to be redone - we are NOT actually working with Astrolabe "icons" here as TomTom did and want the arrow API
-- to be accessible to everyone
function GetDirectionToIcon( point )
    if not point then return end
    local C,Z,X,Y = Astrolabe:GetCurrentPlayerPosition() -- continent, zone, x, y
    local dist, xDelta, yDelta = Astrolabe:ComputeDistance( C, Z, X, Y, point.c, point.z, point.x, point.y )
    if not xDelta or not yDelta then return end
    local dir = atan2(xDelta, -(yDelta))
    if ( dir > 0 ) then
        return twopi - dir;
    else
        return -dir;
    end
end
---------------------------------------------------------------------------------------------------
function GetDistanceToIcon( point )
    local C,Z,X,Y = Astrolabe:GetCurrentPlayerPosition() -- continent, zone, x, y
    local dist, xDelta, yDelta = Astrolabe:ComputeDistance( C, Z, X, Y, point.c, point.z, point.x, point.y )
    return dist, xDelta, yDelta
end