changeset 29:c1612c2c1840

WorldPlan: - Optimizations to in a lot of areas that should lead to better load-times and snappier world map. * Responding to quest log and map events by setting flags instead of tailing into the complete works. * Using a generic getter function for resolving pin visual attributes. and making use of blizzard constants for sanity's sake.
author Nenue
date Thu, 27 Oct 2016 13:50:56 -0400
parents 3f4368c4a49b
children 8cb750e79952
files QuestPOI.lua WorldPlan.lua WorldPlan.xml
diffstat 3 files changed, 360 insertions(+), 334 deletions(-) [+]
line wrap: on
line diff
--- a/QuestPOI.lua	Thu Oct 27 06:19:05 2016 -0400
+++ b/QuestPOI.lua	Thu Oct 27 13:50:56 2016 -0400
@@ -3,13 +3,17 @@
 -- Created: 10/1/2016 7:21 PM
 -- %file-revision%
 --
+
+local TQ_GetQuestInfoByQuestID = C_TaskQuest.GetQuestInfoByQuestID -- Return the name of a quest with a given ID
 local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation
 local TQ_GetQuestTimeLeftMinutes = C_TaskQuest.GetQuestTimeLeftMinutes
 local TQ_IsActive = C_TaskQuest.IsActive
+local TQ_RequestPreloadRewardData = C_TaskQuest.RequestPreloadRewardData
 local QuestPOIGetIconInfo, WorldMapPOIFrame =  QuestPOIGetIconInfo, WorldMapPOIFrame
 
 local print = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end
 local qprint = DEVIAN_WORKSPACE and function(...) _G.print('POI', ...) end or function() end
+local wqprint = DEVIAN_WORKSPACE and function(...) _G.print('WorldQuest', ...) end or function() end
 local iprint = DEVIAN_WORKSPACE and function(...) _G.print('ItemScan', ...) end or function() end
 local QuestPOI = WorldPlanPOIMixin
 
@@ -23,6 +27,27 @@
 local POI_BORDER_YELLOW = "Interface\\BUTTONS\\YELLOWORANGE64"
 local POI_BORDER_GREEN = "Interface\\BUTTONS\\GREENGRAD64"
 
+local REWARD_CASH = WORLD_QUEST_REWARD_TYPE_FLAG_GOLD
+local REWARD_ARTIFACT_POWER = WORLD_QUEST_REWARD_TYPE_FLAG_ARTIFACT_POWER
+local REWARD_GEAR = WORLD_QUEST_REWARD_TYPE_FLAG_EQUIPMENT
+local REWARD_CURRENCY = WORLD_QUEST_REWARD_TYPE_FLAG_ORDER_RESOURCES
+local REWARD_REAGENT = WORLD_QUEST_REWARD_TYPE_FLAG_MATERIALS
+
+
+local LE_QUEST_TAG_TYPE_PVP = LE_QUEST_TAG_TYPE_PVP
+local LE_QUEST_TAG_TYPE_PET_BATTLE = LE_QUEST_TAG_TYPE_PET_BATTLE
+local LE_QUEST_TAG_TYPE_DUNGEON = LE_QUEST_TAG_TYPE_DUNGEON
+local LE_QUEST_TAG_TYPE_PROFESSION = LE_QUEST_TAG_TYPE_PROFESSION
+local LE_QUEST_TAG_TYPE_NORMAL = LE_QUEST_TAG_TYPE_NORMAL
+
+local LE_QUEST_TAG_TYPE_PVP = LE_QUEST_TAG_TYPE_PVP
+local LE_QUEST_TAG_TYPE_PET_BATTLE = LE_QUEST_TAG_TYPE_PET_BATTLE
+local LE_QUEST_TAG_TYPE_DUNGEON = LE_QUEST_TAG_TYPE_DUNGEON
+local LE_QUEST_TAG_TYPE_PROFESSION = LE_QUEST_TAG_TYPE_PROFESSION
+local LE_QUEST_TAG_TYPE_NORMAL = LE_QUEST_TAG_TYPE_NORMAL
+
+-- Pin color/display variables
+
   local familiars = {
       [42159] = {npc = 106552, name = 'Nightwatcher Merayl'},
       [40277] = {npc = 97804, name = 'Tiffany Nelson'},
@@ -43,25 +68,6 @@
   local familiars_id = 9696
 
 
-local PIN_TIME_CONTEXT = {
-  {max = 60,
-    r=1, g=0.25, b =0, format = function (minutes) return '|cFFFF4400'.. minutes .. 'm' end,
-    continentAlpha = 1, swipeTime = 1440,
-  },
-  {max = 240,
-    r=1, g=.5, b=0, format = function(minutes) return '|cFFFF4400'.. floor(minutes/60) .. 'h' end,
-    continentAlpha = 1, swipeTime = 1440,
-  },
-  {max = 1440,
-    r=1, g=1, b=0, format = function(minutes) return '|cFFFFFF00'.. floor(minutes/60) .. 'h' end,
-    continentAlpha = .55, swipeTime = 1440
-  },
-  {max = 10081,
-    r=0, g=1, b=0,
-    continentAlpha = .3,
-  }, -- 7 days + 1 minute
-}
-
 -- update a masked texture without messing up its blending mask
 local SetMaskedTexture = function(region, file, mask)
   mask = mask or POI_BORDER_MASK
@@ -70,6 +76,59 @@
   region:SetMask(mask)
 end
 
+
+-- use tooltip object to extract item details
+local ParseItemReward = function(questID)
+  local name, icon, quantity, quality, _, itemID = GetQuestLogRewardInfo(1, questID)
+  local scanner = _G.WorldPlanTooltip
+  if not itemID then
+    return
+  end
+
+  scanner:SetOwner(WorldPlan, "ANCHOR_NONE")
+  scanner:SetItemByID(itemID)
+  scanner:Show()
+  local ttl1 = _G['WorldPlanTooltipTextLeft1']
+  local ttl2 = _G['WorldPlanTooltipTextLeft2']
+  local ttl3 = _G['WorldPlanTooltipTextLeft3']
+  local ttl4 = _G['WorldPlanTooltipTextLeft4']
+  if ttl2 then
+    local text = ttl2:GetText()
+    -- Artifact Power
+    if text then
+      if text:match("|cFFE6CC80") then
+        --print('AP token!', text)
+        local power
+        if ttl4 then
+          local text = ttl4:GetText()
+          --print('tip line 4', text)
+          if text then
+            power = text:gsub("%p", ""):match("%d+")
+            power = tonumber(power)
+          end
+
+        end
+        return REWARD_ARTIFACT_POWER, "Interface\\ICONS\\inv_7xp_inscription_talenttome01", power, name, itemID
+      elseif text:match("Item Level") then
+        --print('equipment!', text)
+        quantity = text:match("Item Level ([%d\+]+)")
+        return REWARD_GEAR, icon, quantity, name, itemID
+      elseif  text:match("Crafting Reagent") then
+        --print('|cFFFF4400it is a reagent', text)
+        return REWARD_REAGENT, icon, quantity, name, itemID
+      end
+    end
+
+  elseif ttl3 then
+    local text = ttl3:GetText()
+    if  text:match("Crafting Reagent") then
+      --print('|cFFFF4400it is a reagent', text)
+      return REWARD_REAGENT, icon, quantity, name, itemID
+    end
+  end
+  return 128, icon, quantity, name, itemID
+end
+
 function WorldPlanPOIMixin:OnEnter()
   local completed = select(4,GetAchievementInfo(familiars_id))
   if not completed then
@@ -106,10 +165,113 @@
 end
 
 
+
+-- create or update the pin using the given questID and C_TaskQuest results
+function WorldPlanPOIMixin:RefreshData (info)
+
+  qprint('|cFF00FF88'..self:GetName()..':RefreshData()|r')
+
+  if info then
+
+    self.x = info.x or self.x
+    self.y = info.y or self.y
+    self.inProgress = info.inProgress
+    self.floor = info.floor
+    self.numObjectives = info.numObjectives or 0
+    print('|cFFFF4400subbing in new info', info.x, info.y, self.x, self.y)
+  end
+
+
+  local questID = self:GetID()
+  local questTitle, rewardIcon, rewardName, rewardCount, rewardStyle, rewardType, itemID, quantity, quality, _
+  local hasUpdate, isPending = self.isNew, false
+
+
+  if not HaveQuestData(questID) then
+    TQ_RequestPreloadRewardData(questID)
+    isPending = true
+    qprint('because not have data')
+  else
+
+    -- set reward category
+    local numRewards = GetNumQuestLogRewards(questID)
+    local numCurrency = GetNumQuestLogRewardCurrencies(questID)
+    local money = GetQuestLogRewardMoney(questID)
+    if numRewards >= 1 then
+      rewardType, rewardIcon, rewardCount, rewardName, itemID = ParseItemReward(questID)
+    elseif numCurrency >= 1 then
+      rewardName, rewardIcon, rewardCount = GetQuestLogRewardCurrencyInfo(1, questID)
+      rewardType = REWARD_CURRENCY
+    elseif money >= 1 then
+      rewardIcon = ICON_MONEY
+      rewardName = GetMoneyString(money)
+      rewardType = REWARD_CASH
+    end
+    rewardStyle = WorldPlan:GetTypeInfo(rewardType)
+
+    self.itemNumber = rewardCount or self.itemNumber
+    self.rewardType = rewardType or REWARD_ITEM
+    self.style = rewardStyle
+
+    -- title, faction, capped state
+    local questTitle, factionID, capped = TQ_GetQuestInfoByQuestID(questID)
+    self.factionID = factionID
+    self.capped = capped
+
+    -- set tag details
+    local tagID, tagName, worldQuestType, rarity, isElite, tradeskillLineIndex = GetQuestTagInfo(questID);
+    local tagAtlas
+    if worldQuestType == LE_QUEST_TAG_TYPE_PET_BATTLE then
+      tagAtlas = "worldquest-icon-petbattle"
+    elseif worldQuestType == LE_QUEST_TAG_TYPE_PVP then
+      tagAtlas = "worldquest-icon-pvp-ffa"
+    elseif worldQuestType == LE_QUEST_TAG_TYPE_PROFESSION then
+      local id = tradeskillLineIndex and select(7, GetProfessionInfo(tradeskillLineIndex))
+      if id then
+        tagAtlas = WORLD_QUEST_ICONS_BY_PROFESSION[id]
+      end
+    elseif worldQuestType == LE_QUEST_TAG_TYPE_DUNGEON then
+      tagAtlas = "worldquest-icon-dungeon"
+    end
+
+    self.tagID = tagID
+    self.tagName = tagName
+    self.worldQuestType = worldQuestType
+    self.isElite = isElite
+    self.tradeskillLineIndex = tradeskillLineIndex
+    self.rarity = rarity
+    self.tagAtlas = tagAtlas
+
+    -- flag unresolved info
+    if not (rewardIcon and rewardName) then
+      isPending = true
+      qprint('because not have icon')
+      TQ_RequestPreloadRewardData (questID)
+      --WorldPlan:print('|cFFFFFF00'..tostring(self.title)..'|r waiting on texture info')
+    else
+      if (rewardIcon and rewardName) and isPending then
+        --WorldPlan:print('|cFF00FF00'..tostring(self.title)..'|r has info', rewardIcon, rewardName)
+        hasUpdate = true
+      end
+      isPending = false
+    end
+
+    self.title = questTitle or "|cFFFF0000Retrieving..."
+    self.itemTexture = rewardIcon or self.itemTexture
+    self.itemName = rewardName or self.itemName
+    self.hasUpdate = hasUpdate
+    self.isPending = isPending
+
+
+    qprint('  |cFF00FFFF'..questID..'|r hasUpdate:', hasUpdate, 'isPending:', isPending)
+    qprint(' ', self.title, self.itemTexture, 'rewardType:', self.rewardType, 'tag:', self.tagID, 'style', self.style )
+  end
+  return hasUpdate, isPending
+end
+
+
 function WorldPlanPOIMixin:SetAchievementProgressTooltip()
   print('cheevos')
-
-
 end
 
 function WorldPlanPOIMixin:ShowNew()
@@ -133,8 +295,9 @@
 end
 
 function WorldPlanPOIMixin:SetAnchor(frame, mapID, mapWidth, mapHeight)
+  qprint('  |cFF00FF00'..self:GetName()..':SetAnchor()|r', self.questID, mapID, mapWidth)
   self:ClearAllPoints()
-  local dX, dY = TQ_GetQuestLocation(self.questID, mapID)
+  local dX, dY = TQ_GetQuestLocation(self.questID)
   if not dX or dX == 0 then
     local _, x, y = QuestPOIGetIconInfo(self.questID)
     if x and floor(x) ~= 0 then
@@ -146,7 +309,7 @@
   self.x = dX
   self.y = dY
 
-  qprint('  |cFF00FF00'..self.questID..':|r', format("%0.2f %0.2f", dX, dY))
+  --qprint('  |cFF00FF00'..self.questID..':|r', format("%0.2f %0.2f", dX, dY))
 
   local pX = (dX * mapWidth)
   local pY = (-dY * mapHeight)
@@ -187,7 +350,7 @@
   -- query for reward data if it wasn't found in the original scan
   local questID = self.questID
   if self.isPending then
-    self:Reset()
+    self:RefreshData()
     if not (self.PendingFade:IsPlaying() or self.isAnimating) then
       self.PendingFade:Play()
     end
@@ -207,25 +370,10 @@
   local tl = self.timeThreschold
   local timeLeft = TQ_GetQuestTimeLeftMinutes(questID)
   if timeLeft > 0 then
-    for i, context in ipairs(PIN_TIME_CONTEXT) do
-      if i > self.TimeleftStage then
-        self.timeLabel:SetText(nil)
-        break
-      end
-
-
-      if timeLeft <= context.max then
-        if tl ~= i then
-          tl = i
-        end
-
-        if context.format then
-          self.timeLabel:SetText(context.format(timeLeft))
-        else
-          self.timeLabel:SetText(nil)
-        end
-        break
-      end
+    local text, timeState = WorldPlan:GetTimeInfo(timeLeft, self.TimeleftStage)
+    if tl ~= timeState then
+      tl = timeState
+      self.timeLabel:SetText(text)
     end
   else
     -- remove self in a timely manner
@@ -255,9 +403,12 @@
 
 
 
-  local questID = self.questId
-  local style = self.style
-  local subStyle = style[(self.filtered and 'minimized' or 'continent')]
+  local questID = self:GetID()
+  local style,subStyle =  WorldPlan:GetTypeInfo(self.rewardType or ((self.quality or 0) + 127))
+  if self.filtered then
+    subStyle = style.minimized
+  end
+
   local borderMask = style.mask
   local borderFill = style.texture
   local iconBorder = self.iconBorder
@@ -280,18 +431,21 @@
     local color = self.rewardColor or COMMON_COLOR
 
 
-    self.label:SetShown( self.showNumber)
+
     if self.hasNumeric then
-      self.label:SetText(self.itemNumber)
-      self.label:SetTextColor(unpack(self.numberRGB))
+      self.count:SetShown(true)
+      self.count:SetText(self.itemNumber)
+      self.count:SetTextColor(unpack(self.numberRGB))
     else
-      self.label:SetText(nil)
+      self.count:SetShown(false)
+      self.count:SetText(nil)
     end
 
   end
 
   SetMaskedTexture(iconBorder, borderFill, borderMask)
-  local border = (self.rewardType and db.rewardStyle[self.rewardType]) or (WORLD_QUEST_QUALITY_COLORS[self.rarity] or db.defaultStyle)
+  local border = WorldPlan:GetTypeInfo(self.rewardType)
+  print(self.rewardType, print)
   iconBorder:SetVertexColor(border.r, border.g, border.b, border.a)
   iconBorder:SetDesaturated(true)
 
@@ -314,9 +468,9 @@
 
 
   if self.isElite then
-    self.EliteDecal:Show()
+    self.EliteBorder:Show()
   else
-    self.EliteDecal:Hide()
+    self.EliteBorder:Hide()
   end
   qprint('|cFF88FF00updated', questID, self.title, self.rewardType, (style.showNumber and self.itemNumber) or '')
 
--- a/WorldPlan.lua	Thu Oct 27 06:19:05 2016 -0400
+++ b/WorldPlan.lua	Thu Oct 27 13:50:56 2016 -0400
@@ -10,7 +10,20 @@
  Dalaran quests aren't visible until that map has been specifically viewed by the player.
 --]]
 
-WorldPlanCore = {}
+local ICON_UNKNOWN = "Interface\\ICONS\\inv_misc_questionmark"
+local ICON_MONEY = "Interface\\Buttons\\UI-GroupLoot-Coin-Up"
+
+local POI_BORDER_MASK = "Interface\\Minimap\\UI-Minimap-Background"
+local POI_BORDER_FILL = "Interface\\BUTTONS\\YELLOWORANGE64"
+local POI_BORDER_BLUE = "Interface\\BUTTONS\\GRADBLUE"
+local POI_BORDER_RED = "Interface\\BUTTONS\\RedGrad64"
+local POI_BORDER_YELLOW = "Interface\\BUTTONS\\YELLOWORANGE64"
+local POI_BORDER_GREEN = "Interface\\BUTTONS\\GREENGRAD64"
+
+WorldPlanCore = {
+  defaults = {},
+
+}
 WorldPlanPOIMixin = {}
 WorldPlanFilterPinMixin = {}
 local WorldPlanFlightMapMixin = setmetatable({}, {__tostring = function() return 'FlightMapHandler' end})
@@ -30,11 +43,8 @@
 local fbprint = DEVIAN_WORKSPACE and function(...) _G.print('FilterBar', ...) end or function() end
 
 local wipe, tremove, tinsert, pairs, floor, tContains = table.wipe, table.remove, table.insert, pairs, floor, tContains
-local TQ_GetQuestInfoByQuestID = C_TaskQuest.GetQuestInfoByQuestID -- Return the name of a quest with a given ID
 local TQ_GetQuestsForPlayerByMapID = C_TaskQuest.GetQuestsForPlayerByMapID -- This function is not yet documented
-local TQ_GetQuestTimeLeftMinutes = C_TaskQuest.GetQuestTimeLeftMinutes
-local TQ_RequestPreloadRewardData = C_TaskQuest.RequestPreloadRewardData
-local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation
+local TQ_GetQuestZoneID = C_TaskQuest.GetQuestZoneID
 local TQ_IsActive = C_TaskQuest.IsActive
 local ITEM_QUALITY_COLORS = ITEM_QUALITY_COLORS
 local WorldMap_DoesWorldQuestInfoPassFilters = WorldMap_DoesWorldQuestInfoPassFilters
@@ -63,25 +73,7 @@
 local ARTIFACT_COLOR = ITEM_QUALITY_COLORS[LE_ITEM_QUALITY_ARTIFACT]
 local MONEY_COLOR = {hex ='|cFFFFFF00', r=1, g=1, b=0}
 local COMMON_COLOR = ITEM_QUALITY_COLORS[LE_ITEM_QUALITY_COMMON]
-
-local ICON_UNKNOWN = "Interface\\ICONS\\inv_misc_questionmark"
-local ICON_MONEY = "Interface\\Buttons\\UI-GroupLoot-Coin-Up"
-
-local POI_BORDER_MASK = "Interface\\Minimap\\UI-Minimap-Background"
-local POI_BORDER_FILL = "Interface\\BUTTONS\\YELLOWORANGE64"
-local POI_BORDER_BLUE = "Interface\\BUTTONS\\GRADBLUE"
-local POI_BORDER_RED = "Interface\\BUTTONS\\RedGrad64"
-local POI_BORDER_YELLOW = "Interface\\BUTTONS\\YELLOWORANGE64"
-local POI_BORDER_GREEN = "Interface\\BUTTONS\\GREENGRAD64"
-
-local REWARD_CASH = 1001
-local REWARD_ARTIFACT_POWER = 1002
-local REWARD_GEAR = 1003
-local REWARD_CURRENCY = 1004
-local REWARD_ITEM = 1005
-local REWARD_REAGENT = 1006
-
-local POI_DEFAULT_TYPE = {
+local DEFAULT_TYPE = {
   a = 1,
   r = 1, g = 1, b = 1,
   x = 0, y = 0,
@@ -114,53 +106,12 @@
     showNumber = false,
   }
 }
-local POI_REWARD_TYPE =  setmetatable({}, {
-  __newindex = function(t, k, v)
-    if type(v) == 'table' then
-      setmetatable(v, {__index = POI_DEFAULT_TYPE})
-    end
-    rawset(t,k,v)
-  end
-})
+
+
 local POI_FILTER_STYLE = setmetatable({
   continentBorder = 2,
   zoneBorder = 2,
-}, {__index = POI_DEFAULT_TYPE})
-
-local LE_QUEST_TAG_TYPE_PVP = LE_QUEST_TAG_TYPE_PVP
-local LE_QUEST_TAG_TYPE_PET_BATTLE = LE_QUEST_TAG_TYPE_PET_BATTLE
-local LE_QUEST_TAG_TYPE_DUNGEON = LE_QUEST_TAG_TYPE_DUNGEON
-local LE_QUEST_TAG_TYPE_PROFESSION = LE_QUEST_TAG_TYPE_PROFESSION
-local LE_QUEST_TAG_TYPE_NORMAL = LE_QUEST_TAG_TYPE_NORMAL
-
--- Pin color/display variables
-POI_REWARD_TYPE[REWARD_ITEM] = {
-  r = 1, g = 1, b = 1,
-}
-POI_REWARD_TYPE[REWARD_REAGENT] = {
-  r = 0, g = 1, b = 1,
-}
-POI_REWARD_TYPE[REWARD_ARTIFACT_POWER] = {
-  r = 1, g = .25, b = .5,
-  hasNumeric = true,
-  numberRGB = {1, 1, 1},
-}
-POI_REWARD_TYPE[REWARD_GEAR] = {
-  r = .1, g = .2, b = 1,
-}
-POI_REWARD_TYPE[REWARD_CURRENCY] = {
-  r = 1, g = 1, b = 0,
-  hasNumeric = true,
-  numberRGB = {1, 1, 1},
-}
-POI_REWARD_TYPE[REWARD_CASH] = {
-  r = 0, g = 0, b = 0,
-  --x = 0, y = -1,
-  --mask = ICON_MONEY,
-  --continentBorder = 1,
-  --zoneBorder = 1,
-}
-
+}, {__index = DEFAULT_TYPE})
 
 
 local defaults = {
@@ -176,14 +127,26 @@
 }
 
 -- Summary header structure
+
+local REWARD_CASH = WORLD_QUEST_REWARD_TYPE_FLAG_GOLD
+local REWARD_ARTIFACT_POWER = WORLD_QUEST_REWARD_TYPE_FLAG_ARTIFACT_POWER
+local REWARD_GEAR = WORLD_QUEST_REWARD_TYPE_FLAG_EQUIPMENT
+local REWARD_CURRENCY = WORLD_QUEST_REWARD_TYPE_FLAG_ORDER_RESOURCES
+local REWARD_REAGENT = WORLD_QUEST_REWARD_TYPE_FLAG_MATERIALS
+
+
+local LE_QUEST_TAG_TYPE_PVP = LE_QUEST_TAG_TYPE_PVP
+local LE_QUEST_TAG_TYPE_PET_BATTLE = LE_QUEST_TAG_TYPE_PET_BATTLE
+local LE_QUEST_TAG_TYPE_DUNGEON = LE_QUEST_TAG_TYPE_DUNGEON
+local LE_QUEST_TAG_TYPE_PROFESSION = LE_QUEST_TAG_TYPE_PROFESSION
+local LE_QUEST_TAG_TYPE_NORMAL = LE_QUEST_TAG_TYPE_NORMAL
 local POI_FILTER_OPTIONS = {
   { label = 'Filters', texture = "Interface\\WorldMap\\WorldMap-Icon" },
   { filterKey= 'rewardType', filterValue = REWARD_ARTIFACT_POWER, label = 'Artifact Power', texture = "Interface\\ICONS\\inv_7xp_inscription_talenttome01" },
-  { filterKey= 'rewardType', filterValue = REWARD_CURRENCY,label = 'Currency', texture = "Interface\\ICONS\\inv_misc_elvencoins" },
-  { filterKey= 'rewardType', filterValue = REWARD_ITEM, label = 'Item', texture = "Interface\\ICONS\\inv_crate_01" },
+  { filterKey= 'rewardType', filterValue = REWARD_CURRENCY,label = 'Order Resources', texture = "Interface\\ICONS\\inv_misc_elvencoins" },
   { filterKey= 'rewardType', filterValue = REWARD_GEAR, label = 'Equipment', texture = "Interface\\ICONS\\garrison_bluearmorupgrade" },
-  { filterKey= 'rewardType', filterValue = REWARD_REAGENT, label = 'Reagents', texture = 1417744 },
-  { filterKey= 'rewardType', filterValue = REWARD_CASH, label = 'Reagents', texture = ICON_MONEY },
+  { filterKey= 'rewardType', filterValue = REWARD_REAGENT, label = 'Materials', texture = 1417744 },
+  { filterKey= 'rewardType', filterValue = REWARD_CASH, label = 'Gold', texture = ICON_MONEY },
   { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PVP, label = 'PvP', texture = "Interface\\Icons\\Ability_PVP_GladiatorMedallion", spacing = 10 },
   { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PET_BATTLE, label = 'Pet Battle', texture = "Interface\\Icons\\PetJournalPortrait", },
   { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_DUNGEON, label = 'Dungeon', texture = "Interface\\LFGFRAME\\UI-LFR-PORTRAIT", },
@@ -250,55 +213,6 @@
   return frame
 end
 
--- use tooltip object to extract item details
-local ParseItemReward = function(questID)
-  local rewardType = REWARD_ITEM
-  local name, icon, quantity, quality, _, itemID = GetQuestLogRewardInfo(1, questID)
-  if not itemID then
-    return REWARD_ITEM
-  end
-
-  scanner:SetOwner(WorldPlan, "ANCHOR_NONE")
-  scanner:SetItemByID(itemID)
-  local ttl1 = _G['WorldPlanTooltipTextLeft1']
-  local ttl2 = _G['WorldPlanTooltipTextLeft2']
-  local ttl3 = _G['WorldPlanTooltipTextLeft3']
-  local ttl4 = _G['WorldPlanTooltipTextLeft4']
-  if ttl2 then
-    local text = ttl2:GetText()
-    -- Artifact Power
-    if text and text:match("|cFFE6CC80") then
-      --print('AP token!', text)
-      local power
-      if ttl4 then
-        local text = ttl4:GetText()
-        --print('tip line 4', text)
-        if text then
-          power = text:gsub("%p", ""):match("%d+")
-          power = tonumber(power)
-        end
-
-      end
-      rewardType = REWARD_ARTIFACT_POWER
-      icon = "Interface\\ICONS\\inv_7xp_inscription_talenttome01"
-      quantity = power
-    elseif text and text:match("Item Level") then
-      --print('equipment!', text)
-      rewardType = REWARD_GEAR
-      quantity = text:match("Item Level ([%d\+]+)")
-    end
-  end
-  if ttl3 then
-    local text = ttl3:GetText()
-    -- Crafting Reagent
-    if text and text:match("Crafting Reagent") then
-      --print('reagent', text)
-      rewardType = REWARD_REAGENT
-    end
-  end
-  iprint('  item:', name, rewardType, icon, quantity)
-  return rewardType, icon, quantity, name, itemID
-end
 
 -- update a masked texture without messing up its blending mask
 local SetMaskedTexture = function(region, file, mask)
@@ -330,6 +244,31 @@
 end
 
 function WorldPlan:OnLoad ()
+
+  self.Types = setmetatable({}, {
+    __newindex = function(t, k, v)
+      print('adding type', k)
+      if type(v) == 'table' then
+        v = setmetatable(v, {__index = function(t,k)
+          print('##deferring to default key', k)
+          return  DEFAULT_TYPE[k]
+        end})
+      end
+      rawset(t,k,v)
+    end
+  })
+
+  local rgbWhite = {1, 1, 1}
+  self.Types[REWARD_REAGENT] = { r = 0, g = 1, b = 1 }
+  self.Types[REWARD_ARTIFACT_POWER] = { r = 1, g = .25, b = .5, hasNumeric = true, numberRGB = rgbWhite }
+  self.Types[REWARD_GEAR] = { r = .1, g = .2, b = 1 }
+  self.Types[REWARD_CURRENCY] = { r = 1, g = 1, b = 0, hasNumeric = true, numberRGB = rgbWhite, }
+  self.Types[REWARD_CASH] = { r = 0, g = 0, b = 0, }
+
+  for index, color in pairs(ITEM_QUALITY_COLORS) do
+    self.Types[(index+127)] = { r = color.r, g = color.g, b = color.b, hex = color.hex, }
+  end
+
   WorldPlan = self
   scanner = _G.WorldPlanTooltip
   wmtt = _G.WorldMapTooltip
@@ -421,6 +360,59 @@
   hooksecurefunc("UIDropDownMenu_Initialize", self.OnDropDownInitialize)
 end
 
+function WorldPlan:GetTypeInfo(typeID)
+  local info, extraInfo
+  if (not typeID) or (not self.Types[typeID]) then
+    qprint('## sent default type')
+    info = DEFAULT_TYPE
+  else
+    qprint('## sent defined type', typeID)
+    info = self.Types[typeID]
+  end
+
+  if isContinentMap then
+    extraInfo = info.continent
+    qprint('### continent subtype', extraInfo)
+  else
+    extraInfo = info.zone
+
+    qprint('### zone subtype', extraInfo)
+  end
+  return info, extraInfo
+end
+
+do
+  local timeStates = {
+    {maxSeconds = 60,
+      r=1, g=0.25, b =0, format = function (minutes) return '|cFFFF4400'.. minutes .. 'm' end,
+    },
+    {maxSeconds = 240,
+      r=1, g=.5, b=0, format = function(minutes) return '|cFFFF4400'.. floor(minutes/60) .. 'h' end,
+    },
+    {maxSeconds = 1440,
+      r=1, g=1, b=0, format = function(minutes) return '|cFFFFFF00'.. floor(minutes/60) .. 'h' end,
+    },
+    {maxSeconds = 10081,
+      r=0, g=1, b=0,
+    }, -- 7 days + 1 minute
+  }
+  -- Generates a timeleft string
+  function WorldPlan:GetTimeInfo(timeLeft, limit)
+    limit = limit or #timeStates
+    for index = 1, limit do
+      local state = timeStates[index]
+      if timeLeft <= state.maxSeconds then
+        local text
+        if state.format then
+          text = state.format(timeLeft)
+        end
+        return text, index
+      end
+    end
+    return nil, nil
+  end
+end
+
 function WorldPlan:RefreshAll (forced)
   if not self.initialized then
     return
@@ -526,6 +518,13 @@
 end
 
 function WorldQuests:Setup()
+
+
+  for mapID, mapName in pairs(WORLD_QUEST_MAPS) do
+    QuestsByZone[mapID] = {}
+  end
+
+
   -- refresh positions any time blizzard does so (i.e. mousewheel zoom)
   hooksecurefunc("WorldMapScrollFrame_ReanchorQuestPOIs", function()
     self:Refresh(true)
@@ -548,9 +547,10 @@
   if event == 'QUEST_LOG_UPDATE' then
     local questID, added = ...
     if questID and added then
-      self:GetPinByQuestID(questID)
+      local questPOI = self:AcquirePin(questID)
+      self.hasUpdate, self.isPending = questPOI:RefreshData()
     else
-      self:GetPinsForMap()
+      self:RefreshData()
     end
       print('WorldMapFrame', WorldMapFrame:IsVisible(), 'doRefresh:', hasNewQuestPins)
     if WorldMapFrame:IsVisible() and hasNewQuestPins then
@@ -566,8 +566,8 @@
     self:Refresh(true)
   end
 end
-
-function WorldQuests:AcquirePin (questID, pinTable)
+local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation
+function WorldQuests:AcquirePin (questID, mapID)
   local pin = QuestsByID[questID]
   local isNew = false
   if not pin then
@@ -580,14 +580,12 @@
       local name = 'WorldPlanQuestMarker' .. NumPinFrames
       --print('|cFF00FF00Creating', name)
       pin = CreateFrame('Frame', name, WorldMapPOIFrame, 'WorldPlanQuestPin')
+
       pin:SetFrameStrata('HIGH')
-
       NumPinFrames = NumPinFrames + 1
-
       --pin.iconBorder:SetVertexColor(0,0,0,1)
-
     end
-    QuestsByID[questID] = pin
+    pin:SetID(questID)
     pin.isNew = true
     pin.currentWidth = nil
 
@@ -595,21 +593,13 @@
     pin.questID = questID
     pin.worldQuest = true
 
-    pin.Reset = function(self)
-      WorldQuests:GetPinByQuestID(questID)
-    end
+    QuestsByID[questID] = pin
   else
     --print('|cFF00FF00Using', pin:GetName())
   end
+  mapID = mapID or TQ_GetQuestZoneID(questID)
+  QuestsByZone[mapID][questID] = pin
 
-  -- set display flags accordingly
-  if pinTable then
-    for k,v in pairs(pinTable) do
-      pin[k] = v
-    end
-  end
-  pin.throttle = nil
-  pin.timeThreschold = nil
   return pin, isNew
 end
 
@@ -634,7 +624,7 @@
 end
 
 -- create of update quest pins for a map and its underlying zones
-function WorldQuests:GetPinsForMap (mapID)
+function WorldQuests:RefreshData (mapID)
   local print = wqprint
   mapID = mapID or GetCurrentMapAreaID()
   superTrackedID = GetSuperTrackedQuestID()
@@ -643,12 +633,12 @@
     return
   end
   if mapID == BROKEN_ISLES_ID then
-    hasPendingQuestData = nil
+    self.hasUpdate = false
     print('|cFF00FFFFRefreshQuestsForMap|r', mapID, GetMapNameByID(mapID), superTrackedID)
     self.fullSearch = true
     for i = 1, MC_GetNumZones(mapID) do
       local submapID, name, depth = MC_GetZoneInfo(mapID, i)
-      self:GetPinsForMap(submapID)
+      self:RefreshData(submapID)
     end
     self.fullSearch = nil
   elseif QuestsByZone[mapID] then
@@ -660,122 +650,25 @@
       wipe(QuestsByZone[mapID])
       ZoneInfo[mapID] = taskInfo
       for taskID, info in pairs(taskInfo) do
+        print('-', taskID)
         local questID = info.questId
-
         info.mapID = mapID
-        QuestsByZone[mapID][questID] = self:GetPinByQuestID(questID, info)
+        local questPOI = self:AcquirePin(questID, mapID)
+        local hasUpdate, isPending = questPOI:RefreshData(taskInfo)
+        self.hasUpdate = (self.hasUpdate or hasUpdate)
+        self.isPending = (self.isPending or isPending)
         numQuests = numQuests + 1
       end
     end
   end
-end
 
--- create or update the pin using the given questID and C_TaskQuest results
-function WorldQuests:GetPinByQuestID (questID, taskInfo)
-
-    local questTitle, rewardIcon, rewardName, rewardCount, rewardStyle, rewardType, itemID, quantity, quality, _
-    local pin = self:AcquirePin(questID, taskInfo)
-
-    if pin.isNew then
-      if not hasNewQuestPins then
-        print('triggering new quest pins event')
-      end
-
-      hasNewQuestPins = true
-    end
-
-    if not HaveQuestData(questID) then
-      print('|cFFFF4400Retrieval failed.')
-      TQ_RequestPreloadRewardData(questID)
-      hasPendingQuestData = true
-    else
-      wqprint('|cFF00FF88Quest Data Received|r')
-      pin.mapID = pin.mapID or C_TaskQuest.GetQuestZoneID(questID)
-
-      -- set reward category
-      local numRewards = GetNumQuestLogRewards(questID)
-      local numCurrency = GetNumQuestLogRewardCurrencies(questID)
-      local money = GetQuestLogRewardMoney(questID)
-      if numRewards >= 1 then
-        rewardType, rewardIcon, rewardCount, rewardName, itemID = ParseItemReward(questID)
-      elseif numCurrency >= 1 then
-        rewardName, rewardIcon, rewardCount = GetQuestLogRewardCurrencyInfo(1, questID)
-        rewardType = REWARD_CURRENCY
-      elseif money >= 1 then
-        rewardIcon = ICON_MONEY
-        rewardName = GetMoneyString(money)
-        rewardType = REWARD_CASH
-      end
-      rewardStyle = POI_REWARD_TYPE[rewardType] or POI_DEFAULT_TYPE
-
-      pin.itemNumber = rewardCount or pin.itemNumber
-      pin.rewardType = rewardType or REWARD_ITEM
-      pin.style = rewardStyle
-      QuestsByID[questID] = pin
-
-      -- title, faction, capped state
-      local questTitle, factionID, capped = TQ_GetQuestInfoByQuestID(questID)
-      if factionID then
-        QuestsByFaction[factionID] = QuestsByFaction[factionID] or {}
-        QuestsByFaction[factionID][questID] = pin
-      end
-      pin.factionID = factionID
-      pin.capped = capped
-
-      -- set tag details
-      local tagID, tagName, worldQuestType, rarity, isElite, tradeskillLineIndex = GetQuestTagInfo(questID);
-      local tagAtlas
-      if worldQuestType == LE_QUEST_TAG_TYPE_PET_BATTLE then
-        tagAtlas = "worldquest-icon-petbattle"
-      elseif worldQuestType == LE_QUEST_TAG_TYPE_PVP then
-        tagAtlas = "worldquest-icon-pvp-ffa"
-      elseif worldQuestType == LE_QUEST_TAG_TYPE_PROFESSION then
-        local id = tradeskillLineIndex and select(7, GetProfessionInfo(tradeskillLineIndex))
-        if id then
-          tagAtlas = WORLD_QUEST_ICONS_BY_PROFESSION[id]
-        end
-      elseif worldQuestType == LE_QUEST_TAG_TYPE_DUNGEON then
-        tagAtlas = "worldquest-icon-dungeon"
-      end
-
-      pin.tagID = tagID
-      pin.tagName = tagName
-      pin.worldQuestType = worldQuestType
-      pin.isElite = isElite
-      pin.tradeskillLineIndex = tradeskillLineIndex
-      pin.rarity = rarity
-      pin.tagAtlas = tagAtlas
-
-    -- flag unresolved info
-    if not (rewardIcon and rewardName) then
-      if not pin.isPending then
-        pin.isPending = true
-        TQ_RequestPreloadRewardData (questID)
-        pin.rewardType = pin.rewardType or REWARD_ITEM
-        pin.style = pin.style or POI_REWARD_TYPE[REWARD_ITEM]
-
-        if not hasPendingQuestData then
-          hasPendingQuestData = true
-          PlaySoundKitID(229)
-        end
-        --WorldPlan:print('|cFFFFFF00'..tostring(pin.title)..'|r waiting on texture info')
-      end
-    else
-      if (rewardIcon and rewardName) then
-        --WorldPlan:print('|cFF00FF00'..tostring(pin.title)..'|r has info', rewardIcon, rewardName)
-        pin.hasUpdate = true
-      end
-      pin.isPending = nil
-    end
-
-    pin.title = questTitle or "|cFFFF0000Retrieving..."
-    pin.itemTexture = rewardIcon or pin.itemTexture
-    pin.itemName = rewardName or pin.itemName
-
-    qprint('  |cFF00FFFF'..questID..'|r:->', (HaveQuestData(questID) and "|cFF00FF00HaveQuestData" or "-"), (C_TaskQuest.IsActive(questID) and "|cFF88FF00IsActive|r" or ""))
-    qprint(' ', pin.title, pin.itemTexture, 'rewardType:', pin.rewardType, 'tag:', pin.tagID, 'style', pin.style )
+  print('  hasUpdate:', self.hasUpdate, 'isPending:', self.isPending, 'timer:', self.OnNext)
+  if self.hasUpdate then
+    self.OnNext = self.OnNext or C_Timer.NewTimer(0.25, function()
+      self:Refresh(true)
+      self.OnNext = nil
+    end)
   end
-  return QuestsByID[questID]
 end
 
 function WorldQuests:Refresh(forced)
@@ -1171,6 +1064,7 @@
       local button = blocks[numHeaders]
       if not blocks[numHeaders] then
         button = CreateFrame('Button', 'WorldPlanFilterButton'..numHeaders, WorldMapScrollFrame, 'WorldPlanFilterPin')
+        for k,v in pairs(info)do print(k,v) end
         button.iconBorder:SetTexture(info.fill or POI_BORDER_FILL)
         button.iconBorder:SetMask(info.mask or POI_BORDER_MASK)
         button.iconBorder:SetDesaturated(info.desaturated)
@@ -1220,7 +1114,7 @@
     self.icon:SetTexture(info.texture)
     self.icon:SetAllPoints(self)
     self.supertrackBorder:Hide()
-    self.label:SetText(numQuests)
+    self.count:SetText(numQuests)
     self:Show()
   end
 
@@ -1325,13 +1219,3 @@
   SetTimedCallbackForAllPins(8, function(self) self.PendingFade:Stop() end)
 end
 --%end-debug%
-
-for mapID, mapName in pairs(WORLD_QUEST_MAPS) do
-  QuestsByZone[mapID] = {}
-end
-for index, color in pairs(ITEM_QUALITY_COLORS) do
-  POI_REWARD_TYPE[index] = {
-    r = color.r, g = color.g, b = color.b,
-    hex = color.hex,
-  }
-end
--- a/WorldPlan.xml	Thu Oct 27 06:19:05 2016 -0400
+++ b/WorldPlan.xml	Thu Oct 27 13:50:56 2016 -0400
@@ -6,6 +6,7 @@
 
   <Font name="WorldPlanFont" font="Interface\AddOns\WorldPlan\Font\ArchivoNarrow-Bold.ttf" height="13" outline="NORMAL" virtual="true" />
   <Font name="WorldPlanNumberFont" font="Interface\AddOns\WorldPlan\Font\ArchivoNarrow-Bold.ttf" height="10" outline="NORMAL" virtual="true" />
+  <Font name="WorldPlanNumberFontThin" font="Interface\AddOns\WorldPlan\Font\ArchivoNarrow-Regular.ttf" height="13" outline="THICK" virtual="true" />
 
   <GameTooltip name="WorldPlanTooltip" parent="UIParent" inherits="GameTooltipTemplate">
 
@@ -77,8 +78,8 @@
             <Anchor point="BOTTOMLEFT" x="-14" y="-14" />
           </Anchors>
         </Texture>
-        <Texture parentKey="supertrackBorder" file="Interface\BUTTONS\GREENGRAD64" desaturated="true" />
-        <Texture parentKey="EliteDecal" atlas="worldquest-questmarker-dragon" hidden="true">
+        <Texture parentKey="supertrackBorder" desaturated="true" />
+        <Texture parentKey="EliteBorder" atlas="worldquest-questmarker-dragon" hidden="true">
           <Anchors>
             <Anchor point="TOPLEFT" relativeKey="$parent.iconBorder" x="-6" y="6"/>
             <Anchor point="BOTTOMRIGHT" relativeKey="$parent.iconBorder" x="6" y="-6"/>
@@ -86,14 +87,9 @@
         </Texture>
       </Layer>
       <Layer level="OVERLAY">
-        <FontString inherits="GameFontNormal" parentKey="count">
+        <FontString inherits="WorldPlanNumberFontThin" parentKey="count">
           <Anchors>
-            <Anchor point="BOTTOMRIGHT" relativeKey="$parent.icon" x="0" y="0" />
-          </Anchors>
-        </FontString>
-        <FontString inherits="WorldPlanFont" parentKey="label">
-          <Anchors>
-            <Anchor point="BOTTOM" x="0" y="0" />
+            <Anchor point="BOTTOM" relativeKey="$parent.icon" x="0" y="0" />
           </Anchors>
         </FontString>
         <FontString inherits="WorldPlanNumberFont" parentKey="timeLabel">
@@ -116,23 +112,12 @@
           </Anchors>
         </Texture>
 
+      </Layer>
+      <Layer level="HIGHLIGHT">
         <Texture parentKey="highlight" setAllPoints="true" alphaMode="ADD" alpha="0" file="Interface\Tooltips\UI-Tooltip-Background" desaturated="true" />
 
       </Layer>
     </Layers>
-    <Frames>
-      <Cooldown parentKey="Swipe" hideCountdownNumbers="true" hidden="true">
-        <Anchors>
-          <Anchor point="CENTER" />
-        </Anchors>
-        <SwipeTexture file="Interface\Garrison\GarrLanding-TradeskillTimerFill" setAllPoints="true" />
-        <Layers>
-          <Layer level="BACKGROUND">
-            <Texture parentKey="bg" setAllPoints="true" atlas="GarrLanding-TradeskillTimer-Border"  alpha="1"/>
-          </Layer>
-        </Layers>
-      </Cooldown>
-    </Frames>
     <Scripts>
       <OnLoad method="OnLoad" />
       <OnEvent method="OnEvent" />