Advertisement
alanm26

Questking Proving Grounds fixes

Sep 24th, 2013
203
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 82.56 KB | None | 0 0
  1. local addonName, QuestKing = ...
  2. local opt = QuestKing.options
  3.  
  4. -- quest "The Arena of Annihilation" is in "Kun-Lai Summit" zone header...
  5.  
  6. ---- Options
  7.  
  8. -- low freq
  9.  
  10. local opt_font = opt.font
  11. local opt_fontChallengeTimer = opt.fontChallengeTimer
  12. local opt_fontSize = opt.fontSize
  13.  
  14. local opt_fontStyle = opt.fontStyle
  15. local opt_fontLayer = opt.fontLayer
  16.  
  17. local opt_positionPresets = opt.positionPresets
  18. local opt_tooltipAnchor = opt.tooltipAnchor
  19. local opt_tooltipScale = opt.tooltipScale
  20. local opt_enableItemPopups = opt.enableItemPopups
  21.  
  22. local opt_subzoneHeuristicHighlight = opt.subzoneHeuristicHighlight
  23.  
  24. -- high freq
  25.  
  26. local opt_buttonWidth = opt.buttonWidth
  27. local opt_lineHeight = opt.lineHeight
  28. local opt_titleHeight = opt.titleHeight
  29.  
  30. local opt_itemAnchorSide = opt.itemAnchorSide
  31. local opt_showCompletedObjectives = opt.showCompletedObjectives
  32. local opt_updateRate = opt.updateRate
  33. local opt_colors = opt.colors
  34.  
  35.  
  36. ---- Locals
  37.  
  38. local fEvents = CreateFrame("Frame", "QuestKing_EventsFrame")
  39. local fTimerMonitor = CreateFrame("Frame", "QuestKing_TimerMonitorFrame")
  40. local fCombat = CreateFrame("Frame", "QuestKing_CombatFrame")
  41.  
  42. local headerList = {}       -- updated by buildQuestSortTable
  43. local questSortTable = {}   -- "
  44. local totalQuestCount = 0   -- "
  45.  
  46. local trackedAchievementCache = {}
  47.  
  48. local updatedObjectives = {} -- objectives updated since last updateTracker
  49.  
  50. local achievementTimers = {}
  51. local achievementTimersMeta = {}
  52.  
  53. local numWatchButtons = 0 -- total watch buttons
  54. local numButtonsShown = 0 -- buttons curtently in use
  55.  
  56. local prev_GetNumQuestLogEntries = 0  -- used to determine if updateTracker needs to call buildQuestTable
  57. local prev_GetNumQuestWatches = 0     -- "
  58.  
  59. local cached_numQuestTimers = 0   -- used to determine if the number of timers has changed while timers are running in update mode
  60.  
  61. local watchMoney = false  -- set true if a quest we're watching needs money
  62.  
  63. local OBJECTIVE_PATTERN = "(.*):%s*([%d]+)%s*/%s*([%d]+)"
  64.  
  65. local db = nil    -- savedvariables
  66. local dbc = nil
  67.  
  68. local newPlayerLevel = nil
  69.  
  70. local itemPopups = {}
  71. local QUEST_START_ITEMS = nil
  72. local LOOT_SELF_REGEX = gsub(LOOT_ITEM_SELF, "%%s", "(.+)")
  73.  
  74. local checkCombat = false
  75.  
  76. ---- ############################
  77.  
  78. -- Upvalues
  79.  
  80. local _G = _G
  81. local pairs = pairs
  82. local format = format
  83. local floor = math.floor
  84. local math_modf = math.modf
  85. local math_ceil = math.ceil
  86. local GetTime = GetTime
  87. local GetQuestTimers = GetQuestTimers
  88. local SecondsToTime = SecondsToTime
  89.  
  90. local GetQuestLink = GetQuestLink
  91. local GetQuestLogTitle = GetQuestLogTitle
  92. local GetNumQuestLogEntries = GetNumQuestLogEntries
  93. local GetQuestLogQuestText = GetQuestLogQuestText
  94. local GetNumQuestLeaderBoards = GetNumQuestLeaderBoards
  95.  
  96. -- Local functions
  97.  
  98. local QuestKing_Tracker, WatchButton
  99.  
  100. local checkCombatTimer, startCombatTimer, checkPlayerLevelUp, parseLoot, UseContainerItemByID, GetTimeStringFromSecondsShort
  101. local hookQuestWatch
  102.  
  103. local updateTracker
  104. local updateTrackerChallengeTimers, setButtonToChallengeTimer, updateChallengeMedal, onUpdateChallengeTimer
  105. local updateTrackerScenarios, setButtonToScenario
  106. local updateTrackerQuestTimers, setButtonToQuestTimer, onUpdateQuestTimer
  107. local updateTrackerPopups, setButtonToPopup, setButtonToItemPopup
  108. local updateTrackerQuests, setButtonToQuest
  109. local updateTrackerAchievements, setButtonToAchievement, onUpdateAchievementTimer
  110. local setButtonToProvingGroundsTimer, onUpdateProvingGroundsTimer, UpdateProvingGroundsBar
  111.  
  112. local buildQuestSortTable, getQuestTaggedTitle, colorGradient, getObjectiveColor
  113.  
  114. -- Tracker
  115.  
  116. function QuestKing:CreateTracker ()
  117.     local frame = CreateFrame("Frame", "QuestKing_Tracker", UIParent)
  118.     QuestKing_Tracker = frame
  119.  
  120.     QuestKing:PositionTracker()
  121.  
  122.     frame:SetWidth(opt_buttonWidth)
  123.     frame:SetHeight(opt_titleHeight)
  124.  
  125.     -- frame:SetBackdrop({
  126.     --  bgFile = "Interface/Tooltips/UI-Tooltip-Background",
  127.     --  insets = { left = 0, right = 0, top = 0, bottom = 0 }
  128.     -- })
  129.     -- frame:SetBackdropColor(0,0,0,1)
  130.    
  131.     -- titlebar
  132.    
  133.     local titlebar = CreateFrame("Button", nil, frame)
  134.     titlebar:SetWidth(opt_buttonWidth)
  135.     titlebar:SetHeight(opt_titleHeight)
  136.     titlebar:SetPoint("TOPLEFT", UIParent, "TOPLEFT", 0, -100)
  137.     -- titlebar:SetBackdrop({
  138.     --  bgFile = "Interface/Tooltips/UI-Tooltip-Background",
  139.     --  insets = { left = 0, right = 0, top = 0, bottom = 0 }
  140.     -- })
  141.     -- titlebar:SetBackdropColor(1, 0, 0, 0)   
  142.     titlebar.parent = frame
  143.     frame.titlebar = titlebar
  144.    
  145.     -- minimize button
  146.    
  147.     local minimizeButton = CreateFrame("Button", "QuestKing_TrackerMinimizeButton", titlebar)
  148.     minimizeButton:SetWidth(15)
  149.     minimizeButton:SetHeight(15)
  150.    
  151.     local tex = minimizeButton:CreateTexture()
  152.     tex:SetPoint("CENTER")
  153.     tex:SetTexture([[Interface\Buttons\UI-Quickslot2]])
  154.     tex:SetWidth(22)
  155.     tex:SetHeight(22)
  156.     minimizeButton:SetNormalTexture(tex)
  157.    
  158.     local tex = minimizeButton:CreateTexture()
  159.     tex:SetPoint("CENTER")
  160.     tex:SetTexture([[Interface\Buttons\UI-Quickslot2]])
  161.     tex:SetWidth(15)
  162.     tex:SetHeight(15)
  163.     minimizeButton:SetPushedTexture(tex)
  164.  
  165.     local tex = minimizeButton:CreateTexture()
  166.     tex:SetPoint("CENTER")
  167.     tex:SetTexture([[Interface\Buttons\UI-Quickslot-Depress]])
  168.     tex:SetWidth(15)
  169.     tex:SetHeight(15)
  170.     minimizeButton:SetHighlightTexture(tex, "ADD")
  171.    
  172.     local label = minimizeButton:CreateFontString(nil, opt_fontLayer)
  173.     label:SetFont(opt_font, opt_fontSize, opt_fontStyle)
  174.     label:SetJustifyH("CENTER")
  175.     label:SetJustifyV("MIDDLE")
  176.     label:SetTextColor(opt_colors.TrackerTitlebarText[1], opt_colors.TrackerTitlebarText[2], opt_colors.TrackerTitlebarText[3])
  177.     label:SetShadowOffset(1, -1)
  178.     label:SetShadowColor(0, 0, 0, 1)   
  179.     label:SetPoint("CENTER", 1, 0.5)
  180.     label:SetText("+")
  181.     minimizeButton.label = label
  182.  
  183.     minimizeButton:RegisterForClicks("LeftButtonUp", "RightButtonUp")
  184.     minimizeButton:SetScript("OnClick", QuestKing.MinimizeButtonOnClick)
  185.    
  186.     -- mode button
  187.    
  188.     local modeButton = CreateFrame("Button", "QuestKing_TrackerModeButton", titlebar)
  189.     modeButton:SetWidth(15)
  190.     modeButton:SetHeight(15)
  191.    
  192.     local tex = modeButton:CreateTexture()
  193.     tex:SetPoint("CENTER")
  194.     tex:SetTexture([[Interface\Buttons\UI-Quickslot2]])
  195.     tex:SetWidth(22)
  196.     tex:SetHeight(22)
  197.     modeButton:SetNormalTexture(tex)
  198.    
  199.     local tex = modeButton:CreateTexture()
  200.     tex:SetPoint("CENTER")
  201.     tex:SetTexture([[Interface\Buttons\UI-Quickslot2]])
  202.     tex:SetWidth(15)
  203.     tex:SetHeight(15)
  204.     modeButton:SetPushedTexture(tex)
  205.  
  206.     local tex = modeButton:CreateTexture()
  207.     tex:SetPoint("CENTER")
  208.     tex:SetTexture([[Interface\Buttons\UI-Quickslot-Depress]])
  209.     tex:SetWidth(15)
  210.     tex:SetHeight(15)
  211.     modeButton:SetHighlightTexture(tex, "ADD")
  212.    
  213.     local label = modeButton:CreateFontString(nil, opt_fontLayer)
  214.     label:SetFont(opt_font, opt_fontSize, opt_fontStyle)
  215.     label:SetJustifyH("CENTER")
  216.     label:SetJustifyV("MIDDLE")
  217.     label:SetTextColor(opt_colors.TrackerTitlebarText[1], opt_colors.TrackerTitlebarText[2], opt_colors.TrackerTitlebarText[3])
  218.     label:SetShadowOffset(1, -1)
  219.     label:SetShadowColor(0, 0, 0, 1)   
  220.     label:SetPoint("CENTER", 1, 0.5)
  221.     label:SetText("Q")
  222.     modeButton.label = label
  223.  
  224.     modeButton:RegisterForClicks("LeftButtonUp", "RightButtonUp")
  225.     modeButton:SetScript("OnClick", QuestKing.ModeButtonOnClick)
  226.    
  227.     -- titlebar text
  228.    
  229.     local titlebarText = titlebar:CreateFontString(nil, opt_fontLayer)
  230.     titlebarText:SetFont(opt_font, opt_fontSize, opt_fontStyle)
  231.     titlebarText:SetJustifyH("RIGHT")
  232.     titlebarText:SetTextColor(opt_colors.TrackerTitlebarText[1], opt_colors.TrackerTitlebarText[2], opt_colors.TrackerTitlebarText[3])
  233.     titlebarText:SetShadowOffset(1, -1)
  234.     titlebarText:SetShadowColor(0, 0, 0, 1)
  235.  
  236.     titlebarText:SetText("0/"..MAX_QUESTS)
  237.     frame.titlebarText = titlebarText
  238.  
  239.     -- layout
  240.    
  241.     if true then
  242.         minimizeButton:SetPoint("RIGHT", titlebar, "RIGHT", 100, 0)
  243.         modeButton:SetPoint("RIGHT", minimizeButton, "LEFT", 100, 0)
  244.         titlebarText:SetPoint("RIGHT", modeButton, "LEFT", 100, 0)
  245.     end
  246.    
  247.     --frame:SetPoint("TOPLEFT", titlebar)
  248.     --frame:SetPoint("BOTTOMLEFT", titlebar)
  249.     --frame:SetWidth(opt_buttonWidth)
  250.    
  251.     titlebar:SetPoint("TOPLEFT", frame)
  252.    
  253.     -- frame:SetMovable(true)
  254.     -- titlebar:SetScript("OnMouseDown", function ()
  255.     --  frame:StartMoving()
  256.     -- end)
  257.     -- titlebar:SetScript("OnMouseUp", function ()
  258.     --  frame:StopMovingOrSizing()
  259.     --  frame:SetUserPlaced(false)
  260.     -- end)
  261.    
  262. end
  263.  
  264. local measureFrame = nil
  265. function QuestKing:ResizeTracker (lastShown)
  266.     if (not lastShown) then
  267.         QuestKing_Tracker:SetHeight(opt_titleHeight)
  268.     else
  269.         if not measureFrame then
  270.             measureFrame = CreateFrame("Frame", nil, UIParent)
  271.             measureFrame:SetWidth(opt_buttonWidth)
  272.             -- measureFrame:SetBackdrop({
  273.             --  bgFile = "Interface/Tooltips/UI-Tooltip-Background",
  274.             --  insets = { left = 0, right = 0, top = 0, bottom = 0 }
  275.             -- })
  276.             -- measureFrame:SetBackdropColor(0,1,0,0.5)
  277.         end
  278.        
  279.         measureFrame:ClearAllPoints()
  280.         measureFrame:SetPoint("TOPLEFT", QuestKing_Tracker)
  281.         measureFrame:SetPoint("BOTTOMLEFT", lastShown)
  282.         local height = measureFrame:GetHeight()
  283.         QuestKing_Tracker:SetHeight(height)
  284.     end
  285. end
  286.  
  287. function QuestKing:PositionTracker()
  288.     local preset = opt_positionPresets[dbc.trackerPositionPreset]
  289.     if not preset then
  290.         dbc.trackerPositionPreset = 1
  291.         preset = opt_positionPresets[1]
  292.     end
  293.     QuestKing_Tracker:SetPoint(unpack(preset))
  294. end
  295.  
  296. function QuestKing:CycleTrackerPosition()
  297.     local new = dbc.trackerPositionPreset + 1
  298.     if new > #opt_positionPresets then
  299.         new = 1
  300.     end
  301.     dbc.trackerPositionPreset = new
  302.     QuestKing:PositionTracker()
  303. end
  304.  
  305. -- Events
  306.  
  307. function checkCombatTimer ()
  308.     if not InCombatLockdown() then
  309.         --D("FINISH")
  310.         checkCombat = false
  311.         fCombat:SetScript("OnUpdate", nil)
  312.         QuestKing_TrackerModeButton.label:SetTextColor(opt_colors.TrackerTitlebarText[1], opt_colors.TrackerTitlebarText[2], opt_colors.TrackerTitlebarText[3])
  313.         updateTracker()
  314.     end
  315. end
  316.  
  317. function startCombatTimer ()
  318.     if (checkCombat == false) then
  319.         checkCombat = true
  320.         fCombat:SetScript("OnUpdate", checkCombatTimer)
  321.         QuestKing_TrackerModeButton.label:SetTextColor(1, 0, 0)
  322.     end
  323. end
  324.  
  325. function checkPlayerLevelUp ()
  326.     local level = UnitLevel("player")
  327.     if level >= newPlayerLevel then
  328.         QuestKing_Tracker:SetScript("OnUpdate", nil)
  329.         updateTracker()
  330.     else
  331.         --
  332.     end
  333. end
  334.  
  335. function parseLoot (msg)
  336.     local _, _, link = string.find(msg, LOOT_SELF_REGEX)
  337.     if link then
  338.         local _, _, itemID, itemName = string.find(link, "item:(%d+):.*|h%[(.+)%]|h")
  339.         itemID = tonumber(itemID)
  340.         if itemID then
  341.             if tContains(QUEST_START_ITEMS, itemID) then
  342.                 itemPopups[itemID] = itemName
  343.                 PlaySoundFile("Sound\\Interface\\PVPWarningHordeMono.wav")
  344.                 updateTracker()
  345.             end
  346.         end
  347.     end
  348. end
  349.  
  350. function UseContainerItemByID(searchID)
  351.     for i = 0,4 do
  352.         for j = 1, GetContainerNumSlots(i) do
  353.             local id = GetContainerItemID(i,j)
  354.             if id == searchID then
  355.                 UseContainerItem(i, j)
  356.                 return
  357.             end
  358.         end
  359.     end
  360. end
  361.  
  362. function QuestKing_HandleEvent (self, event, ...)
  363.     --D("|cffaaccff"..event, ...)
  364.     if (event == "CHAT_MSG_LOOT") then
  365.         parseLoot(...)
  366.     elseif (event == "PLAYER_MONEY") and (watchMoney) then
  367.         updateTracker()
  368.     elseif (event == "PLAYER_LEVEL_UP") then
  369.         -- local v = 60; D("= " .. Hex(GetQuestDifficultyColor(v))..v)
  370.         -- local v = 61; D("= " .. Hex(GetQuestDifficultyColor(v))..v)
  371.         -- local v = 62; D("= " .. Hex(GetQuestDifficultyColor(v))..v)
  372.         -- local v = 63; D("= " .. Hex(GetQuestDifficultyColor(v))..v)
  373.         -- local v = 64; D("= " .. Hex(GetQuestDifficultyColor(v))..v)
  374.         -- D("GreenRange is " .. GetQuestGreenRange())
  375.         newPlayerLevel = ...
  376.         QuestKing_Tracker:SetScript("OnUpdate", checkPlayerLevelUp)
  377.     elseif (event == "QUEST_LOG_UPDATE") or (event == "ITEM_PUSH") then
  378.         updateTracker()
  379.     elseif (event == "UI_INFO_MESSAGE") then
  380.         local desc = ...
  381.         local p1, p2, quantName, quantCur, quantMax = string.find(desc, OBJECTIVE_PATTERN)
  382.         if quantName then
  383.             updatedObjectives[quantName] = true
  384.         end
  385.     elseif (event == "TRACKED_ACHIEVEMENT_UPDATE") then
  386.         -- can i ignore this/updateTracker entirely if achieveID isnt in trackedAchievementCache? (tContains)
  387.         -- if i do, tracking a quest with a timer that's already started ma not show it (for a while...?)
  388.            
  389.         local achievementID, criteriaID, timeElapsed, timeLimit = ...
  390.         --
  391.         if timeElapsed and timeLimit then
  392.             if timeElapsed >= timeLimit then
  393.                 achievementTimers[criteriaID] = nil
  394.                 achievementTimersMeta[achievementID] = nil
  395.             else
  396.                 achievementTimers[criteriaID] = achievementTimers[criteriaID] or {}
  397.                 achievementTimers[criteriaID].startTime = GetTime() - timeElapsed
  398.                 achievementTimers[criteriaID].duration = timeLimit
  399.                 achievementTimersMeta[achievementID] = achievementTimers[criteriaID]
  400.             end
  401.         end
  402.         --D(">>>")
  403.         updateTracker()
  404.     elseif (event == "QUEST_AUTOCOMPLETE") then
  405.         local questId = ...
  406.         if (AddAutoQuestPopUp(questId, "COMPLETE")) then
  407.             PlaySound("UI_AutoQuestComplete")
  408.         end
  409.         updateTracker()
  410.     elseif (event == "SCENARIO_UPDATE") or (event == "SCENARIO_CRITERIA_UPDATE") then
  411.         -- D("SCENARIO_UPDATE")
  412.         updateTracker()
  413.     elseif (event == "PLAYER_ENTERING_WORLD") or (event == "WORLD_STATE_TIMER_START") or (event == "WORLD_STATE_TIMER_STOP") then
  414.         -- challenge/scenario zone in + timers
  415.         updateTracker()
  416.     elseif (event == "ZONE_CHANGED") or (event == "ZONE_CHANGED_INDOORS") or (event == "ZONE_CHANGED_NEW_AREA") then
  417.         -- zone heuristic highlight
  418.         updateTracker()
  419.     end
  420. end
  421.  
  422. function QuestKing.MinimizeButtonOnClick (self, mouse, down)
  423.     if mouse == "RightButton" then
  424.         QuestKing:CycleTrackerPosition()
  425.     else
  426.         if dbc.trackerCollapsed then
  427.             dbc.trackerCollapsed = false
  428.             --PlaySound("igMiniMapOpen")
  429.         else
  430.             dbc.trackerCollapsed = true
  431.             --PlaySound("igMiniMapClose")
  432.         end
  433.         updateTracker()
  434.     end
  435. end
  436.  
  437. function QuestKing.ModeButtonOnClick (self, mouse, down)
  438.     if mouse == "RightButton" then
  439.         if IsAltKeyDown() then
  440.             SetSuperTrackedQuestID(0)
  441.         elseif dbc.displayMode ~= "combined" then
  442.             dbc.displayMode = "combined"
  443.         else
  444.             dbc.displayMode = "quests"
  445.         end
  446.     else
  447.         if dbc.displayMode == "quests" then
  448.             dbc.displayMode = "achievements"
  449.         else
  450.             dbc.displayMode = "quests"
  451.         end
  452.     end
  453.     updateTracker()
  454. end
  455.  
  456. function QuestKing.ButtonOnClick (self, mouse, down)
  457.     local button = self
  458.     if button.type == "popup" then
  459.         if button.popupType == "ITEM" then
  460.             if mouse == "RightButton" then
  461.                 itemPopups[button.itemID] = nil
  462.                 updateTracker()
  463.             else
  464.                 --if InCombatLockdown() then return end
  465.                 UseContainerItemByID(button.itemID)
  466.                 itemPopups[button.itemID] = nil
  467.                 updateTracker()
  468.             end
  469.         elseif mouse == "RightButton" then
  470.             RemoveAutoQuestPopUp(self.questID)
  471.             updateTracker()
  472.         else
  473.             if button.popupType == "OFFER" then
  474.                 QuestLog_OpenToQuest(self.questIndex)
  475.                 RemoveAutoQuestPopUp(self.questID)
  476.                 updateTracker()
  477.             elseif button.popupType == "COMPLETE" then
  478.                 ShowQuestComplete(self.questIndex)
  479.                 RemoveAutoQuestPopUp(self.questID)
  480.                 updateTracker()
  481.             end
  482.         end
  483.     end
  484. end
  485.  
  486. function QuestKing.TitleButtonOnClick (self, mouse, down)
  487.     local button = self.parent
  488.  
  489.     if (IsModifiedClick("CHATLINK") and ChatEdit_GetActiveWindow()) then
  490.         if (button.type == "quest") then
  491.             local questLink = GetQuestLink(button.questIndex)
  492.             if (questLink) then
  493.                 ChatEdit_InsertLink(questLink)
  494.                 return
  495.             end
  496.         elseif (button.type == "achievement") then
  497.             local achievementLink = GetAchievementLink(button.achievementID)
  498.             if (achievementLink) then
  499.                 ChatEdit_InsertLink(achievementLink)
  500.                 return
  501.             end
  502.         end
  503.     end
  504.        
  505.     if button.type == "header" then
  506.         local headerName = button.headerName
  507.        
  508.         if dbc.collapsedHeaders[headerName] then
  509.             dbc.collapsedHeaders[headerName] = nil
  510.         else
  511.             dbc.collapsedHeaders[headerName] = true
  512.         end
  513.         updateTracker()
  514.        
  515.     elseif button.type == "quest" then
  516.         if IsAltKeyDown() then
  517.             if mouse == "RightButton" then
  518.                 RemoveQuestWatch(button.questIndex)
  519.                 updateTracker()
  520.                 return
  521.             else
  522.                 if dbc.collapsedQuests[button.questID] then
  523.                     dbc.collapsedQuests[button.questID] = nil
  524.                 else
  525.                     dbc.collapsedQuests[button.questID] = true
  526.                 end
  527.                 updateTracker()
  528.                 return
  529.             end
  530.         end
  531.    
  532.         if mouse == "RightButton" then
  533.             WORLDMAP_SETTINGS.selectedQuestId = button.questID
  534.             SetSuperTrackedQuestID(button.questID)
  535.             QuestPOIUpdateIcons()
  536.             if WorldMapFrame:IsShown() then
  537.                 HideUIPanel(WorldMapFrame)
  538.                 ShowUIPanel(WorldMapFrame)
  539.             end
  540.         else
  541.             if (QuestLogFrame:IsShown()) and (QuestLogFrame.selectedIndex == button.questIndex) then
  542.                 HideUIPanel(QuestLogFrame)
  543.             else
  544.                 QuestLog_OpenToQuest(button.questIndex)
  545.                 ShowUIPanel(QuestLogFrame)
  546.             end
  547.         end
  548.  
  549.     elseif button.type == "achievement" then
  550.         if IsAltKeyDown() then
  551.             if mouse == "RightButton" then
  552.                 RemoveTrackedAchievement(button.achievementID)
  553.                 updateTracker()
  554.                 return
  555.             else
  556.                 if dbc.collapsedAchievements[button.achievementID] then
  557.                     dbc.collapsedAchievements[button.achievementID] = nil
  558.                 else
  559.                     dbc.collapsedAchievements[button.achievementID] = true
  560.                 end
  561.                 updateTracker()
  562.                 return
  563.             end
  564.         end
  565.    
  566.         if (not AchievementFrame) then AchievementFrame_LoadUI() end
  567.        
  568.         if (not AchievementFrame:IsShown()) then
  569.             AchievementFrame_ToggleAchievementFrame()
  570.             AchievementFrame_SelectAchievement(button.achievementID)
  571.         else
  572.             if (AchievementFrameAchievements.selection ~= button.achievementID) then
  573.                 AchievementFrame_SelectAchievement(button.achievementID)
  574.             else
  575.                 AchievementFrame_ToggleAchievementFrame()
  576.             end
  577.         end
  578.     end
  579. end
  580.  
  581. function QuestKing.TitleButtonOnEnter (self, event, ...)
  582.     local button = self.parent
  583.     if (button.type == "quest") or (button.type == "questtimer") then
  584.         local link = GetQuestLink(button.questIndex)
  585.         if link then
  586.             GameTooltip:SetOwner(self, opt_tooltipAnchor)
  587.  
  588.             if opt_tooltipScale then
  589.                 if not GameTooltip.__QuestKingPreviousScale then
  590.                     GameTooltip.__QuestKingPreviousScale = GameTooltip:GetScale()
  591.                 end
  592.                 GameTooltip:SetScale(opt_tooltipScale)
  593.             end
  594.  
  595.             GameTooltip:SetHyperlink(link)
  596.             GameTooltip:Show()
  597.         end
  598.     elseif (button.type == "achievement") then
  599.         local link = GetAchievementLink(button.achievementID)
  600.         if link then
  601.             GameTooltip:SetOwner(self, opt_tooltipAnchor)
  602.  
  603.             if opt_tooltipScale then
  604.                 if not GameTooltip.__QuestKingPreviousScale then
  605.                     GameTooltip.__QuestKingPreviousScale = GameTooltip:GetScale()
  606.                 end
  607.                 GameTooltip:SetScale(opt_tooltipScale)
  608.             end
  609.  
  610.             GameTooltip:SetHyperlink(link)
  611.             GameTooltip:Show()
  612.         end    
  613.     elseif (button.type == "scenario") then
  614.         local stageName, stageDescription, numCriteria = C_Scenario.GetStepInfo()
  615.         GameTooltip:SetOwner(self, opt_tooltipAnchor)
  616.  
  617.         if opt_tooltipScale then
  618.             if not GameTooltip.__QuestKingPreviousScale then
  619.                 GameTooltip.__QuestKingPreviousScale = GameTooltip:GetScale()
  620.             end
  621.             GameTooltip:SetScale(opt_tooltipScale)
  622.         end
  623.  
  624.         GameTooltip:AddLine(stageName, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
  625.         GameTooltip:AddLine(" ")
  626.         GameTooltip:AddLine(stageDescription, 1, 1, 1, 1)
  627.         GameTooltip:Show()
  628.     end
  629. end
  630.  
  631. function QuestKing.TitleButtonOnLeave (self, event, ...)
  632.     if opt_tooltipScale then
  633.         local oldScale = GameTooltip.__QuestKingPreviousScale or 1
  634.         GameTooltip.__QuestKingPreviousScale = nil
  635.         GameTooltip:SetScale(oldScale)
  636.     end
  637.     GameTooltip:Hide()
  638. end
  639.  
  640. function hookQuestWatch ()
  641.     --D("|cffaaffcchookQuestWatch")
  642.     updateTracker(true)
  643. end
  644.  
  645. -- Watch buttons
  646.  
  647. local WatchButtonPrototype = CreateFrame("Frame")
  648. local WatchButton = setmetatable({}, { __index = WatchButtonPrototype })
  649. WatchButton.__index = WatchButton
  650. local watchButtonList = {}
  651. do
  652.     function WatchButton:GetNext()
  653.         numButtonsShown = numButtonsShown + 1
  654.         local wb = self:Get(numButtonsShown)
  655.         wb:Reset()
  656.         return wb
  657.     end
  658.  
  659.     function WatchButton:Get(num)
  660.         local button = watchButtonList[num]
  661.         if button then return button end
  662.        
  663.         local name = "QuestKing_WatchButton" .. num
  664.        
  665.         -- button
  666.        
  667.         button = CreateFrame("Button", name, QuestKing_Tracker)
  668.         button:SetBackdrop({
  669.             bgFile = "Interface/Tooltips/UI-Tooltip-Background",
  670.             insets = { left = 0, right = 0, top = 0, bottom = 0 }
  671.         })
  672.         button:SetBackdropColor(0, 0, 0, 0)
  673.         button:SetWidth(opt_buttonWidth)
  674.         button:SetHeight(opt_lineHeight)
  675.         button:SetPoint("TOPLEFT", 0, 0)
  676.        
  677.         local buttonHighlight = button:CreateTexture()
  678.         buttonHighlight:SetAllPoints(button)
  679.         buttonHighlight:SetTexture([[Interface\QuestFrame\UI-QuestLogTitleHighlight]])
  680.         buttonHighlight:SetAlpha(0.6)
  681.        
  682.         button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
  683.         button:EnableMouse(false)
  684.         button:SetHighlightTexture(buttonHighlight, "ADD")
  685.         button:SetScript("OnClick", QuestKing.ButtonOnClick)
  686.        
  687.         -- icons
  688.        
  689.         local iconExclamationMark = button:CreateTexture(nil, nil, "QuestIcon-Exclamation")
  690.         iconExclamationMark:ClearAllPoints()
  691.         iconExclamationMark:SetPoint("RIGHT", button, "LEFT")
  692.         iconExclamationMark:SetHeight(opt_lineHeight * 2 - 2)
  693.         iconExclamationMark:SetWidth(opt_lineHeight * 1.4)
  694.         iconExclamationMark:Hide()
  695.         button.iconExclamationMark = iconExclamationMark
  696.        
  697.         local animGroup = iconExclamationMark:CreateAnimationGroup()
  698.         local a1 = animGroup:CreateAnimation("Alpha")
  699.         a1:SetStartDelay(0.25); a1:SetDuration(0.33); a1:SetChange(-1); a1:SetOrder(1); a1:SetSmoothing("IN");
  700.         animGroup:SetLooping("BOUNCE")
  701.         iconExclamationMark.animGroup = animGroup
  702.  
  703.         local iconQuestionMark = button:CreateTexture(nil, nil, "QuestIcon-QuestionMark")
  704.         iconQuestionMark:ClearAllPoints()
  705.         iconQuestionMark:SetPoint("RIGHT", button, "LEFT")
  706.         iconQuestionMark:SetHeight(opt_lineHeight * 2 - 2)
  707.         iconQuestionMark:SetWidth(opt_lineHeight * 1.4)
  708.         iconQuestionMark:Hide()
  709.         button.iconQuestionMark = iconQuestionMark
  710.  
  711.         local animGroup = iconQuestionMark:CreateAnimationGroup()
  712.         local a1 = animGroup:CreateAnimation("Alpha")
  713.         a1:SetStartDelay(0.25); a1:SetDuration(0.33); a1:SetChange(-1); a1:SetOrder(1); a1:SetSmoothing("IN");
  714.         animGroup:SetLooping("BOUNCE")
  715.         iconQuestionMark.animGroup = animGroup
  716.  
  717.         -- title button
  718.        
  719.         local titleButton = CreateFrame("Button", nil, button)
  720.         titleButton:SetPoint("BOTTOMLEFT", 0, 0)
  721.         titleButton:SetWidth(opt_buttonWidth)
  722.         titleButton:SetHeight(opt_lineHeight)      
  723.         titleButton.parent = button
  724.        
  725.         titleButton:RegisterForClicks("LeftButtonUp", "RightButtonUp")
  726.         titleButton:SetScript("OnClick", QuestKing.TitleButtonOnClick)
  727.         titleButton:SetScript("OnEnter", QuestKing.TitleButtonOnEnter)
  728.         titleButton:SetScript("OnLeave", QuestKing.TitleButtonOnLeave)
  729.         button.titleButton = titleButton
  730.        
  731.         -- title button hover
  732.        
  733.         local tex = titleButton:CreateTexture()
  734.         tex:SetAllPoints(titleButton)
  735.         tex:SetTexture([[Interface\QuestFrame\UI-QuestLogTitleHighlight]])
  736.         tex:SetAlpha(0.6)
  737.        
  738.         titleButton:EnableMouse(true)
  739.         titleButton:SetHighlightTexture(tex, "ADD")
  740.        
  741.         -- title text
  742.        
  743.         local title = button:CreateFontString(nil, opt_fontLayer)
  744.         title:SetFont(opt_font, opt_fontSize, opt_fontStyle)
  745.         title:SetJustifyH("LEFT")
  746.         title:SetTextColor(1, 1, 0)
  747.         title:SetShadowOffset(1, -1)
  748.         title:SetShadowColor(0, 0, 0, 1)   
  749.         title:SetPoint("TOPLEFT", 0, 0)
  750.  
  751.         title:SetWidth(opt_buttonWidth)
  752.         title:SetHeight(opt_lineHeight)
  753.        
  754.         title:SetText("<Error>")
  755.    
  756.         button.title = title
  757.        
  758.         -- variables
  759.         button.linesLeft = {}
  760.         button.linesRight = {}
  761.         button.currentLine = 0
  762.         button.updateTimer = opt_updateRate
  763.  
  764.         button.challengeBarShown = false
  765.        
  766.         button.type = "none"
  767.  
  768.         button.name = name
  769.        
  770.         setmetatable(button, WatchButton)
  771.        
  772.         watchButtonList[num] = button
  773.         numWatchButtons = numWatchButtons + 1
  774.        
  775.         button.buttonNumber = numWatchButtons
  776.        
  777.         return button
  778.     end
  779.    
  780.     function WatchButton:Reset()
  781.         self.currentLine = 0
  782.         if self.itemButton and self.itemButton:IsShown() then
  783.             if InCombatLockdown() then
  784.                 startCombatTimer()
  785.             else
  786.                 self.itemButton:Hide()
  787.             end
  788.         end
  789.         self:SetBackdropColor(0, 0, 0, 0)
  790.         self:SetScript("OnUpdate", nil)
  791.         self.updateTimer = opt_updateRate
  792.        
  793.         self:EnableMouse(false)
  794.         self.titleButton:EnableMouse(true)
  795.        
  796.         self.iconExclamationMark.animGroup:Stop()
  797.         self.iconExclamationMark:Hide()
  798.         self.iconQuestionMark.animGroup:Stop()
  799.         self.iconQuestionMark:Hide()
  800.  
  801.         if (self.challengeBarShown) then
  802.             self.challengeBarShown = false
  803.             self.challengeBar:Hide()
  804.         end
  805.     end
  806.  
  807.     function WatchButton:CreateLines()
  808.         local left = self:CreateFontString(nil, opt_fontLayer)
  809.         left:SetFont(opt_font, opt_fontSize, opt_fontStyle)
  810.         left:SetJustifyH("LEFT")
  811.         left:SetTextColor(1, 1, 0)
  812.         left:SetShadowOffset(1, -1)
  813.         left:SetShadowColor(0, 0, 0, 1)
  814.         left:SetPoint("TOPLEFT", 0, 0)
  815.         left:SetJustifyV("TOP")
  816.         tinsert(self.linesLeft, left)
  817.        
  818.         local right = self:CreateFontString(nil, opt_fontLayer)
  819.         right:SetFont(opt_font, opt_fontSize, opt_fontStyle)
  820.         right:SetJustifyH("LEFT")
  821.         right:SetTextColor(1, 1, 0)
  822.         right:SetShadowOffset(1, -1)
  823.         right:SetShadowColor(0, 0, 0, 1)   
  824.         right:SetPoint("TOPLEFT", 0, 0)
  825.         right:SetJustifyV("TOP")
  826.         tinsert(self.linesRight, right)
  827.        
  828.         local flash = self:CreateTexture()
  829.         flash:SetPoint("TOPLEFT", left)
  830.         flash:SetPoint("BOTTOMLEFT", left)
  831.         flash:SetWidth(opt_buttonWidth)
  832.         flash:SetTexture([[Interface\QuestFrame\UI-QuestLogTitleHighlight]])
  833.         flash:SetBlendMode("ADD")
  834.         flash:SetVertexColor(opt_colors.ObjectiveFlash[1], opt_colors.ObjectiveFlash[2], opt_colors.ObjectiveFlash[3], 0)
  835.        
  836.         local animGroup = flash:CreateAnimationGroup()
  837.         local a1 = animGroup:CreateAnimation("Alpha")
  838.         local a2 = animGroup:CreateAnimation("Alpha")
  839.        
  840.         a1:SetStartDelay(0)
  841.         a1:SetDuration(0.15)
  842.         a1:SetChange(1)
  843.         a1:SetOrder(1)
  844.         --a1:SetSmoothing("IN")
  845.  
  846.         a2:SetStartDelay(0.25)
  847.         a2:SetDuration(0.50)
  848.         a2:SetChange(-1)
  849.         a2:SetOrder(2)
  850.         --a1:SetSmoothing("OUT")
  851.        
  852.         left.flash = flash
  853.         left.flash.animGroup = animGroup
  854.        
  855.         return left, right
  856.     end
  857.  
  858.     function WatchButton:AddLine(textleft, textright, r, g, b, a)
  859.         local currentLine = self.currentLine + 1
  860.         self.currentLine = currentLine
  861.        
  862.         local left, right
  863.         if self.linesLeft[currentLine] then
  864.             left = self.linesLeft[currentLine]
  865.             right = self.linesRight[currentLine]
  866.         else
  867.             left, right = self:CreateLines()
  868.         end
  869.        
  870.         left.isTimer = false
  871.        
  872.         left:SetText(textleft)
  873.         right:SetText(textright)
  874.        
  875.         if r ~= nil then
  876.             left:SetTextColor(r, g, b, a or 1)
  877.             right:SetTextColor(r, g, b, a or 1)
  878.         end
  879.        
  880.         return left
  881.     end
  882.    
  883.     function WatchButton:Layout()
  884.         local height = 0
  885.         local lastLine = nil
  886.         for i = 1, #self.linesLeft do
  887.             local left, right = self.linesLeft[i], self.linesRight[i]
  888.            
  889.             if i > self.currentLine then
  890.                 left:Hide()
  891.                 right:Hide()
  892.                 left.flash.animGroup:Stop()
  893.             else
  894.                 left:Show()
  895.                 right:Show()
  896.                 if lastLine == nil then
  897.                     left:SetPoint("TOPLEFT", self.title, "BOTTOMLEFT", 0, 0)
  898.                 else
  899.                     left:SetPoint("TOPLEFT", lastLine, "BOTTOMLEFT", 0, 0)
  900.                 end
  901.                 right:SetPoint("TOPLEFT", left, "TOPRIGHT", -1, 0)
  902.                
  903.                 left:SetWidth(0)
  904.                 left:SetHeight(0)
  905.                
  906.                 local lenLeft = left:GetStringWidth()
  907.                 local lenRight = right:GetStringWidth()            
  908.                
  909.                 if (lenLeft + lenRight) > opt_buttonWidth then
  910.                     --left:SetHeight(left:GetStringHeight())
  911.                     left:SetHeight(opt_lineHeight)
  912.                     left:SetWidth(opt_buttonWidth - lenRight)
  913.                 else
  914.                     left:SetHeight(opt_lineHeight)
  915.                 end
  916.  
  917.                 lastLine = left
  918.                 height = (opt_lineHeight * i)
  919.             end
  920.         end
  921.        
  922.         -- if (self.type == "popup") then
  923.         --  self.iconExclamationMark:SetHeight((opt_lineHeight * 2 - 2) * 3.5)
  924.         --  self.iconExclamationMark:SetWidth((opt_lineHeight * 1.4) * 3.5)
  925.         --  self.iconQuestionMark:SetHeight((opt_lineHeight * 2 - 2) * 3.5)
  926.         --  self.iconQuestionMark:SetWidth((opt_lineHeight * 1.4) * 3.5)
  927.         --  height = height * 6
  928.         -- end
  929.  
  930.         if (self.challengeBarShown) then
  931.             height = height + 18
  932.         end
  933.        
  934.         self:SetHeight(opt_lineHeight + height)
  935.     end
  936. end
  937.  
  938. -- Tracker Updating
  939.  
  940. function updateTracker (forceBuild)
  941.     local numEntries = GetNumQuestLogEntries()
  942.     local numWatches = GetNumQuestWatches()
  943.     if forceBuild then
  944.         buildQuestSortTable()
  945.         prev_GetNumQuestLogEntries = numEntries -- since we built it... is this safe?
  946.         prev_GetNumQuestWatches = numWatches
  947.     else
  948.         if numEntries ~= prev_GetNumQuestLogEntries then
  949.             buildQuestSortTable()
  950.         elseif numWatches ~= prev_GetNumQuestWatches then
  951.             buildQuestSortTable()
  952.         end
  953.         prev_GetNumQuestLogEntries = numEntries
  954.         prev_GetNumQuestWatches = numWatches
  955.     end
  956.     --D("!updateTracker")
  957.  
  958.     numButtonsShown = 0
  959.     watchMoney = false
  960.  
  961.     -- titlebar
  962.     if dbc.trackerCollapsed == true then
  963.         QuestKing_TrackerMinimizeButton.label:SetText("+")
  964.     else
  965.         QuestKing_TrackerMinimizeButton.label:SetText("-")
  966.     end
  967.  
  968.     -- challenge timers
  969.     local hasTimer = GetWorldElapsedTimers()
  970.     local ProvingGroundsType, _, _, _ = C_Scenario.GetProvingGroundsInfo()
  971.     if hasTimer then
  972.         if ProvingGroundsType ~= 0 then
  973.             updateTrackerChallengeTimers(2)
  974.         else
  975.             updateTrackerChallengeTimers(GetWorldElapsedTimers())
  976.         end
  977.     end
  978.  
  979.     -- scenarios
  980.     local inScenario = C_Scenario.IsInScenario()
  981.     if inScenario then
  982.         updateTrackerScenarios()
  983.     end
  984.    
  985.     -- quest timers
  986.     if GetQuestTimers() then
  987.         updateTrackerQuestTimers()
  988.     end
  989.    
  990.     -- popups
  991.     --if not dbc.trackerCollapsed then
  992.     --  if (dbc.displayMode == "combined") or (dbc.displayMode == "quests") then
  993.             updateTrackerPopups()
  994.     --  end
  995.     --end
  996.  
  997.     -- achievements
  998.     trackedAchievementCache = { GetTrackedAchievements() }
  999.     if not dbc.trackerCollapsed then
  1000.         if (dbc.displayMode == "combined") or (dbc.displayMode == "achievements") then
  1001.  
  1002.             -- add header if we're in a scenario since it has its own headers
  1003.             if (inScenario) and (dbc.displayMode == "achievements") then
  1004.                 local achheader = WatchButton:GetNext()
  1005.                 achheader.type = "header_basic"
  1006.                 achheader.title:SetText("Achievements")
  1007.                 achheader.title:SetTextColor(opt_colors.AchievementHeader[1], opt_colors.AchievementHeader[2], opt_colors.AchievementHeader[3])
  1008.                 achheader:Layout()
  1009.             end
  1010.  
  1011.             updateTrackerAchievements()
  1012.         end
  1013.     end
  1014.  
  1015.     -- quests
  1016.     if (not inScenario) then
  1017.         if not dbc.trackerCollapsed then   
  1018.             if (dbc.displayMode == "combined") or (dbc.displayMode == "quests") then
  1019.                 updateTrackerQuests()
  1020.             end
  1021.         end
  1022.     end
  1023.    
  1024.     local numAch = #trackedAchievementCache
  1025.     if dbc.displayMode == "combined" then
  1026.         QuestKing_TrackerModeButton.label:SetText("C")
  1027.         if numAch > 0 then
  1028.             QuestKing_Tracker.titlebarText:SetText(format("%d/%d + %d", totalQuestCount, MAX_QUESTS, numAch))
  1029.         else
  1030.             QuestKing_Tracker.titlebarText:SetText(format("%d/%d", totalQuestCount, MAX_QUESTS))
  1031.         end
  1032.         if (numWatches == 0) and (numAch == 0) then
  1033.             QuestKing_Tracker.titlebarText:SetTextColor(opt_colors.TrackerTitlebarTextDimmed[1], opt_colors.TrackerTitlebarTextDimmed[2], opt_colors.TrackerTitlebarTextDimmed[3])
  1034.         else
  1035.             QuestKing_Tracker.titlebarText:SetTextColor(opt_colors.TrackerTitlebarText[1], opt_colors.TrackerTitlebarText[2], opt_colors.TrackerTitlebarText[3])
  1036.         end
  1037.     elseif dbc.displayMode == "achievements" then
  1038.         QuestKing_TrackerModeButton.label:SetText("A")
  1039.         QuestKing_Tracker.titlebarText:SetText(numAch)
  1040.         if (numAch == 0) then
  1041.             QuestKing_Tracker.titlebarText:SetTextColor(opt_colors.TrackerTitlebarTextDimmed[1], opt_colors.TrackerTitlebarTextDimmed[2], opt_colors.TrackerTitlebarTextDimmed[3])
  1042.         else
  1043.             QuestKing_Tracker.titlebarText:SetTextColor(opt_colors.TrackerTitlebarText[1], opt_colors.TrackerTitlebarText[2], opt_colors.TrackerTitlebarText[3])
  1044.         end    
  1045.     else
  1046.         QuestKing_TrackerModeButton.label:SetText("Q")
  1047.         QuestKing_Tracker.titlebarText:SetText(format("%d/%d", totalQuestCount, MAX_QUESTS))
  1048.         if (numWatches == 0) then
  1049.             QuestKing_Tracker.titlebarText:SetTextColor(opt_colors.TrackerTitlebarTextDimmed[1], opt_colors.TrackerTitlebarTextDimmed[2], opt_colors.TrackerTitlebarTextDimmed[3])
  1050.         else
  1051.             QuestKing_Tracker.titlebarText:SetTextColor(opt_colors.TrackerTitlebarText[1], opt_colors.TrackerTitlebarText[2], opt_colors.TrackerTitlebarText[3])
  1052.         end    
  1053.     end
  1054.    
  1055.  
  1056.     -- LAYOUT
  1057.     local lastShown = nil
  1058.     if numWatchButtons > 0 then
  1059.         for i = 1, numWatchButtons do
  1060.             local button = watchButtonList[i]
  1061.            
  1062.             if i > numButtonsShown then
  1063.                 button:Hide()
  1064.                 if (button.itemButton) and (button.itemButton:IsShown()) then
  1065.                     if InCombatLockdown() then
  1066.                         startCombatTimer()
  1067.                     else
  1068.                         button.itemButton:Hide()
  1069.                     end
  1070.                 end
  1071.             elseif lastShown == nil then
  1072.                 button:SetPoint("TOPLEFT", QuestKing_Tracker.titlebar, "BOTTOMLEFT", 0, -1)
  1073.                 button:Show()
  1074.                 lastShown = button
  1075.             else
  1076.                 if (button.type == "header") or (button.type == "header_basic") then
  1077.                     button:SetPoint("TOPLEFT", lastShown, "BOTTOMLEFT", 0, -4)
  1078.                 elseif (lastShown.type == "header") or (lastShown.type == "header_basic") then
  1079.                     button:SetPoint("TOPLEFT", lastShown, "BOTTOMLEFT", 0, -3)
  1080.                 else
  1081.                     button:SetPoint("TOPLEFT", lastShown, "BOTTOMLEFT", 0, -2)
  1082.                 end
  1083.                 button:Show()
  1084.                 lastShown = button
  1085.             end
  1086.         end
  1087.     end
  1088.    
  1089.     QuestKing:ResizeTracker(lastShown)
  1090. end
  1091.  
  1092. -- simplified and shortened version of Blizzard equivalent GetTimeStringFromSeconds
  1093. function GetTimeStringFromSecondsShort (timeAmount)
  1094.     local seconds = timeAmount
  1095.  
  1096.     local hours = floor(seconds / 3600)
  1097.     local minutes = floor((seconds / 60) - (hours * 60))
  1098.     seconds = seconds - hours * 3600 - minutes * 60
  1099.  
  1100.     if hours > 0 then
  1101.         return format("%d:%.2d:%.2d", hours, minutes, seconds)
  1102.     else
  1103.         return format("%d:%.2d", minutes, seconds)
  1104.     end
  1105. end
  1106.  
  1107. function updateTrackerChallengeTimers (...)
  1108.     for i = 1, select("#", ...) do
  1109.         local timerID = select(i, ...)
  1110.         local description, elapsedTime, isChallengeModeTimer = GetWorldElapsedTime(timerID)
  1111.         if isChallengeModeTimer == 2 then
  1112.             local _, _, _, _, _, _, _, mapID, _ = GetInstanceInfo()
  1113.             if (mapID) then
  1114.                 local button = WatchButton:GetNext()
  1115.                 button.type = "challengetimer"
  1116.                 setButtonToChallengeTimer(button, timerID, elapsedTime, GetChallengeModeMapTimes(mapID))
  1117.                 button:Layout()
  1118.            
  1119.  
  1120.                 return
  1121.             end
  1122.         elseif isChallengeModeTimer == 3 then
  1123.             local difficulty, curWave, maxWave, duration = C_Scenario.GetProvingGroundsInfo()
  1124.             local button = WatchButton:GetNext()
  1125.             button.type = "challengetimer"
  1126.             setButtonToProvingGroundsTimer(button, difficulty, elapsedTime, curWave, maxWave, duration)
  1127.         end
  1128.     end
  1129. end
  1130.  
  1131. function setButtonToChallengeTimer (button, timerID, elapsedTime, ...)
  1132.     if not (button.challengeMedalTimes) then
  1133.         button.challengeMedalTimes = { }
  1134.     end
  1135.     for i = 1, select("#", ...) do
  1136.         button.challengeMedalTimes[i] = select(i, ...);
  1137.     end
  1138.  
  1139.     button.titleButton:EnableMouse(false)
  1140.  
  1141.     button.title:SetText("")
  1142.  
  1143.     if not button.challengeBar then
  1144.         local challengeBar = CreateFrame("StatusBar", nil, button)
  1145.         challengeBar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar")
  1146.         challengeBar:GetStatusBarTexture():SetHorizTile(false)
  1147.         challengeBar:SetStatusBarColor(0, 0.33, 0.61)
  1148.         challengeBar:SetMinMaxValues(0, 100)
  1149.         challengeBar:SetValue(100)
  1150.         challengeBar:SetWidth(opt_buttonWidth - 36)
  1151.         challengeBar:SetHeight(17)
  1152.         challengeBar:SetPoint("BOTTOMLEFT", button, "BOTTOMLEFT", 26, 5)
  1153.         button.challengeBar = challengeBar
  1154.  
  1155.         local border = challengeBar:CreateTexture(nil, "OVERLAY")
  1156.         border:SetTexture([[Interface\Challenges\challenges-main]])
  1157.         border:SetPoint("TOPLEFT", challengeBar, "TOPLEFT", -5, 5)
  1158.         border:SetPoint("BOTTOMRIGHT", challengeBar, "BOTTOMRIGHT", 5, -5)
  1159.         border:SetTexCoord(0.00097656, 0.13769531, 0.47265625, 0.51757813)
  1160.         challengeBar.border = border
  1161.  
  1162.         local icon = challengeBar:CreateTexture(nil, "OVERLAY")
  1163.         icon:SetTexture([[Interface\Challenges\challenges-plat-sm]])
  1164.         icon:SetSize(22, 22)
  1165.         icon:SetPoint("RIGHT", challengeBar, "LEFT", -6, 0)
  1166.         icon:SetTexCoord(0.25, 0.7, 0.25, 0.7)
  1167.         challengeBar.icon = icon
  1168.         button.challengeBarIcon = icon
  1169.  
  1170.         local text = challengeBar:CreateFontString(nil, "OVERLAY")
  1171.         text:SetFont(opt_fontChallengeTimer, opt_fontSize, opt_fontStyle)
  1172.         text:SetJustifyH("CENTER")
  1173.         text:SetJustifyV("CENTER")
  1174.         text:SetAllPoints(true)
  1175.         text:SetTextColor(1, 1, 1)
  1176.         text:SetShadowOffset(1, -1)
  1177.         text:SetShadowColor(0, 0, 0, 1)
  1178.         text:SetText("No Medal")
  1179.         challengeBar.text = text
  1180.         button.challengeBarText = text
  1181.     else
  1182.         button.challengeBar:Show()
  1183.     end
  1184.     button.challengeBarShown = true
  1185.  
  1186.     button.challengeTime = 0
  1187.     button.challengeCurrentMedalTime = -1
  1188.     button.challengeRecheck = 0
  1189.  
  1190.     -- adding a little to help reduce sync jitter when difference is floor'd later
  1191.     onUpdateChallengeTimer(button, (elapsedTime + 0.01), true)
  1192.  
  1193.     if (button.challengeCurrentMedalTime) then
  1194.         button:SetScript("OnUpdate", onUpdateChallengeTimer)
  1195.     end
  1196. end
  1197.  
  1198. function setButtonToProvingGroundsTimer (button, difficulty, elapsedTime, curWave, maxWave, duration)
  1199.     button.titleButton:EnableMouse(false)
  1200.     button.ProvingGroundsDuration = duration
  1201.     button.title:SetText("")
  1202.  
  1203.     if not button.challengeBar then
  1204.         local challengeBar = CreateFrame("StatusBar", nil, button)
  1205.         challengeBar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar")
  1206.         challengeBar:GetStatusBarTexture():SetHorizTile(false)
  1207.         challengeBar:SetStatusBarColor(0, 0.33, 0.61)
  1208.         challengeBar:SetMinMaxValues(0, 100)
  1209.         challengeBar:SetValue(100)
  1210.         challengeBar:SetWidth(opt_buttonWidth - 36)
  1211.         challengeBar:SetHeight(17)
  1212.         challengeBar:SetPoint("BOTTOMLEFT", button, "BOTTOMLEFT", 26, 5)
  1213.         button.challengeBar = challengeBar
  1214.  
  1215.         local border = challengeBar:CreateTexture(nil, "OVERLAY")
  1216.         border:SetTexture([[Interface\Challenges\challenges-main]])
  1217.         border:SetPoint("TOPLEFT", challengeBar, "TOPLEFT", -5, 5)
  1218.         border:SetPoint("BOTTOMRIGHT", challengeBar, "BOTTOMRIGHT", 5, -5)
  1219.         border:SetTexCoord(0.00097656, 0.13769531, 0.47265625, 0.51757813)
  1220.         challengeBar.border = border
  1221.  
  1222.         local icon = challengeBar:CreateTexture(nil, "OVERLAY")
  1223.         icon:SetTexture([[Interface\Challenges\challenges-plat-sm]])
  1224.         icon:SetSize(22, 22)
  1225.         icon:SetPoint("RIGHT", challengeBar, "LEFT", -6, 0)
  1226.         icon:SetTexCoord(0.25, 0.7, 0.25, 0.7)
  1227.         challengeBar.icon = icon
  1228.         button.challengeBarIcon = icon
  1229.  
  1230.         local text = challengeBar:CreateFontString(nil, "OVERLAY")
  1231.         text:SetFont(opt_fontChallengeTimer, opt_fontSize, opt_fontStyle)
  1232.         text:SetJustifyH("CENTER")
  1233.         text:SetJustifyV("CENTER")
  1234.         text:SetAllPoints(true)
  1235.         text:SetTextColor(1, 1, 1)
  1236.         text:SetShadowOffset(1, -1)
  1237.         text:SetShadowColor(0, 0, 0, 1)
  1238.         text:SetText("")
  1239.         challengeBar.text = text
  1240.         button.challengeBarText = text
  1241.     else
  1242.         button.challengeBar:Show()
  1243.     end
  1244.     button.challengeBarShown = true
  1245.  
  1246.     button.ProvingGroundsTime = 0
  1247.     button.ProvingGroundsDurationMax = -1
  1248.     button.ProvingGroundsCurrentWave = curWave
  1249.     button.ProvingGroundsMaxWave = maxWave
  1250.     button.ProvingGroundsRecheck = 0
  1251.  
  1252.     -- adding a little to help reduce sync jitter when difference is floor'd later
  1253.     onUpdateProvingGroundsTimer(button, (elapsedTime), true, difficulty)
  1254.  
  1255.     if (button.ProvingGroundsTime) then
  1256.         button:SetScript("OnUpdate", onUpdateProvingGroundsTimer)
  1257.     end
  1258. end
  1259.  
  1260. function updateChallengeMedal (self, elapsedTime)
  1261.     local prevMedalTime = 0
  1262.     for i = #self.challengeMedalTimes, 1, -1 do
  1263.         local curMedalTime = self.challengeMedalTimes[i]
  1264.         if (elapsedTime < curMedalTime) then
  1265.             self.challengeCurrentMedalTime = curMedalTime
  1266.             self.challengeBar:SetMinMaxValues(0, curMedalTime - prevMedalTime)
  1267.  
  1268.             if i == 1 then
  1269.                 self.challengeBar:SetStatusBarColor(0.76, 0.38, 0.15)
  1270.                 self.challengeBarIcon:SetTexture([[Interface\Challenges\challenges-bronze-sm]])
  1271.                 self.challengeBarIcon:Show()
  1272.             elseif i == 2 then
  1273.                 self.challengeBar:SetStatusBarColor(0.64, 0.6, 0.6)
  1274.                 self.challengeBarIcon:SetTexture([[Interface\Challenges\challenges-silver-sm]])
  1275.                 self.challengeBarIcon:Show()
  1276.             elseif i == 3 then
  1277.                 self.challengeBar:SetStatusBarColor(0.93, 0.67, 0.25)
  1278.                 self.challengeBarIcon:SetTexture([[Interface\Challenges\challenges-gold-sm]])
  1279.                 self.challengeBarIcon:Show()
  1280.             elseif i == 4 then
  1281.                 self.challengeBar:SetStatusBarColor(0.6, 0.75, 0.7)
  1282.                 self.challengeBarIcon:SetTexture([[Interface\Challenges\challenges-plat-sm]])
  1283.                 self.challengeBarIcon:Show()
  1284.             else
  1285.                 self.challengeBar:SetStatusBarColor(1, 0.3, 0.3)
  1286.                 self.challengeBarIcon:Hide()
  1287.             end
  1288.  
  1289.             return
  1290.         else
  1291.             prevMedalTime = curMedalTime
  1292.         end
  1293.     end
  1294.  
  1295.     -- no medal
  1296.     self.challengeCurrentMedalTime = false
  1297.     self:SetScript("OnUpdate", nil)
  1298.  
  1299.     self.challengeBarText:SetText(CHALLENGES_TIMER_NO_MEDAL)
  1300.     self.challengeBar:SetMinMaxValues(0, 1)
  1301.     self.challengeBar:SetValue(1)
  1302.     self.challengeBar:SetStatusBarColor(0.3, 0.3, 0.3)
  1303.     self.challengeBarIcon:Hide()
  1304. end
  1305.  
  1306. function updateProvingGroundsBar (self, elapsedTime, difficulty)
  1307.     local DurTime = self.ProvingGroundsDuration
  1308.     self.challengeBar:SetMinMaxValues(0, DurTime)
  1309.     if elapsedTime  < DurTime then
  1310.         self.ProvingGroundsDurationMax = DurTime
  1311.         self.challengeBar:SetMinMaxValues(0, DurTime)
  1312.         if difficulty == 1 then
  1313.             self.challengeBar:SetStatusBarColor(0.76, 0.38, 0.15)
  1314.             self.challengeBarIcon:SetTexture([[Interface\Challenges\challenges-bronze-sm]])
  1315.             self.challengeBarIcon:Show()
  1316.         elseif difficulty == 2 then
  1317.             self.challengeBar:SetStatusBarColor(0.64, 0.6, 0.6)
  1318.             self.challengeBarIcon:SetTexture([[Interface\Challenges\challenges-silver-sm]])
  1319.             self.challengeBarIcon:Show()
  1320.         elseif difficulty == 3 then
  1321.             self.challengeBar:SetStatusBarColor(0.93, 0.67, 0.25)
  1322.             self.challengeBarIcon:SetTexture([[Interface\Challenges\challenges-gold-sm]])
  1323.             self.challengeBarIcon:Show()
  1324.         elseif difficulty == 4 then
  1325.             self.challengeBar:SetStatusBarColor(0.6, 0.75, 0.7)
  1326.             self.challengeBarIcon:SetTexture([[Interface\Challenges\challenges-plat-sm]])
  1327.             self.challengeBarIcon:Show()
  1328.         end
  1329.     else
  1330.         self.ProvingGroundsDurationMax = -1
  1331.         elapsedTime = 0
  1332.         --self:SetScript("OnUpdate", nil)
  1333.         self.challengeBarText:SetText("")
  1334.         self.challengeBar:SetMinMaxValues(0, 1)
  1335.         self.challengeBar:SetValue(0)
  1336.         self.challengeBar:SetStatusBarColor(0.3, 0.3, 0.3)
  1337.         self.challengeBarIcon:Hide()
  1338.     end
  1339.  
  1340.  
  1341. end
  1342.  
  1343. function onUpdateChallengeTimer (self, elapsed, manual)
  1344.     local newTime = self.challengeTime + elapsed
  1345.     self.challengeTime = newTime
  1346.  
  1347.     local currentMedalTime = self.challengeCurrentMedalTime
  1348.    
  1349.     if (currentMedalTime) then
  1350.         if (newTime > currentMedalTime) then
  1351.             -- manual update or medal expired, force update
  1352.             updateChallengeMedal(self, newTime)
  1353.             currentMedalTime = self.challengeCurrentMedalTime
  1354.            
  1355.             if currentMedalTime then
  1356.                 local timeLeft = floor(currentMedalTime - newTime)
  1357.                 self.challengeBar:SetValue(timeLeft)
  1358.                 self.challengeBarText:SetText(GetTimeStringFromSecondsShort(timeLeft))
  1359.  
  1360.                 --D("forceupd", manual)
  1361.             end
  1362.  
  1363.         else
  1364.             -- timed update, throttle it
  1365.             local updateTimer = self.updateTimer
  1366.             updateTimer = updateTimer - elapsed
  1367.  
  1368.             if (updateTimer <= 0) then
  1369.                 local timeLeft = floor(currentMedalTime - newTime)
  1370.                 self.challengeBar:SetValue(timeLeft)
  1371.                 self.challengeBarText:SetText(GetTimeStringFromSecondsShort(timeLeft))
  1372.  
  1373.  
  1374.                 updateTimer = opt_updateRate           
  1375.                 --D("noskip")
  1376.             end
  1377.  
  1378.             self.updateTimer = updateTimer
  1379.         end
  1380.     else
  1381.         --D("nomedal!?")
  1382.     end
  1383.  
  1384.     -- force a resync every 10 sec for onupdate calls
  1385.     if not manual then
  1386.         local recheck = self.challengeRecheck + elapsed
  1387.         if recheck > 10.1 then
  1388.             --D("Recheck", recheck, elapsed)
  1389.             self.challengeRecheck = 0
  1390.             self:SetScript("OnUpdate", updateTracker)
  1391.         else
  1392.             self.challengeRecheck = recheck
  1393.         end
  1394.     end
  1395.  
  1396. end
  1397.  
  1398. function onUpdateProvingGroundsTimer (self, elapsed, manual, difficulty)
  1399.     local newTime = self.ProvingGroundsTime + elapsed
  1400.     self.ProvingGroundsTime = newTime
  1401.     local durationTime = self.ProvingGroundsDurationMax
  1402.     curWave = self.ProvingGroundsCurrentWave
  1403.     maxWave = self.ProvingGroundsMaxWave           
  1404.     if (durationTime) then
  1405.         if floor(newTime) == durationTime then
  1406.             self.challengeBar:SetValue(0)
  1407.             if maxWave == 0 then
  1408.                 self.challengeBarText:SetText(format("Wave %u   %s", curWave, GetTimeStringFromSecondsShort(0)))
  1409.             else
  1410.                 self.challengeBarText:SetText(format("Wave %u of %u   %s", curWave, maxWave, GetTimeStringFromSecondsShort(0)))
  1411.             end
  1412.         elseif newTime > durationTime then
  1413.             -- manual update or medal expired, force update
  1414.             updateProvingGroundsBar(self, newTime, difficulty)
  1415.             durationTime = self.ProvingGroundsDurationMax
  1416.                    
  1417.             --local timeLeft = durationTime - newTime
  1418.             --self.challengeBar:SetValue(timeLeft)
  1419.             --if maxWave == 0 then
  1420.             --  self.challengeBarText:SetText(format("Wave %u   %s", curWave, GetTimeStringFromSecondsShort(timeLeft)))
  1421.             --else
  1422.             --  self.challengeBarText:SetText(format("Wave %u of %u   %s", curWave, maxWave, GetTimeStringFromSecondsShort(timeLeft)))
  1423.             --end
  1424.             --D("forceupd", manual)
  1425.        
  1426.         else
  1427.             -- timed update, throttle it
  1428.             local updateTimer = self.updateTimer
  1429.             updateTimer = updateTimer - elapsed
  1430.             if (updateTimer <= 0) then
  1431.                 local timeLeft = durationTime - newTime + 1
  1432.                 self.challengeBar:SetValue(timeLeft)
  1433.                 if maxWave == 0 then
  1434.                     self.challengeBarText:SetText(format("Wave %u   %s", curWave, GetTimeStringFromSecondsShort(timeLeft)))
  1435.                 else
  1436.                     self.challengeBarText:SetText(format("Wave %u of %u   %s", curWave, maxWave, GetTimeStringFromSecondsShort(timeLeft)))
  1437.                 end
  1438.                 updateTimer = opt_updateRate / 2
  1439.                 --D("noskip")
  1440.             end
  1441.            
  1442.         self.updateTimer = updateTimer
  1443.  
  1444.         end
  1445.     else
  1446.         --D("nomedal!?")
  1447.     end
  1448.  
  1449.     --force a resync every 10 sec for onupdate calls
  1450.     if not manual then
  1451.         local recheck = self.ProvingGroundsRecheck + elapsed
  1452.         if recheck > 10.1 then
  1453.             --D("Recheck", recheck, elapsed)
  1454.             self.ProvingGroundsRecheck = 0
  1455.            
  1456.             self:SetScript("OnUpdate", updateTracker)
  1457.         else
  1458.             self.ProvingGroundsRecheck = recheck
  1459.         end
  1460.     end
  1461. end
  1462.  
  1463. function updateTrackerScenarios ()
  1464.     local name, currentStage, numStages = C_Scenario.GetInfo()
  1465.     local stageName, stageDescription, numCriteria = C_Scenario.GetStepInfo()
  1466.     local inChallengeMode = C_Scenario.IsChallengeMode()
  1467.    
  1468.     if (currentStage > 0) then
  1469.         if (currentStage <= numStages) then
  1470.             -- scenario type header
  1471.             local header = WatchButton:GetNext()
  1472.             header.type = "header_basic"
  1473.             if (not inChallengeMode) then
  1474.                 if (currentStage == numStages) then
  1475.                     header.title:SetText("Scenario: Final Stage")
  1476.                 else
  1477.                     header.title:SetFormattedText("Scenario: Stage %d/%d", currentStage, numStages)
  1478.                 end        
  1479.             else
  1480.                 header.title:SetText("Challenge Mode")
  1481.             end
  1482.             header.title:SetTextColor(opt_colors.QuestHeader[1], opt_colors.QuestHeader[2], opt_colors.QuestHeader[3])
  1483.             header:Layout()
  1484.  
  1485.             -- scenario stage
  1486.             local button = WatchButton:GetNext()
  1487.             button.type = "scenario"
  1488.             setButtonToScenario(button)
  1489.             button:Layout()
  1490.         elseif (currentStage > numStages) then
  1491.             -- scenario complete header
  1492.             local header = WatchButton:GetNext()
  1493.             header.type = "header_basic"
  1494.             if (not inChallengeMode) then
  1495.                 header.title:SetText("Scenario Complete")
  1496.             else
  1497.                 header.title:SetText("Challenge Mode Complete")
  1498.             end
  1499.             header.title:SetTextColor(opt_colors.ScenarioComplete[1], opt_colors.ScenarioComplete[2], opt_colors.ScenarioComplete[3])
  1500.             header:Layout()        
  1501.         end
  1502.  
  1503.         -- questtypes
  1504.         -- thunderaan the windseeker = 62
  1505.         -- stranger in a strange land = 83
  1506.         -- blades of the anointed = 85
  1507.         -- the kun-lai kicker = 98
  1508.         -- soften them up = 81
  1509.         -- slay them all! = 41
  1510.         -- the champion's call! = 1
  1511.         -- imperial qiraji armaments = 62
  1512.  
  1513.         -- scenario quests
  1514.         local addedHeader = false
  1515.         local currentHeader = "(Unknown)"
  1516.         local numEntries = GetNumQuestLogEntries()
  1517.         for questIndex = 1, numEntries do
  1518.             local questTitle,_,_,_,isHeader = GetQuestLogTitle(questIndex)
  1519.             if isHeader then
  1520.                 currentHeader = questTitle
  1521.             elseif (currentHeader == name) and (GetQuestLogQuestType(questIndex) == QUEST_TYPE_SCENARIO) then
  1522.                 if not addedHeader then
  1523.                     local questHeader = WatchButton:GetNext()
  1524.                     questHeader.type = "header_basic"
  1525.                     questHeader.title:SetText("Scenario Quests")
  1526.                     questHeader.title:SetTextColor(opt_colors.QuestHeader[1], opt_colors.QuestHeader[2], opt_colors.QuestHeader[3])
  1527.                     questHeader:Layout()                       
  1528.                     addedHeader = true
  1529.                 end
  1530.                 local button = WatchButton:GetNext()
  1531.                 button.type = "quest"
  1532.                 setButtonToQuest(button, questIndex)
  1533.                 button:Layout()            
  1534.             end
  1535.         end
  1536.  
  1537.         --
  1538.     end
  1539.  
  1540. end
  1541.  
  1542. function setButtonToScenario (button)
  1543.     local name, currentStage, numStages = C_Scenario.GetInfo()
  1544.     local stageName, stageDescription, numCriteria = C_Scenario.GetStepInfo()
  1545.     local inChallengeMode = C_Scenario.IsChallengeMode()
  1546.  
  1547.     if (not inChallengeMode) then
  1548.         button.title:SetText(stageName)
  1549.     else
  1550.         button.title:SetText(stageName)
  1551.     end
  1552.     button.title:SetTextColor(opt_colors.ScenarioStageTitle[1], opt_colors.ScenarioStageTitle[2], opt_colors.ScenarioStageTitle[3])
  1553.  
  1554.     for i = 1, numCriteria do
  1555.         local criteriaString, criteriaType, criteriaCompleted, quantity, totalQuantity, flags, assetID, quantityString, criteriaID = C_Scenario.GetCriteriaInfo(i)
  1556.        
  1557.         if (not criteriaCompleted) then
  1558.             local r, g, b = getObjectiveColor(quantity / totalQuantity)
  1559.             button:AddLine(format("  %s", criteriaString), format(": %s/%s", quantity, totalQuantity), r, g, b)
  1560.         elseif (opt_showCompletedObjectives) then
  1561.             button:AddLine(format("  %s", criteriaString), format(": %s/%s", quantity, totalQuantity), opt_colors.ObjectiveGradientComplete[1], opt_colors.ObjectiveGradientComplete[2], opt_colors.ObjectiveGradientComplete[3])
  1562.         end
  1563.     end
  1564.  
  1565. end
  1566.  
  1567. function updateTrackerQuestTimers ()
  1568.     local questTimers = { GetQuestTimers() }
  1569.     local numQuestTimers = #questTimers
  1570.     cached_numQuestTimers = numQuestTimers
  1571.     for i = 1, numQuestTimers do
  1572.         local button = WatchButton:GetNext()
  1573.         button.type = "questtimer"
  1574.         setButtonToQuestTimer(button, i, questTimers)
  1575.         button:Layout()
  1576.     end
  1577. end
  1578.  
  1579. function setButtonToQuestTimer(button, timerID, questTimers)
  1580.     button.timerID = timerID
  1581.  
  1582.     local questIndex = GetQuestIndexForTimer(timerID)
  1583.     local questTitle, _, _, _, _, _, _, _, questID = GetQuestLogTitle(questIndex)
  1584.    
  1585.     if (not questTitle) or (questTitle == "") then
  1586.         questTitle = "(Unknown Quest)"
  1587.     else
  1588.         questTitle = getQuestTaggedTitle(questIndex)
  1589.     end
  1590.    
  1591.     button.questIndex = questIndex
  1592.     button.questID = questID
  1593.    
  1594.     local timer = questTimers[button.timerID]
  1595.     local timerText = SecondsToTime(timer, false, false, 4)
  1596.     if (timerText == "") then
  1597.         timerText = "0 Sec"
  1598.     end
  1599.    
  1600.     button.title:SetText(questTitle)
  1601.     button.title:SetTextColor(opt_colors.QuestTimerTitle[1], opt_colors.QuestTimerTitle[2], opt_colors.QuestTimerTitle[3])
  1602.     button:AddLine("  "..timerText, nil, opt_colors.QuestTimerTime[1], opt_colors.QuestTimerTime[2], opt_colors.QuestTimerTime[3])
  1603.     button:SetBackdropColor(opt_colors.QuestTimerBackground[1], opt_colors.QuestTimerBackground[2], opt_colors.QuestTimerBackground[3], opt_colors.QuestTimerBackground[4])
  1604.    
  1605.     button:SetScript("OnUpdate", onUpdateQuestTimer)
  1606. end
  1607.  
  1608. function onUpdateQuestTimer (self, elapsed)
  1609.     local updateTimer = self.updateTimer
  1610.     updateTimer = updateTimer - elapsed
  1611.     if (updateTimer <= 0) then
  1612.         local questTimers = { GetQuestTimers() }
  1613.         local numQuestTimers = #questTimers
  1614.        
  1615.         if (numQuestTimers ~= cached_numQuestTimers) then
  1616.             -- number of quest timers has changed, force tracker update to dispose of this frame
  1617.             --D("!!! Quest Timer count changed, forcing tracker update!")
  1618.             updateTracker()
  1619.             return
  1620.         end
  1621.        
  1622.         local timer = questTimers[self.timerID]
  1623.         --D(timer, "###", GetQuestTimers())
  1624.         local timerText = SecondsToTime(timer, false, false, 4)
  1625.         if (timerText == "") then
  1626.             timerText = "0 Sec"
  1627.         end
  1628.  
  1629.         local line = self.linesLeft[1]
  1630.         line:SetText("  "..timerText)
  1631.        
  1632.         updateTimer = opt_updateRate
  1633.     end
  1634.     self.updateTimer = updateTimer
  1635. end
  1636.  
  1637.  
  1638. function updateTrackerPopups()
  1639.     for itemID, itemName in pairs(itemPopups) do
  1640.         local button = WatchButton:GetNext()
  1641.         button.type = "popup"
  1642.         setButtonToItemPopup(button, itemID, itemName)
  1643.         button:Layout()
  1644.     end
  1645.    
  1646.     local numPopups = GetNumAutoQuestPopUps()
  1647.     for i = 1, numPopups do
  1648.         local popID, popType = GetAutoQuestPopUp(i)
  1649.        
  1650.         local button = WatchButton:GetNext()
  1651.         button.type = "popup"
  1652.         setButtonToPopup(button, popID, popType)
  1653.         button:Layout()
  1654.     end
  1655. end
  1656.  
  1657. function setButtonToItemPopup (button, itemID, itemName)
  1658.     button.popupType = "ITEM"
  1659.     button.itemID = itemID
  1660.     button.itemName = itemName
  1661.    
  1662.     button.title:SetText(itemName)
  1663.     button.title:SetTextColor(opt_colors.PopupItemTitle[1], opt_colors.PopupItemTitle[2], opt_colors.PopupItemTitle[3])
  1664.     button:AddLine("  Item Begins a Quest", nil, opt_colors.PopupItemDescription[1], opt_colors.PopupItemDescription[2], opt_colors.PopupItemDescription[3])
  1665.     button:SetBackdropColor(opt_colors.PopupItemBackground[1], opt_colors.PopupItemBackground[2], opt_colors.PopupItemBackground[3], opt_colors.PopupItemBackground[4])
  1666.     button.iconExclamationMark:Show()
  1667.     button.iconExclamationMark.animGroup:Play()
  1668.    
  1669.     button.titleButton:EnableMouse(false)
  1670.     button:EnableMouse(true)   
  1671. end
  1672.  
  1673. function setButtonToPopup (button, questID, popType)
  1674.     local questIndex = GetQuestLogIndexByID(questID)
  1675.     local taggedTitle
  1676.     --enter the nexus?
  1677.     --D(button, questID, popType, questIndex)
  1678.     if (questIndex == 0) or (questIndex == nil) then
  1679.         --D("NQ")
  1680.         taggedTitle = "New Quest!"
  1681.     else
  1682.         --D("TI")
  1683.         taggedTitle = getQuestTaggedTitle(questIndex)
  1684.     end
  1685.    
  1686.     button.popupType = popType
  1687.     button.questIndex = questIndex
  1688.     button.questID = questID
  1689.  
  1690.     button.title:SetText(taggedTitle)
  1691.  
  1692.     if popType == "COMPLETE" then
  1693.         button.title:SetTextColor(opt_colors.PopupCompleteTitle[1], opt_colors.PopupCompleteTitle[2], opt_colors.PopupCompleteTitle[3])
  1694.         button:AddLine("  Quest Completed", nil, opt_colors.PopupCompleteDescription[1], opt_colors.PopupCompleteDescription[2], opt_colors.PopupCompleteDescription[3])
  1695.         button:SetBackdropColor(opt_colors.PopupCompleteBackground[1], opt_colors.PopupCompleteBackground[2], opt_colors.PopupCompleteBackground[3], opt_colors.PopupCompleteBackground[4])
  1696.         button.iconQuestionMark:Show()
  1697.         button.iconQuestionMark.animGroup:Play()
  1698.     else
  1699.         button.title:SetTextColor(opt_colors.PopupOfferTitle[1], opt_colors.PopupOfferTitle[2], opt_colors.PopupOfferTitle[3])
  1700.         button:AddLine("  Quest Received", nil, opt_colors.PopupOfferDescription[1], opt_colors.PopupOfferDescription[2], opt_colors.PopupOfferDescription[3])
  1701.         button:SetBackdropColor(opt_colors.PopupOfferBackground[1], opt_colors.PopupOfferBackground[2], opt_colors.PopupOfferBackground[3], opt_colors.PopupOfferBackground[4])
  1702.         button.iconExclamationMark:Show()
  1703.         button.iconExclamationMark.animGroup:Play()
  1704.     end
  1705.     button.titleButton:EnableMouse(false)
  1706.     button:EnableMouse(true)
  1707. end
  1708.  
  1709.  
  1710. function updateTrackerQuests()
  1711.     local oldSelection
  1712.     if (opt_subzoneHeuristicHighlight) then
  1713.         oldSelection = GetQuestLogSelection()
  1714.     end
  1715.  
  1716.     local headerName, questIndex
  1717.     for i = 1, #headerList do
  1718.         headerName = headerList[i]
  1719.         -- header
  1720.         if #questSortTable[headerName] > 0 then
  1721.             local button = WatchButton:GetNext()
  1722.             button.type = "header"
  1723.             button.headerName = headerName
  1724.            
  1725.             --|TTexturePath:size1:size2:xoffset:yoffset:dimx:dimy:coordx1:coordx2:coordy1:coordy2:red:green:blue|t
  1726.             if dbc.collapsedHeaders[headerName] then
  1727.                 button.title:SetText("|TInterface\\AddOns\\QuestKing\\UI-SortArrow_sm_right:8:8:0:-1:0:0:0:0:0:0:1:1:1|t"..headerName)
  1728.                 button.title:SetTextColor(opt_colors.QuestHeaderCollapsed[1], opt_colors.QuestHeaderCollapsed[2], opt_colors.QuestHeaderCollapsed[3])
  1729.             else
  1730.                 button.title:SetText("|TInterface\\AddOns\\QuestKing\\UI-SortArrow_sm_down:8:8:0:-1:0:0:0:0:0:0:1:1:1|t"..headerName)
  1731.                 button.title:SetTextColor(opt_colors.QuestHeader[1], opt_colors.QuestHeader[2], opt_colors.QuestHeader[3])
  1732.             end
  1733.            
  1734.             button:Layout()
  1735.         end
  1736.  
  1737.         -- quests
  1738.        
  1739.         if not dbc.collapsedHeaders[headerName] then
  1740.             for j = 1, #questSortTable[headerName] do
  1741.                 questIndex = questSortTable[headerName][j]
  1742.                 local button = WatchButton:GetNext()
  1743.                 button.type = "quest"
  1744.                 setButtonToQuest(button, questIndex)
  1745.                 button:Layout()
  1746.             end
  1747.         end
  1748.     end
  1749.  
  1750.     if (opt_subzoneHeuristicHighlight) then
  1751.         SelectQuestLogEntry(oldSelection)
  1752.     end
  1753. end
  1754.  
  1755. function setButtonToQuest (button, questIndex)
  1756.     local questTitle, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily, questID, startEvent = GetQuestLogTitle(questIndex)
  1757.    
  1758.     button.questIndex = questIndex
  1759.     button.questID = questID
  1760.    
  1761.     local collapseObjectives = dbc.collapsedQuests[questID]
  1762.    
  1763.     -- set title
  1764.     local taggedTitle = getQuestTaggedTitle(questIndex)
  1765.     -- taggedTitle = GetQuestLogQuestType(questIndex) .. " / " .. taggedTitle
  1766.    
  1767.     if isComplete == -1 then
  1768.         button.title:SetText(opt_colors._FailedQuestTag .. taggedTitle)
  1769.     else
  1770.         button.title:SetText(taggedTitle)
  1771.     end
  1772.    
  1773.     -- add objectives      
  1774.     local numObj = GetNumQuestLeaderBoards(questIndex) or 0
  1775.     local completedObj = 0
  1776.     local displayedObj = 0
  1777.     for i = 1, numObj do
  1778.         local desc, objectiveType, isDone = GetQuestLogLeaderBoard(i, questIndex)
  1779.         if (desc == nil) then
  1780.             desc = "Unknown"
  1781.         end
  1782.         local p1, p2, quantName, quantCur, quantMax = string.find(desc, OBJECTIVE_PATTERN)
  1783.        
  1784.         if isDone then
  1785.             completedObj = completedObj + 1
  1786.         end
  1787.        
  1788.         local displayObjective = true
  1789.         if collapseObjectives then
  1790.             displayObjective = false
  1791.         elseif isComplete == 1 then
  1792.             if (opt_showCompletedObjectives == "always") then
  1793.                 displayObjective = true
  1794.             else
  1795.                 displayObjective = false
  1796.             end
  1797.         end
  1798.  
  1799.         if (desc == "Unknown") then
  1800.             displayObjective = false
  1801.         end
  1802.  
  1803.         if (displayObjective) then
  1804.             if (not desc) then
  1805.                 --
  1806.             elseif (not quantName) or (objectiveType == "spell") then
  1807.                 if (not isDone) or (opt_showCompletedObjectives) then
  1808.                     local r, g, b = getObjectiveColor(isDone and 1 or 0)
  1809.                     button:AddLine(format("  %s", desc), nil, r, g, b)
  1810.                     displayedObj = displayedObj + 1
  1811.                 end
  1812.             else
  1813.                 if (not isDone) or (opt_showCompletedObjectives) then
  1814.                     local r, g, b = getObjectiveColor(quantCur / quantMax)
  1815.                     local line = button:AddLine(format("  %s", quantName), format(": %s/%s", quantCur, quantMax), r, g, b)
  1816.                     displayedObj = displayedObj + 1
  1817.                    
  1818.                     if updatedObjectives[quantName] then
  1819.                         updatedObjectives[quantName] = nil
  1820.                         line.flash.animGroup:Play()
  1821.                     end
  1822.                 end
  1823.             end
  1824.         end
  1825.        
  1826.     end
  1827.  
  1828.     -- money
  1829.     local requiredMoney = GetQuestLogRequiredMoney(questIndex)
  1830.     if requiredMoney > 0 then
  1831.         watchMoney = true
  1832.         local playerMoney = GetMoney()
  1833.        
  1834.         -- not sure about this, but the default watch frame does it
  1835.         -- (fake completion for gold-requiring connectors when gold req is met and no event begins)
  1836.         if (numObj == 0 and playerMoney >= requiredMoney and not startEvent) then
  1837.             isComplete = 1
  1838.         end
  1839.        
  1840.         numObj = numObj + 1 -- (questking only) ensure all gold-requiring quests aren't marked as connectors
  1841.  
  1842.         if (not collapseObjectives) then -- hide entirely if objectives are collapsed
  1843.             if playerMoney >= requiredMoney then
  1844.                 -- show met gold amounts only for incomplete quests
  1845.                 if (isComplete ~= 1) and (opt_showCompletedObjectives) then
  1846.                     local r, g, b = getObjectiveColor(1)
  1847.                     button:AddLine("  Requires: "..GetMoneyString(requiredMoney), nil, r, g, b)
  1848.                 end
  1849.             else
  1850.                 -- always show unmet gold amount
  1851.                 local r, g, b = getObjectiveColor(0)
  1852.                 button:AddLine("  Requires: "..GetMoneyString(requiredMoney), nil, r, g, b)
  1853.             end
  1854.         end
  1855.     end
  1856.    
  1857.     -- colour title
  1858.     if (isComplete == -1) then
  1859.         button.title:SetTextColor(opt_colors.QuestTitleFailed[1], opt_colors.QuestTitleFailed[2], opt_colors.QuestTitleFailed[3]) -- failed
  1860.     elseif (isComplete == 1) then
  1861.         if GetQuestLogIsAutoComplete(questIndex) then
  1862.             button.title:SetTextColor(opt_colors.QuestTitleCompleteAuto[1], opt_colors.QuestTitleCompleteAuto[2], opt_colors.QuestTitleCompleteAuto[3]) -- autocompletable
  1863.         elseif (numObj == 0) then
  1864.             button.title:SetTextColor(opt_colors.QuestTitleConnector[1], opt_colors.QuestTitleConnector[2], opt_colors.QuestTitleConnector[3]) -- connector quest [type c] (complete, 0/0 objectives)
  1865.         else
  1866.             button.title:SetTextColor(opt_colors.QuestTitleComplete[1], opt_colors.QuestTitleComplete[2], opt_colors.QuestTitleComplete[3]) -- completed quest (complete, n/n objectives)
  1867.         end
  1868.     -- elseif (GetQuestLogQuestType(questIndex) == QUEST_TYPE_SCENARIO) then
  1869.     --  button.title:SetTextColor(opt_colors.QuestTitleScenario[1], opt_colors.QuestTitleScenario[2], opt_colors.QuestTitleScenario[3])
  1870.     else
  1871.         if numObj == 0 then
  1872.             button.title:SetTextColor(opt_colors.QuestTitleConnector[1], opt_colors.QuestTitleConnector[2], opt_colors.QuestTitleConnector[3]) -- connector quest [type i] (incomplete, 0/0 objectives)
  1873.         elseif numObj == completedObj then
  1874.             button.title:SetTextColor(1, 0, 1) -- unknown state (incomplete, n/n objectives where n>0)
  1875.         else
  1876.             local color = GetQuestDifficultyColor(level)
  1877.             button.title:SetTextColor(color.r, color.g, color.b) -- incomplete quest (incomplete, n/m objectives where m>n)
  1878.         end
  1879.     end
  1880.  
  1881.     if collapseObjectives then
  1882.         button.title:SetAlpha(0.6)
  1883.     end
  1884.    
  1885.     -- add item button
  1886.     local link, item, charges, showItemWhenComplete = GetQuestLogSpecialItemInfo(questIndex)
  1887.     local itemButton
  1888.     if opt_itemAnchorSide and item and ((isComplete ~= 1) or (showItemWhenComplete)) then
  1889.         if InCombatLockdown() then
  1890.             startCombatTimer()
  1891.         else
  1892.             itemButton = _G["QuestKing_WatchFrameItem" .. button.buttonNumber]
  1893.            
  1894.             if (not itemButton) then
  1895.                 --itemButton = CreateFrame("Button", "QuestKing_WatchFrameItem" .. button.buttonNumber, button, "WatchFrameItemButtonTemplate")
  1896.                 itemButton = CreateFrame("Button", "QuestKing_WatchFrameItem" .. button.buttonNumber, UIParent, "WatchFrameItemButtonTemplate")
  1897.                 button.itemButton = itemButton
  1898.             end
  1899.            
  1900.             -- setup
  1901.             itemButton:Show()
  1902.             itemButton:ClearAllPoints()
  1903.             itemButton:SetID(questIndex)
  1904.             SetItemButtonTexture(itemButton, item)
  1905.             SetItemButtonCount(itemButton, charges)
  1906.             itemButton.charges = charges
  1907.             WatchFrameItem_UpdateCooldown(itemButton)
  1908.             itemButton.rangeTimer = -1
  1909.    
  1910.             -- anchor
  1911.             if opt_itemAnchorSide == "right" then      
  1912.                 itemButton:SetPoint("TOPLEFT", button.title, "TOPRIGHT", 4, -1)
  1913.             else
  1914.                 itemButton:SetPoint("TOPRIGHT", button.title, "TOPLEFT", -4, -1)
  1915.             end
  1916.            
  1917.             -- resize
  1918.             if displayedObj > 0 then
  1919.                 itemButton:SetHeight(opt_lineHeight * 2)
  1920.                 _G[format("QuestKing_WatchFrameItem%dIconTexture", button.buttonNumber)]:SetTexCoord(0, 1, 0, 1)
  1921.                 _G[format("QuestKing_WatchFrameItem%dNormalTexture", button.buttonNumber)]:SetHeight(42)
  1922.             else
  1923.                 itemButton:SetHeight(opt_lineHeight)
  1924.                 _G[format("QuestKing_WatchFrameItem%dIconTexture", button.buttonNumber)]:SetTexCoord(0, 1, 0.25, 0.75)
  1925.                 _G[format("QuestKing_WatchFrameItem%dNormalTexture", button.buttonNumber)]:SetHeight(21)
  1926.             end
  1927.             itemButton:SetWidth(opt_lineHeight * 2)
  1928.             itemButton:SetScale(0.9)
  1929.         end
  1930.        
  1931.     else
  1932.         if button.itemButton and button.itemButton:IsShown() then
  1933.             if InCombatLockdown() then
  1934.                 startCombatTimer()
  1935.             else       
  1936.                 button.itemButton:Hide()
  1937.             end
  1938.         end
  1939.     end
  1940.  
  1941.     if (opt_subzoneHeuristicHighlight) then
  1942.         local subzone = string.lower(GetSubZoneText() or "")
  1943.  
  1944.         SelectQuestLogEntry(questIndex)
  1945.         local logDescription, logObjectives = GetQuestLogQuestText()
  1946.  
  1947.         logDescription = (logDescription and string.lower(logDescription)) or "<<QK_ERROR>>"
  1948.         logObjectives = (logObjectives and string.lower(logObjectives)) or "<<QK_ERROR>>"
  1949.  
  1950.         if (subzone ~= "") then
  1951.             if (string.find(logDescription, subzone, 1, true)) or (string.find(logObjectives, subzone, 1, true)) then
  1952.                 button:SetBackdropColor(opt_colors.SubzoneHeuristicHighlightColor[1], opt_colors.SubzoneHeuristicHighlightColor[2], opt_colors.SubzoneHeuristicHighlightColor[3], opt_colors.SubzoneHeuristicHighlightColor[4])
  1953.             end
  1954.         end
  1955.     end
  1956.    
  1957. end
  1958.  
  1959.  
  1960. function updateTrackerAchievements()
  1961.     local trackedAchievements = trackedAchievementCache
  1962.     trackedAchievementCache = trackedAchievements
  1963.    
  1964.     local numTrackedAchievements = #trackedAchievements
  1965.  
  1966.     -- header
  1967.     local showAchievements = true
  1968.     if (dbc.displayMode == "combined") then
  1969.         local headerName = "Achievements"
  1970.         if numTrackedAchievements > 0 then
  1971.             local button = WatchButton:GetNext()
  1972.             button.type = "header"
  1973.             button.headerName = headerName
  1974.    
  1975.             if dbc.collapsedHeaders[headerName] then
  1976.                 button.title:SetText("|TInterface\\AddOns\\QuestKing\\UI-SortArrow_sm_right:8:8:0:-1:0:0:0:0:0:0:1:1:1|t"..headerName)
  1977.                 button.title:SetTextColor(opt_colors.AchievementHeaderCollapsed[1], opt_colors.AchievementHeaderCollapsed[2], opt_colors.AchievementHeaderCollapsed[3])
  1978.             else
  1979.                 button.title:SetText("|TInterface\\AddOns\\QuestKing\\UI-SortArrow_sm_down:8:8:0:-1:0:0:0:0:0:0:1:1:1|t"..headerName)
  1980.                 button.title:SetTextColor(opt_colors.AchievementHeader[1], opt_colors.AchievementHeader[2], opt_colors.AchievementHeader[3])
  1981.             end
  1982.            
  1983.             button:Layout()
  1984.         end
  1985.        
  1986.         if dbc.collapsedHeaders[headerName] then
  1987.             showAchievements = false
  1988.         end
  1989.     end
  1990.    
  1991.     -- achievements
  1992.     if showAchievements then
  1993.         for i = 1, numTrackedAchievements do
  1994.             local achievementID = trackedAchievements[i]
  1995.            
  1996.             local button = WatchButton:GetNext()
  1997.             button.type = "achievement"
  1998.             setButtonToAchievement(button, achievementID)
  1999.             button:Layout()
  2000.         end
  2001.     end
  2002. end
  2003.  
  2004. function setButtonToAchievement (button, achievementID)
  2005.     local id, achievementName, points, achievemntCompleted, _, _, _, achievementDesc, flags, image, rewardText, isGuildAch = GetAchievementInfo(achievementID) 
  2006.  
  2007.     button.achievementID = achievementID
  2008.  
  2009.     local collapseCriteria = dbc.collapsedAchievements[achievementID]
  2010.  
  2011.     -- set title       
  2012.     button.title:SetText(achievementName)
  2013.     if completed then
  2014.         button.title:SetTextColor(opt_colors.AchievementTitleComplete[1], opt_colors.AchievementTitleComplete[2], opt_colors.AchievementTitleComplete[3])
  2015.     else
  2016.         if isGuildAch then
  2017.             button.title:SetTextColor(opt_colors.AchievementTitleGuild[1], opt_colors.AchievementTitleGuild[2], opt_colors.AchievementTitleGuild[3])
  2018.         else
  2019.             button.title:SetTextColor(opt_colors.AchievementTitle[1], opt_colors.AchievementTitle[2], opt_colors.AchievementTitle[3])
  2020.         end
  2021.     end
  2022.    
  2023.     if collapseCriteria then
  2024.         button.title:SetAlpha(0.6)
  2025.     end
  2026.    
  2027.     -- criteria setup
  2028.     local numCriteria = GetAchievementNumCriteria(achievementID)   
  2029.     local foundTimer = false
  2030.     local timeNow -- avoid multiple calls to GetTime()
  2031.    
  2032.     -- no criteria
  2033.     if (numCriteria == 0) then
  2034.         if (not collapseCriteria) then
  2035.             button:AddLine("  "..achievementDesc, nil, opt_colors.AchievementDescription[1], opt_colors.AchievementDescription[2], opt_colors.AchievementDescription[3]) -- no criteria exist, show desc line
  2036.         end
  2037.     end
  2038.    
  2039.     -- criteria loop
  2040.     for i = 1, numCriteria do
  2041.         local _
  2042.         local criteriaString, criteriaType, criteriaCompleted, quantity, totalQuantity, name, flags, assetID, quantityString, criteriaID, eligible = GetAchievementCriteriaInfo(achievementID, i)
  2043.        
  2044.         -- set string
  2045.         if (bit.band(flags, EVALUATION_TREE_FLAG_PROGRESS_BAR) == EVALUATION_TREE_FLAG_PROGRESS_BAR) then
  2046.             criteriaString = quantityString
  2047.         else
  2048.             if (criteriaType == CRITERIA_TYPE_ACHIEVEMENT and assetID) then -- meta achievement
  2049.                 _, criteriaString = GetAchievementInfo(assetID)
  2050.             end
  2051.         end
  2052.        
  2053.         -- display criteria depending on timer state
  2054.         -- kinda wanna seperate this out, but display is dependent on timer logic (e.g. timeLeft > 0 forces display)
  2055.         local timerTable = achievementTimers[criteriaID]
  2056.         local timeLeft = 0
  2057.         if timerTable then
  2058.             -- timer exists
  2059.             foundTimer = true
  2060.             timeNow = timeNow or GetTime()
  2061.             local timeLeft = floor(timerTable.startTime + timerTable.duration - timeNow)
  2062.            
  2063.             if timeLeft > 0 then
  2064.                 -- timer is running, force showing criteria
  2065.                 if criteriaCompleted then
  2066.                     button:AddLine("  "..criteriaString, nil, opt_colors.AchievementCriteriaComplete[1], opt_colors.AchievementCriteriaComplete[2], opt_colors.AchievementCriteriaComplete[3]) -- timer running, force showing completed objective
  2067.                 else
  2068.                     button:AddLine("  "..criteriaString, nil, opt_colors.AchievementCriteria[1], opt_colors.AchievementCriteria[2], opt_colors.AchievementCriteria[3]) -- timer running, force showing normal objective
  2069.                 end
  2070.                
  2071.                 -- adding timer line
  2072.                 local time = SecondsToTime(timeLeft, false, false, 4)
  2073.                 if (time == "") then time = "0 Sec" end
  2074.                
  2075.                 button.title:SetTextColor(opt_colors.AchievementTimedTitle[1], opt_colors.AchievementTimedTitle[2], opt_colors.AchievementTimedTitle[3])
  2076.                 button:SetBackdropColor(opt_colors.AchievementTimedBackground[1], opt_colors.AchievementTimedBackground[2], opt_colors.AchievementTimedBackground[3], opt_colors.AchievementTimedBackground[4])
  2077.                 --D(opt_colors.AchievementTimedBackground[1], opt_colors.AchievementTimedBackground[2], opt_colors.AchievementTimedBackground[3], opt_colors.AchievementTimedBackground[4])
  2078.                 local line = button:AddLine("    "..time, nil, opt_colors.AchievementTimedTimer[1], opt_colors.AchievementTimedTimer[2], opt_colors.AchievementTimedTimer[3])
  2079.                
  2080.                 line.isTimer = true
  2081.                 line.startTime = timerTable.startTime
  2082.                 line.duration = timerTable.duration
  2083.                
  2084.                 button:SetScript("OnUpdate", onUpdateAchievementTimer)
  2085.                
  2086.             else
  2087.                 -- timer has expired
  2088.                 if (not criteriaCompleted) and (not collapseCriteria) then
  2089.                     button:AddLine("  "..criteriaString, nil, opt_colors.AchievementCriteria[1], opt_colors.AchievementCriteria[2], opt_colors.AchievementCriteria[3]) -- timer expired, show normally unless completed/collapsed
  2090.                 end
  2091.                 achievementTimers[criteriaID] = nil -- since timer expired, erase it ourselves without waiting for event
  2092.             end
  2093.            
  2094.         else
  2095.             -- no timer exists
  2096.             if (not criteriaCompleted) and (not collapseCriteria) then
  2097.                 button:AddLine("  "..criteriaString, nil, opt_colors.AchievementCriteria[1], opt_colors.AchievementCriteria[2], opt_colors.AchievementCriteria[3]) -- no timer, show normally unless completed/collapsed
  2098.             end
  2099.         end
  2100.        
  2101.     end
  2102.  
  2103.     -- show "meta" timer if there is a timer on this achievement, but no associated criteria are found in GetAchievementNumCriteria (Salt and Pepper?)
  2104.     -- multiple timers would be a problem (it sets/unsets with whichever criteria timer fires last), but it's better than nothing
  2105.     if (foundTimer == false) and (achievementTimersMeta[achievementID]) then
  2106.         local timerTable = achievementTimersMeta[achievementID]
  2107.         local timeNow = GetTime()
  2108.         local timeLeft = floor(timerTable.startTime + timerTable.duration - timeNow)
  2109.  
  2110.         if timeLeft > 0 then
  2111.             local time = SecondsToTime(timeLeft, false, false, 4)
  2112.             if (time == "") then time = "0 Sec" end
  2113.            
  2114.             button.title:SetTextColor(opt_colors.AchievementTimedTitle[1], opt_colors.AchievementTimedTitle[2], opt_colors.AchievementTimedTitle[3])
  2115.             button:SetBackdropColor(opt_colors.AchievementTimedBackground[1], opt_colors.AchievementTimedBackground[2], opt_colors.AchievementTimedBackground[3], opt_colors.AchievementTimedBackground[4])
  2116.             local line = button:AddLine("    "..time, nil, opt_colors.AchievementTimedTimerMeta[1], opt_colors.AchievementTimedTimerMeta[2], opt_colors.AchievementTimedTimerMeta[3])
  2117.            
  2118.             line.isTimer = true
  2119.             line.startTime = timerTable.startTime
  2120.             line.duration = timerTable.duration
  2121.            
  2122.             button:SetScript("OnUpdate", onUpdateAchievementTimer)
  2123.         end
  2124.     end
  2125.    
  2126. end
  2127.  
  2128. function onUpdateAchievementTimer (self, elapsed)
  2129.     local updateTimer = self.updateTimer
  2130.     updateTimer = updateTimer - elapsed
  2131.     if (updateTimer <= 0) then
  2132.         local timeNow
  2133.         for i = 1, #self.linesLeft do
  2134.             local line = self.linesLeft[i]
  2135.             if line.isTimer then
  2136.                 timeNow = timeNow or GetTime()
  2137.                 local timeLeft = floor(line.startTime + line.duration - timeNow)
  2138.                
  2139.                 if timeLeft > 0 then
  2140.                     --D(timeLeft)
  2141.                     local time = SecondsToTime(timeLeft, false, false, 4)
  2142.                     if (time == "") then time = "0 Sec" end            
  2143.                     line:SetText("    "..time)
  2144.                 else
  2145.                     --D("EXPIRED")
  2146.                     updateTracker()
  2147.                     return
  2148.                 end
  2149.             end
  2150.         end
  2151.         updateTimer = opt_updateRate
  2152.     end
  2153.     self.updateTimer = updateTimer
  2154. end
  2155.    
  2156.  
  2157. function buildQuestSortTable ()
  2158.     for k,v in pairs(questSortTable) do
  2159.         wipe(questSortTable[k])
  2160.     end
  2161.     wipe(headerList)
  2162.    
  2163.     local numEntries = GetNumQuestLogEntries()
  2164.     local currentHeader = "(Unknown)"
  2165.    
  2166.     local numQuests = 0
  2167.     for i = 1, numEntries do
  2168.         local title,_,_,_,isHeader,isCollapsed,_,_,_ = GetQuestLogTitle(i)
  2169.         if (not title) or (title == "") then
  2170.             title = "(Unknown)"
  2171.         end
  2172.  
  2173.         if (isHeader) then
  2174.             currentHeader = title
  2175.             tinsert(headerList, title)
  2176.             if not questSortTable[title] then
  2177.                 questSortTable[title] = {}
  2178.             end
  2179.         elseif (not isHeader) and (IsQuestWatched(i)) then
  2180.             if (not questSortTable[currentHeader]) then
  2181.                 questSortTable[currentHeader] = {}
  2182.             end
  2183.             tinsert(questSortTable[currentHeader], i)
  2184.         end
  2185.        
  2186.         if (not isHeader) then
  2187.             numQuests = numQuests + 1
  2188.         end
  2189.     end
  2190.    
  2191.     totalQuestCount = numQuests
  2192. end
  2193.  
  2194. function getQuestTaggedTitle (questIndex)
  2195.     local questTitle, level, questTag, suggestedGroup, _, _, _, isDaily, questID, startEvent, displayQuestID = GetQuestLogTitle(questIndex)
  2196.    
  2197.     -- determine tag
  2198.     local levelClass = tostring(level)
  2199.     if (isDaily) then
  2200.         levelClass = levelClass.."Y"
  2201.     end
  2202.     if (questTag ~= nil) then
  2203.         if ((questTag == "Group") and (suggestedGroup > 0)) then
  2204.             levelClass = levelClass.."G"..suggestedGroup
  2205.         elseif ((questTag == "Group") or (questTag == "Elite")) then
  2206.             levelClass = levelClass.."+"
  2207.         elseif (questTag == "Dungeon") then
  2208.             levelClass = levelClass.."D"
  2209.         elseif (questTag == "Heroic") then
  2210.             levelClass = levelClass.."H"
  2211.         elseif ((questTag == "Raid (10)") or (questTag == "Raid (25)") or (questTag == "Raid")) then   
  2212.             levelClass = levelClass.."R"                   
  2213.         elseif (questTag == "PvP") then
  2214.             levelClass = levelClass.."P"
  2215.         elseif (questTag == "Scenario") then
  2216.             levelClass = levelClass.."S"
  2217.         elseif (questTag == "Legendary") then
  2218.             levelClass = levelClass.."L"
  2219.         elseif (questTag == "Account") then
  2220.             levelClass = levelClass.."A"
  2221.         else
  2222.             levelClass = levelClass.."+"
  2223.         end
  2224.     end
  2225.    
  2226.     if startEvent then
  2227.         levelClass = levelClass.."e"
  2228.     end
  2229.  
  2230.     if GetQuestLogIsAutoComplete(questIndex) then
  2231.         levelClass = levelClass.."a"
  2232.     end
  2233.    
  2234.     return format("[%s] %s", levelClass, questTitle)
  2235. end
  2236.  
  2237. function colorGradient(perc, ...)
  2238.     if perc >= 1 then
  2239.         local r, g, b = select(select('#', ...) - 2, ...)
  2240.         return r, g, b
  2241.     elseif perc <= 0 then
  2242.         local r, g, b = ...
  2243.         return r, g, b
  2244.     end
  2245.  
  2246.     local num = select('#', ...) / 3
  2247.  
  2248.     local segment, relperc = math_modf(perc*(num-1))
  2249.     local r1, g1, b1, r2, g2, b2 = select((segment*3)+1, ...)
  2250.  
  2251.     return r1 + (r2-r1)*relperc, g1 + (g2-g1)*relperc, b1 + (b2-b1)*relperc
  2252. end
  2253.  
  2254. function getObjectiveColor(progress)
  2255.     local r, g, b
  2256.     if (progress == 1) then
  2257.         r, g, b = opt_colors.ObjectiveGradientComplete[1], opt_colors.ObjectiveGradientComplete[2], opt_colors.ObjectiveGradientComplete[3]
  2258.     else
  2259.         r, g, b = colorGradient(progress,
  2260.             opt_colors.ObjectiveGradient0[1], opt_colors.ObjectiveGradient0[2], opt_colors.ObjectiveGradient0[3],
  2261.             opt_colors.ObjectiveGradient50[1], opt_colors.ObjectiveGradient50[2], opt_colors.ObjectiveGradient50[3],
  2262.             opt_colors.ObjectiveGradient99[1], opt_colors.ObjectiveGradient99[2], opt_colors.ObjectiveGradient99[3])
  2263.     end
  2264.     return r, g, b
  2265. end
  2266.  
  2267. -- Misc
  2268.  
  2269. local old_WatchFrame_Update = WatchFrame_Update
  2270. -- @@@@@ test BRC quest with BOTH open - done
  2271. function WatchFrame_Update()
  2272.     --D('HIDING')
  2273.     WatchFrame:Hide()
  2274.     if not WatchFrame.qkfix then
  2275.         WatchFrame.qkfix = true
  2276.         WatchFrame:UnregisterAllEvents()
  2277.         WatchFrameLines:UnregisterAllEvents()
  2278.     end
  2279. end
  2280.  
  2281. WatchFrame:HookScript("OnShow",function ()
  2282.     WatchFrame:Hide()
  2283. end)
  2284.  
  2285. QuestKing_UpdateTracker = updateTracker
  2286.  
  2287. SLASH_QUESTKING_RESET1 = "/qkreset"
  2288. SlashCmdList["QUESTKING_RESET"] = function(msg, editBox)
  2289.     print("QuestKing: Resetting all collapsed headers/quests/achievements.")
  2290.     dbc.collapsedHeaders = {}
  2291.     dbc.collapsedQuests = {}
  2292.     dbc.collapsedAchievements = {}
  2293.  
  2294.     -- dbc.trackerCollapsed = false
  2295.     -- dbc.trackerHidden = false
  2296.     updateTracker()
  2297. end
  2298.  
  2299. fEvents:SetScript("OnEvent", function(self, event, name)
  2300.     if name ~= addonName then return end
  2301.    
  2302.     self:UnregisterEvent("ADDON_LOADED")
  2303.     self:SetScript("OnEvent", QuestKing_HandleEvent)
  2304.    
  2305.     if not (QuestKingDB) then
  2306.         QuestKingDB = {}
  2307.     end
  2308.     if not (QuestKingDBPerChar) then
  2309.         QuestKingDBPerChar = {}
  2310.     end
  2311.  
  2312.     db = QuestKingDB
  2313.     dbc = QuestKingDBPerChar
  2314.    
  2315.     dbc.collapsedHeaders = dbc.collapsedHeaders or {}
  2316.     dbc.collapsedQuests = dbc.collapsedQuests or {}
  2317.     dbc.collapsedAchievements = dbc.collapsedAchievements or {}
  2318.     dbc.trackerCollapsed = dbc.trackerCollapsed or false
  2319.    
  2320.     dbc.displayMode = dbc.displayMode or "combined"
  2321.     dbc.trackerPositionPreset = dbc.trackerPositionPreset or 1
  2322.  
  2323.     -- dbc.trackerHidden = dbc.trackerHidden or false
  2324.     -- dbc.trackerPositionCustom = dbc.trackerPositionCustom or false
  2325.    
  2326.     -- i don't understand why this doesn't work...
  2327.     -- WATCHFRAME_MAXACHIEVEMENTS = 100
  2328.    
  2329.     self:RegisterEvent("QUEST_LOG_UPDATE")
  2330.     self:RegisterEvent("ITEM_PUSH")
  2331.  
  2332.     self:RegisterEvent("QUEST_AUTOCOMPLETE")
  2333.  
  2334.     self:RegisterEvent("TRACKED_ACHIEVEMENT_UPDATE") -- Achievement timers
  2335.     self:RegisterEvent("ACHIEVEMENT_EARNED") -- necessary?
  2336.     --self:RegisterEvent("CRITERIA_UPDATE")
  2337.     self:RegisterEvent("PLAYER_LEVEL_UP")
  2338.    
  2339.     self:RegisterEvent("UI_INFO_MESSAGE")
  2340.  
  2341.     self:RegisterEvent("PLAYER_MONEY") -- for GetQuestLogRequiredMoney
  2342.  
  2343.     self:RegisterEvent("SCENARIO_UPDATE")
  2344.     self:RegisterEvent("SCENARIO_CRITERIA_UPDATE")
  2345.  
  2346.     self:RegisterEvent("PLAYER_ENTERING_WORLD")
  2347.     self:RegisterEvent("WORLD_STATE_TIMER_START")
  2348.     self:RegisterEvent("WORLD_STATE_TIMER_STOP")
  2349.  
  2350.     if (opt_subzoneHeuristicHighlight) then
  2351.     self:RegisterEvent("ZONE_CHANGED")
  2352.         self:RegisterEvent("ZONE_CHANGED_INDOORS")
  2353.         self:RegisterEvent("ZONE_CHANGED_NEW_AREA")
  2354.     end
  2355.    
  2356.     if (opt_enableItemPopups) then
  2357.         self:RegisterEvent("CHAT_MSG_LOOT")
  2358.         QUEST_START_ITEMS = {1307,1357,1972,2839,3082,3317,4056,4433,4613,4854,4881,4926,5099,5102,5103,5138,5179,5352,5791,5877,6172,6196,6497,6766,6775,6776,6916,8244,8524,8623,8704,8705,9326,9572,10454,10589,10590,10593,10621,11116,11668,12558,12564,12771,12842,13140,14646,14647,14648,14649,14650,14651,16303,16304,16305,16408,16782,17008,17115,17116,17409,18356,18357,18358,18359,18360,18361,18362,18363,18364,18422,18423,18565,18589,18628,18703,18706,18769,18770,18771,18969,18987,19002,19003,19016,19018,19228,19257,19267,19277,19423,19443,19452,19802,20310,20460,20461,20483,20644,20741,20742,20765,20798,20806,20807,20938,20939,20940,20941,20942,20943,20944,20945,20946,20947,20948,21165,21166,21167,21220,21221,21230,21245,21246,21247,21248,21249,21250,21251,21252,21253,21255,21256,21257,21258,21259,21260,21261,21262,21263,21264,21265,21378,21379,21380,21381,21382,21384,21385,21514,21749,21750,21751,21776,22597,22600,22601,22602,22603,22604,22605,22606,22607,22608,22609,22610,22611,22612,22613,22614,22615,22616,22617,22618,22620,22621,22622,22623,22624,22719,22723,22727,22888,22970,22972,22973,22974,22975,22977,23179,23180,23181,23182,23183,23184,23216,23228,23249,23338,23580,23678,23759,23777,23797,23837,23850,23870,23890,23892,23900,23904,23910,24132,24228,24330,24367,24407,24414,24483,24484,24504,24558,24559,25459,25705,25706,25752,25753,28113,28114,28552,28598,29233,29234,29235,29236,29476,29588,29590,29738,30431,30579,30756,31120,31239,31241,31345,31363,31384,31489,31707,31890,31891,31907,31914,32385,32386,32405,32523,32621,32726,33102,33121,33289,33314,33345,33347,33961,33962,33978,34028,34090,34091,34469,34777,34815,34984,35120,35567,35568,35569,35648,35723,35787,35855,36742,36744,36746,36756,36780,36855,36856,36940,36958,37163,37164,37432,37571,37599,37736,37737,37830,37833,38280,38281,38321,38567,38660,38673,39713,40666,41267,41556,42203,42772,43242,43297,43512,44148,44158,44259,44276,44294,44326,44569,44577,44725,44927,44979,45039,45506,45857,46004,46052,46053,46128,46318,46697,46875,46876,46877,46878,46879,46880,46881,46882,46883,46884,46955,47039,47246,48679,49010,49200,49203,49205,49219,49220,49641,49643,49644,49667,49676,49776,49932,50320,50379,50380,51315,52079,52197,52831,53053,53106,54345,54614,54639,55166,55167,55181,55186,55243,56474,56571,56812,57102,57118,57935,58117,58491,58898,59143,60816,60886,60956,61310,61322,61378,61505,62021,62044,62045,62046,62056,62138,62281,62282,62483,62768,62933,63090,63250,63276,63686,63700,64353,64450,65894,65895,65896,65897,69854,70928,70932,73058,74034,77957,78912,79238,79323,79324,79325,79326,79341,79343,79812,80240,80241,80597,80827,82870,83076,83767,83769,83770,83771,83772,83773,83774,83777,83779,83780,85477,85557,85558,85783,86404,86433,86434,86435,86436,86542,86544,86545,87878,88538,88563,88715,89169,89170,89171,89172,89173,89174,89175,89176,89178,89179,89180,89181,89182,89183,89184,89185,89209}
  2359.     end
  2360.    
  2361.     WatchFrame:UnregisterEvent("QUEST_AUTOCOMPLETE")
  2362.    
  2363.     hooksecurefunc("AddQuestWatch", hookQuestWatch)
  2364.     hooksecurefunc("RemoveQuestWatch", hookQuestWatch)
  2365.    
  2366.     hooksecurefunc("AddAutoQuestPopUp", function ()
  2367.         updateTracker()
  2368.     end)
  2369.  
  2370.     QuestKing:CreateTracker()
  2371.     updateTracker()
  2372.  
  2373.     -- QuestKing.UpdateTracker = updateTracker
  2374.     -- QuestKing_Tracker:SetScript("OnShow", function (self)
  2375.     --  dbc.trackerHidden = false
  2376.     --  updateTracker()
  2377.     --  print("QuestKing tracker shown.")
  2378.     -- end)
  2379.     -- QuestKing_Tracker:SetScript("OnHide", function (self)
  2380.     --  dbc.trackerHidden = true
  2381.     --  print("QuestKing tracker hidden.")
  2382.     -- end)
  2383.     -- if (dbc.trackerHidden == true) then
  2384.     --  QuestKing_Tracker:Hide()
  2385.     -- end
  2386.  
  2387.     -- QuestKing_Tracker.TitleRegion = QuestKing_Tracker:CreateTitleRegion()
  2388.     -- QuestKing_Tracker.TitleRegion:SetAllPoints()
  2389.     -- QuestKing_Tracker:EnableMouse(true)
  2390.     -- QuestKing_Tracker:SetMovable(true)
  2391.  --    QuestKing_Tracker:SetScript("OnMouseDown", function ()
  2392.  --        QuestKing_Tracker:StartMoving()
  2393.  --    end)
  2394.  --    QuestKing_Tracker:SetScript("OnMouseUp", function ()
  2395.  --        QuestKing_Tracker:StopMovingOrSizing()
  2396.  --    end)
  2397.     --QuestKing_Tracker.TitleRegion:EnableMouse(1)
  2398.     --QuestKing_Tracker.TitleRegion:SetPoint("TOPLEFT")
  2399.     --QuestKing_Tracker.TitleRegion:SetPoint("TOPRIGHT")
  2400.     --QuestKing_Tracker.TitleRegion:SetHeight(opt_titleHeight)
  2401. end)
  2402.  
  2403. fEvents:RegisterEvent("ADDON_LOADED")
  2404.  
  2405.  
  2406. -- Debug stuff, ignore
  2407.  
  2408. -- /run QuestKing_HandleEvent(nil, "TRACKED_ACHIEVEMENT_UPDATE", 2188, 7622, 10, 15); QuestKing_HandleEvent(nil, "TRACKED_ACHIEVEMENT_UPDATE", 3815, 0, 10, 20);
  2409. -- /run AddAutoQuestPopUp(28790, "OFFER"); AddAutoQuestPopUp(25771, "COMPLETE"); QuestKing_UpdateTracker();
  2410.  
  2411. -- function GetQuestTimers()
  2412. --  return GetTime() - 2095200, GetTime() - 2095200, GetTime() - 2095200
  2413. -- end
  2414. --
  2415. -- function GetQuestIndexForTimer(timerID)
  2416. --  if timerID == 1 then
  2417. --      return 2
  2418. --  elseif timerID == 2 then
  2419. --      return 4
  2420. --  else
  2421. --      return 5
  2422. --  end
  2423. -- end
  2424.  
  2425. --/run Boss1TargetFrame:Show(); Boss1TargetFrame:SetPoint("TOPRIGHT", "QuestKing_Tracker", "TOPLEFT", 50, 0)
  2426. --/run VehicleSeatIndicator_SetUpVehicle(221)
  2427. --/run UIParent_ManageFramePositions()
  2428.  
  2429. -- FramePositionDelegate:UIParentManageFramePositions
  2430. -- Boss1TargetFrame:UnregisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT")
  2431. --   221 222 223 224 225 226 227 228 249 254
  2432.  
  2433. -- hook setpoint?
  2434.  
  2435. -- ? convert quest item checks to GetContainerItemQuestInfo
  2436. -- requires expensive bag scans on inventory change, issues with knowing which item is picked up, retriggering items on login etc.
  2437. -- probably not worth it... but does avoid issue of having to manually update IDs
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement