view Modules/ArtifactPower.lua @ 98:dadddb8a551f

- bag scan intervals - progress visualization - artifact xp updates
author Nenue
date Tue, 17 Jan 2017 09:49:15 -0500
parents 5476337198ec
children 74d6d97a2d24
line wrap: on
line source
-- Veneer
-- ArtifactPower.lua
-- Created: 1/15/2017 11:44 PM
-- %file-revision%
--

local print = DEVIAN_WORKSPACE and function(...) print('VnAP', ...) end or nop
VeneerArtifactPowerMixin = {

  anchorPoint = 'TOP',
  anchorFrom = 'TOP',
}
local ap = VeneerArtifactPowerMixin
local BAGS_TO_SCAN = {BACKPACK_CONTAINER }
local TOOLTIP_NAME = 'VeneerAPScanner'
local POINT_COSTS = {
  100, 300, 325, 350, 375,
  400, 425, 450, 525, 625,
  750, 875, 1000, 6840, 8830,
  11280, 14400, 18620, 24000, 30600,
  39520, 50880, 64800, 82500, 105280,
  138650, 182780, 240870, 325520, 417560,
  546000, 718200, 946660, 1245840, 1635200,
  191500, 2010000, 2110000, 2215000, 2325000,
  2440000, 2560000, 2690000, 2825000, 2965000,
  3115000, 3270000, 3435000, 3605000, 3785000,
  3975000, 4175000, 4385000, 4605000
}

function ap:OnLoad()
  self:RegisterEvent('BAG_UPDATE') -- use to obtain bag IDs to scan
  self:RegisterEvent('BAG_UPDATE_DELAYED') -- use to trigger actual scan activity
  self:RegisterEvent('BANKFRAME_OPENED')  -- determine when bank info is available
  self:RegisterEvent('BANKFRAME_CLOSED')  -- " " "
  self:RegisterEvent('ARTIFACT_UPDATE')    -- when artifact data has changed
  self:RegisterEvent('ARTIFACT_XP_UPDATE') -- when artifact xp has changed (but not necessarily data)
  self:RegisterEvent('MODIFIER_STATE_CHANGED')
  self:RegisterEvent('PLAYER_REGEN_ENABLED')
  self:RegisterEvent('PLAYER_REGEN_DISABLED')
  Veneer:AddHandler(self, self.anchorPoint, true)
  SLASH_VENEER_AP1 = "/vap"
  SLASH_VENEER_AP2 = "/veneerap"
  SlashCmdList.VENEER_AP = function(arg)
    if arg == 'fishing' then
      if VeneerData.ArtifactPower.EnableFishing then
        VeneerData.ArtifactPower.EnableFishing = nil
      else
        VeneerData.ArtifactPower.EnableFishing = true
      end
      self:Print('Show Underlight Angler:', (VeneerData.ArtifactPower.EnableFishing and 'ON' or 'OFF'))
      self:Update()

    else
      self:Show()
    end
  end

  self.tooltip = CreateFrame('GameTooltip', TOOLTIP_NAME, self, 'GameTooltipTemplate')

end

local defaultSettings = {
}

function ap:Setup()
  print(self:GetName()..':Setup()')
  local guid = UnitGUID('player')
  VeneerData.ArtifactPower = VeneerData.ArtifactPower or defaultSettings
  VeneerData.ArtifactPower[guid] = VeneerData.ArtifactPower[guid] or {}
  self.profile = VeneerData.ArtifactPower[guid]
  self.profile.bagslots = self.profile.bagslots or {}
  self.profile.artifacts = self.profile.artifacts or {}
  self.updateSummary = true

  -- Bagnon compatibility
  -- todo: ArkInventory, Elv, etc
  if IsAddOnLoaded('Bagnon') then
    local oToggleAllBags = ToggleAllBags
    ToggleAllBags =  function()
      print('|cFFFF0088ToggleAllBags')
      oToggleAllBags()
      if BagnonFrameinventory:IsShown() then
        self:Show()
      else
        self.enabled = nil
        self:Hide()
      end
    end
  else
    hooksecurefunc("OpenBackpack", function()
      self:Show()
    end)
    hooksecurefunc("CloseBackpack", function()
      self.enabled = nil
      self:Hide()
    end)
  end


end
local UNDERLIGHT_ANGLER_ID = 133755
function ap:SetArtifact(itemID, name, texture, currentXP, pointsSpent)
  print('|cFF00FF00SetArtifact()|r')
  if not self.profile then
    return
  end
  local artifacts = self.profile.artifacts


  if itemID then
    artifacts[itemID] = artifacts[itemID] or {}
    table.wipe(artifacts[itemID])
    local artifact = artifacts[itemID]

    artifact.name = name
    artifact.texture = texture
    artifact.currentXP = currentXP
    artifact.level = pointsSpent
    local cost = C_ArtifactUI.GetCostForPointAtRank(pointsSpent)
    artifact.cost = cost

    local pointsAvailable = pointsSpent
    local actualCost = cost
    local actualXP = currentXP
    while actualXP >= actualCost do
      pointsAvailable = pointsAvailable + 1
      actualXP = actualXP - actualCost
      print(pointsAvailable, '-', actualCost, '=', actualXP)
      actualCost = C_ArtifactUI.GetCostForPointAtRank(pointsAvailable)
    end
    print('updating', itemID, name,  currentXP, pointsSpent, pointsAvailable, actualXP)
    artifact.actualXP = actualXP
    artifact.actualLevel = pointsAvailable
    artifact.actualCost = actualCost

  end
end
function ap:QueueBag(containerID)
  containerID = tonumber(containerID)
  if not containerID then
    return
  end

  if not tContains(BAGS_TO_SCAN, containerID) then
    print(' queueing', containerID, type(containerID), #BAGS_TO_SCAN , 'in line')
    BAGS_TO_SCAN[#BAGS_TO_SCAN + 1] = containerID
  end
end

function ap:OnShow()
  self.enabled = true
  self:Update()
  Veneer:DynamicReanchor()
end
function ap:OnHide()
  Veneer:DynamicReanchor()
end

function ap:OnEnter()

  GameTooltip:SetOwner(self, 'ANCHOR_CURSOR')

  GameTooltip:AddLine(self.bagAP)
  GameTooltip:AddLine(self.bankAP)

end

function ap:OnEvent(event, ...)
  print(self:GetName()..':OnEvent()', event, ...)
  if event == 'BAG_UPDATE' then
    local containerID = ...
    self:QueueBag(containerID)
  elseif event == 'PLAYER_BANKSLOTS_CHANGED' then
    self:ScanAllBags(true)
    self:Update()
  elseif event == 'BAG_UPDATE_DELAYED' then
    self:ScanAllBags(self.bankAccess)
  elseif event == 'BANKFRAME_OPENED' then
    self.bankAccess = true
    self:ScanAllBags(true)
  elseif event == 'BANKFRAME_CLOSED' then
    self.bankAccess = false
  elseif event == 'ARTIFACT_UPDATE' then
    local newItem = ...
    if newItem then
      local itemID, _, name, texture, currentXP, pointsSpent = C_ArtifactUI:GetArtifactInfo()
      self:SetArtifact(itemID, name, texture, currentXP, pointsSpent)
      self:ScanAllBags(self.bankAccess)
    end
  elseif event == 'ARTIFACT_XP_UPDATE' then
    local itemID, _, name, texture, currentXP, pointsSpent = C_ArtifactUI:GetEquippedArtifactInfo()
    self:SetArtifact(itemID, name, texture, currentXP, pointsSpent)
    self:ScanAllBags(self.bankAccess)
  elseif event == 'PLAYER_REGEN_ENABLED' then
    if self.enabled then
      self:Show()
    end

  elseif event == 'PLAYER_REGEN_DISABLED' then
    self:Hide()
  end
end

function ap:OnMouseDown()
  self.enabled = nil
  self:Hide()
end

function ap:Update()
  if not self:IsShown() then
    return
  end
  print('|cFF00FFFFUpdate()|r')

  local bankText, bagText
  if not (self.bankAP and self.bagAP) then
    bankText = '|cFFFF0000Open bank frame to count all AP|r '
  else
    if (self.bagAP + self.bankAP) == 0 then
      bankText = '|cFF00FFFFNo Items|r'
    else
      if self.bagAP and (self.bagAP > 0) then
        bankText = '|cFFFFFFFF' .. tostring(self.bagAP) .. '|r'
      end
      if self.bankAP and (self.bankAP > 0) then
        bankText = (bankText and (bankText .. ' | ') or '') .. '|cFFFFFF00'..tostring(self.bankAP)..'|r'
      end
    end
  end
  self.SummaryHeader:SetText(bankText)

  -- Artifact icons, in no particular order
  local equippedID = C_ArtifactUI.GetEquippedArtifactInfo()
  local numButtons = 0
  local lastFrame
  local fishingRod, fishingID, fishingData
  local index, button
  for itemID, artifact in pairs(self.profile.artifacts) do
    local isFishingRod = (itemID == UNDERLIGHT_ANGLER_ID)
    if isFishingRod  then
      if VeneerData.ArtifactPower.EnableFishing then
        fishingID = itemID
        fishingData = artifact
      end

    else
      numButtons = numButtons + 1
      button = self.Artifact[numButtons]
      lastFrame = button:SetButton(itemID, artifact, lastFrame)
    end

  end

  if fishingData then
    numButtons = numButtons + 1
    local button = self.Artifact[GetNumSpecializations()+1]
    button:SetButton(fishingID, fishingData, lastFrame)
  end

  for i = numButtons+ (fishingRod and 2 or 1), #self.Artifact do
    print('hide', i)
    self.Artifact[i]:Hide()
  end



  self:SetWidth(64*numButtons + 4 * (numButtons+1))
  self:SetHeight(12 + self.SummaryHeader:GetHeight() + 64)
  self:Reanchor()

end

function ap:ScanBag(id)
  print('|cFF00FFFFScanBag()|r', id, IsBagOpen(id), GetContainerNumSlots(id))
  local numSlots = GetContainerNumSlots(id)
  local requiresUpdate
  if numSlots == 0 then
    return nil
  end


  self.profile.bagslots[id] = self.profile.bagslots[id] or {}
  table.wipe(self.profile.bagslots[id])
  local bagData = self.profile.bagslots[id]
  bagData.totalAP = 0
  for slotID = 1, numSlots do
    local texture, count, locked, quality, readable, lootable, link = GetContainerItemInfo(id, slotID)
    local itemID = GetContainerItemID(id, slotID)

    if link then
      self.tooltip:SetOwner(self, 'ANCHOR_NONE')
      self.tooltip:SetHyperlink(link)
      self.tooltip:Show()
      local numLines = self.tooltip:NumLines()
      if numLines >= 3 then
        local subText = _G[TOOLTIP_NAME .. 'TextLeft2']:GetText()
        if subText and subText:match(ARTIFACT_POWER) then
          for i = 3, numLines do
            local text = _G[TOOLTIP_NAME .. 'TextLeft'.. i]:GetText()
            if text and text:match(ARTIFACT_POWER) then
              text = text:gsub('[,%D]', '')
              print(link, '-', tonumber(text))
              local itemAP = tonumber(text)
              if itemAP then
                requiresUpdate = true
                bagData.numItems = (bagData.numItems or 0) + 1
                bagData.totalAP = (bagData.totalAP or 0) + itemAP
                bagData.items = bagData.items or {}
                if not bagData.items[itemID] then
                  bagData.numUnique = (bagData.numUnique or 0) + 1
                end
                bagData.items[itemID] = (bagData.items[itemAP] or 0) + 1
              end
            end
          end
        end
      end
    end

    if self.profile.artifacts[itemID] then
      print('artfiact weapon', itemID, link, id, slotID)
      self.profile.artifacts[itemID].containerID = id
      self.profile.artifacts[itemID].slotID = slotID
    end

  end

end

local BAG_SLOTS = {0, 1, 2, 3, 4 }
local BANK_SLOTS = {-1, 5, 6,7, 8, 9, 10, 11, 12}

function ap:ScanAllBags(checkBank)
  print('|cFFFF0088ScanAllBags()|r')

  for _, bagID in ipairs(BAG_SLOTS) do
    self:ScanBag(bagID)
  end

  if checkBank then
    for _, bagID in ipairs(BANK_SLOTS) do
      self:ScanBag(bagID)
    end
  end

  self.bankAP = 0
  self.bagAP = 0
  for id, bagData in pairs(self.profile.bagslots) do
    print(id, GetBagName(id), bagData.totalAP)
    id = tonumber(id)
    if bagData.totalAP then
      if (id == BANK_CONTAINER) or (id >= 5) then
        self.bankAP = self.bankAP + bagData.totalAP
      else
        self.bagAP = self.bagAP + bagData.totalAP
      end
    end

  end
  self.lastUpdate = GetTime()
  self:Update()
  self.updateSummary = nil
end

VeneerArtifactButtonMixin = {}

function VeneerArtifactButtonMixin:SetButton(itemID, artifact, lastFrame)
  print(artifact.name, artifact.texture, artifact.currentXP)
  self:SetID(itemID)
  for k,v in pairs(artifact) do
    --print('::',k,v)
    self[k] = v
  end

  -- this can change between artifact parses
  local potentialPoints = self.actualLevel
  local totalAP = (itemID == UNDERLIGHT_ANGLER_ID) and ((self:GetParent().bankAP or 0) + (self:GetParent().bagAP or 0)) or (self.fishingAP or 0)
  local potentialXP = self.actualXP + totalAP
  self.potentialXP = potentialXP
  local potentialCost = C_ArtifactUI.GetCostForPointAtRank(potentialPoints)
  while potentialXP >= potentialCost do
    potentialXP = potentialXP - potentialCost
    potentialPoints = potentialPoints + 1
    print('inc estimate', potentialXP, potentialPoints)
    potentialCost = C_ArtifactUI.GetCostForPointAtRank(potentialPoints)
  end
  self.potentialCost = potentialCost
  self.potentialLevel = potentialPoints
  self.potentialAdjustedXP = potentialXP



  self.isEquipped = (equippedID == itemID)
  self.relativeFrame = lastFrame
  self:Update()
  self:Show()
  return self
end

function VeneerArtifactButtonMixin:Update()

  if self.actualLevel ~= self.level then
    self.Level:SetText(self.actualLevel)
    self.Level:SetTextColor(0,1,0)
    self.CurrentXP:SetText(self.adjustedXP)
    self.CurrentXP:SetTextColor(0,1,0)
  else
    self.Level:SetText(self.level, 1, 1, 1)
    self.Level:SetTextColor(1,1,1)
    self.CurrentXP:SetText(self.currentXP)
    self.CurrentXP:SetTextColor(1,1,0)
  end

  if self.isEquipped then
    self:SetNormalTexture([[Interface\Buttons\ButtonHilight-Square]])
    self:GetNormalTexture():SetBlendMode('ADD')
    self:GetNormalTexture():SetVertexColor(0,1,0)
  else
    self:SetNormalTexture(nil, 'ADD')
  end

  self:ClearAllPoints()
  if self.relativeFrame then
    self:SetPoint('TOPLEFT', self.relativeFrame, 'TOPRIGHT', 4, 0)
  else
    self:SetPoint('TOPLEFT', 4, -4)
  end
  local currentProgress = (self.currentXP < self.cost) and (self.currentXP / self.cost) or 1
  if self.level <= 53 then
    self.CurrentProgress.animateFrom = self.CurrentProgress:GetHeight() or 1
    self.CurrentProgress.animateTo = currentProgress * self:GetHeight()
    self.CurrentProgress:Show()
  else
    self.CurrentProgress:Hide()
  end
  print(currentProgress)
  if self.potentialXP > self.currentXP then
    local projectedProgress = (self.potentialAdjustedXP < self.potentialCost) and (self.potentialAdjustedXP / self.potentialCost) or 1
    print(projectedProgress)
    if (projectedProgress > currentProgress) then
      self.AdjustedProgress:SetPoint('BOTTOM', self.CurrentProgress, 'TOP')
      projectedProgress = projectedProgress - currentProgress
      print(projectedProgress)
    else
      self.AdjustedProgress:SetPoint('BOTTOM', self, 'BOTTOM')
    end
    self.AdjustedProgress.animateFrom = self.AdjustedProgress:GetHeight() or 1
    self.AdjustedProgress.animateTo = projectedProgress * self:GetHeight()

    self.AdjustedProgress:Show()
  else
    self.AdjustedProgress:Hide()
  end

  self.Icon:SetTexture(self.texture)
  self.Name:SetText(self.name)
  self:SetSize(64,64)
end


function VeneerArtifactButtonMixin:AnimateProgress(region)
  local cTime = GetTime()
  if not region.animateStart then
    region.animateStart = cTime
  end
  local progressTo, progressFrom = region.animateTo, region.animateFrom
    local elapsed = cTime - region.animateStart
  if elapsed >= .5 then
    region:SetHeight(progressTo)
    region.animateTo = nil
    region.animateStart = nil
    region.animateFrom = nil
  else
    local progress = elapsed / .5
    local height = (progressFrom + (progressTo - progressFrom) * progress)
    --print(self:GetName(), progressTo, progressFrom, (progressTo - progressFrom), ceil(progress*10)/10, ceil(height))
    region:SetHeight(height)
  end
end

function VeneerArtifactButtonMixin:OnUpdate(sinceLast)
  if self.CurrentProgress.animateTo then
    self:AnimateProgress(self.CurrentProgress)
  end

  if self.AdjustedProgress.animateTo then
    self:AnimateProgress(self.AdjustedProgress)
  end

end

function VeneerArtifactButtonMixin:OnEnter()
  GameTooltip:SetOwner(self, 'ANCHOR_CURSOR')
  GameTooltip:SetText(self.name)
  GameTooltip:AddLine(tostring(self.currentXP) .. ' / '..tostring(self.cost), 1, 1, 0)
  if self.potentialXP > self.currentXP then
    GameTooltip:AddLine(tostring(self.potentialXP) .. ' potential XP', 0, 1, 1)
    if self.adjustedXP ~= self.potentialXP then
      GameTooltip:AddLine(tostring(self.potentialAdjustedXP) .. ' / ' .. tostring(self.potentialAdjustedCost).. ' after spending', 0, 1, 0)
    end
  end
  GameTooltip:Show()
end
function VeneerArtifactButtonMixin:OnLeave()
  if GameTooltip:IsOwned(self) then
    GameTooltip:Hide()
  end
end

function VeneerArtifactButtonMixin:OnClick(button, down)
  if self.isEquipped then
    SocketInventoryItem(16)
  else
    SocketContainerItem(self.containerID, self.slotID)
  end
end