Nenue@97: -- Veneer Nenue@97: -- ArtifactPower.lua Nenue@97: -- Created: 1/15/2017 11:44 PM Nenue@97: -- %file-revision% Nenue@97: -- Nenue@97: Nenue@97: local print = DEVIAN_WORKSPACE and function(...) print('VnAP', ...) end or nop Nenue@97: VeneerArtifactPowerMixin = { Nenue@99: numItems = 0, Nenue@99: Tokens = {}, Nenue@101: cache = {}, Nenue@101: fishingCache = {}, Nenue@101: scanQueue = {}, Nenue@99: ItemButtons = {}, Nenue@97: anchorPoint = 'TOP', Nenue@116: anchorPriority = 3, Nenue@97: anchorFrom = 'TOP', Nenue@115: moduleName = 'Artifactor', Nenue@115: HideCombat = true Nenue@97: } Nenue@101: local defaultSettings = { Nenue@101: firstUse = true, Nenue@101: autoHide = true, Nenue@101: } Nenue@116: local Module = VeneerArtifactPowerMixin Nenue@97: local BAGS_TO_SCAN = {BACKPACK_CONTAINER } Nenue@97: local TOOLTIP_NAME = 'VeneerAPScanner' Nenue@98: local POINT_COSTS = { Nenue@98: 100, 300, 325, 350, 375, Nenue@98: 400, 425, 450, 525, 625, Nenue@98: 750, 875, 1000, 6840, 8830, Nenue@98: 11280, 14400, 18620, 24000, 30600, Nenue@98: 39520, 50880, 64800, 82500, 105280, Nenue@98: 138650, 182780, 240870, 325520, 417560, Nenue@98: 546000, 718200, 946660, 1245840, 1635200, Nenue@98: 191500, 2010000, 2110000, 2215000, 2325000, Nenue@98: 2440000, 2560000, 2690000, 2825000, 2965000, Nenue@98: 3115000, 3270000, 3435000, 3605000, 3785000, Nenue@98: 3975000, 4175000, 4385000, 4605000 Nenue@98: } Nick@111: local FISHING_MAX_TRAITS = 24 Nenue@116: local WEAPON_MAX_TRAITS = 92 Nenue@116: local FRAME_PADDING = 4 Nenue@116: local EQUIPPED_SIZE = 64 Nick@111: local BUTTON_SIZE = 48 Nenue@99: local FRAME_LIST = {'ContainerFrame1', 'BankFrame'} Nenue@99: local BAG_FRAMES = {'ContainerFrame1'} Nenue@99: local BANK_FRAMES = {'BankFrame'} Nenue@99: Nenue@116: function Module:OnLoad() Nenue@97: self:RegisterEvent('BAG_UPDATE') -- use to obtain bag IDs to scan Nenue@97: self:RegisterEvent('BAG_UPDATE_DELAYED') -- use to trigger actual scan activity Nenue@97: self:RegisterEvent('BANKFRAME_OPENED') -- determine when bank info is available Nenue@97: self:RegisterEvent('BANKFRAME_CLOSED') -- " " " Nenue@97: self:RegisterEvent('ARTIFACT_UPDATE') -- when artifact data has changed Nenue@98: self:RegisterEvent('ARTIFACT_XP_UPDATE') -- when artifact xp has changed (but not necessarily data) Nenue@97: self:RegisterEvent('PLAYER_REGEN_ENABLED') Nenue@97: self:RegisterEvent('PLAYER_REGEN_DISABLED') Nenue@99: self:RegisterEvent('PLAYER_ENTERING_WORLD') Nick@108: self:RegisterEvent('ITEM_LOCK_CHANGED') -- use to clear bag slot cache data Nenue@115: Veneer:AddHandler(self) Nenue@97: SLASH_VENEER_AP1 = "/vap" Nenue@97: SLASH_VENEER_AP2 = "/veneerap" Nenue@98: SlashCmdList.VENEER_AP = function(arg) Nenue@98: if arg == 'fishing' then Nenue@98: if VeneerData.ArtifactPower.EnableFishing then Nenue@98: VeneerData.ArtifactPower.EnableFishing = nil Nenue@98: else Nenue@98: VeneerData.ArtifactPower.EnableFishing = true Nenue@98: end Nenue@98: self:Print('Show Underlight Angler:', (VeneerData.ArtifactPower.EnableFishing and 'ON' or 'OFF')) Nenue@98: self:Update() Nick@108: elseif arg == 'reset' then Nick@108: if self.db then Nick@108: table.wipe(self.db.cache) Nick@108: table.wipe(self.db.fishingCache) Nick@108: end Nick@108: self:Print('Cache data reset.') Nick@108: self:Update() Nenue@98: else Nenue@98: self:Show() Nenue@98: end Nenue@97: end Nenue@97: Nenue@97: self.tooltip = CreateFrame('GameTooltip', TOOLTIP_NAME, self, 'GameTooltipTemplate') Nenue@99: Nenue@97: Nenue@97: end Nick@108: local ShortNumberString = function (value) Nenue@116: if value >= 1000000 then Nenue@116: return tostring(floor(value/100000)/10) .. 'M' Nenue@116: elseif value >= 100000 then Nick@108: return tostring(floor(value/1000)) .. 'k' Nick@108: elseif value >= 1000 then Nick@108: return tostring(floor(value/100)/10) .. 'k' Nick@108: else Nick@108: return value Nick@108: end Nick@108: end Nenue@97: Nenue@102: Nenue@102: local IsBagnonOpen = function() Nenue@102: return ((BagnonFramebank and BagnonFramebank:IsShown()) or (BagnonFrameinventory and BagnonFrameinventory:IsShown())) Nenue@102: end Nenue@99: local addonCompatibility = { Nenue@99: ['Bagnon'] = { Nenue@99: BagFrames = {'BagnonFrameinventory'}, Nenue@99: BankFrames = {'BagnonFramebank'}, Nenue@102: FrameMethods = { Nenue@103: ['Hide'] = IsBagnonOpen, Nenue@103: ['Show'] = IsBagnonOpen Nenue@102: }, Nenue@103: PostHooks = {}, Nenue@99: MethodClass = 'Bagnon', Nenue@102: MethodHooks = {'BANK_OPENED', 'BANKFRAME_CLOSED'}, Nenue@102: Nenue@99: } Nenue@97: } Nenue@97: Nenue@103: Nenue@103: Nenue@103: local queued_hooks = {} Nenue@103: local function CreateHook(...) Nenue@103: if select('#', ...) >= 2 then Nenue@103: tinsert(queued_hooks, {...}) Nenue@103: end Nenue@103: if not InCombatLockdown() then Nenue@103: local info = tremove(queued_hooks) Nenue@103: while info do Nick@111: --[[local oFunc = tremove(info, #info) Nick@111: local args = info Nick@111: Nick@111: local func = function(...) Nick@111: print('|cFFFF0088Callback:|r', unpack(args)) Nick@111: Nick@111: oFunc(...) Nick@111: end Nick@111: print('hooking', unpack(info), oFunc, func) Nick@111: hooksecurefunc(unpack(info), func) Nick@111: --]] Nenue@103: hooksecurefunc(unpack(info)) Nenue@103: info = tremove(queued_hooks) Nenue@103: end Nenue@103: Nenue@103: end Nenue@103: end Nenue@103: Nenue@102: local function AddFrameHooks(frame, args) Nenue@102: for funcName, func in pairs(args.FrameMethods) do Nenue@102: print('binding', frame:GetName(), funcName, 'to', tostring(func)) Nenue@103: CreateHook(frame, funcName, function() Nick@111: print(frame:GetName(), funcName, 'hook') Nenue@103: VeneerArtifactPower:TryToShow() Nenue@103: end) Nenue@102: end Nenue@102: end Nenue@102: local PENDING_HOOKS = {} Nenue@102: Nenue@102: local function RegisterInventoryFrame(name, listType, args) Nenue@102: print('register', name, 'as inventory frame type =', (listType == BAG_FRAMES) and 'bags' or 'bank') Nenue@102: tinsert(FRAME_LIST, name) Nenue@102: tinsert(listType, name) Nenue@102: if _G[name] then Nenue@102: AddFrameHooks(_G[name], args) Nenue@102: else Nenue@102: PENDING_HOOKS[name] = args Nenue@102: end Nenue@102: end Nenue@102: Nenue@116: function Module:Setup() Nenue@97: print(self:GetName()..':Setup()') Nenue@97: local guid = UnitGUID('player') Nenue@97: VeneerData.ArtifactPower = VeneerData.ArtifactPower or defaultSettings Nenue@101: self.db = VeneerData.ArtifactPower Nenue@101: self.db[guid] = self.db[guid] or {} Nenue@101: self.db.cache = self.db.cache or {} Nenue@101: self.db.fishingCache = self.db.fishingCache or {} Nenue@101: Nenue@101: for i, data in pairs(self.cache) do Nenue@101: -- bring in anything found before player data is active Nenue@101: self.db.cache[i] = data Nenue@101: end Nenue@101: for i, data in pairs(self.fishingCache) do Nenue@101: self.db.fishingCache[i] = data Nenue@101: end Nenue@101: Nenue@101: Nenue@101: self.profile = self.db[guid] Nick@108: self.profile.cache = self.profile.cache or {} Nick@108: self.profile.cache.bagItems = self.profile.cache.bagItems or {} Nick@108: self.profile.cache.bags = self.profile.cache.bags or {} Nick@108: self.profile.cache.fishing = self.profile.cache.fishing or {} Nick@108: self.profile.cache.items = self.profile.cache.items or {} Nenue@97: self.profile.bagslots = self.profile.bagslots or {} Nenue@97: self.profile.artifacts = self.profile.artifacts or {} Nenue@97: self.updateSummary = true Nick@108: self.cache = self.profile.cache Nenue@97: Nenue@101: VeneerArtifactPowerTimer:SetScript('OnUpdate', function() Nenue@101: self:OnUpdate() Nenue@101: end) Nenue@101: Nenue@99: local DoTryToShow = function() Nick@111: Nenue@99: self:TryToShow() Nenue@99: end Nenue@103: CreateHook("OpenBackpack", DoTryToShow) Nenue@103: CreateHook("CloseBackpack", DoTryToShow) Nenue@99: Nenue@97: -- Bagnon compatibility Nenue@97: -- todo: ArkInventory, Elv, etc Nenue@99: for addon, args in pairs(addonCompatibility) do Nenue@99: if IsAddOnLoaded(addon) then Nenue@102: Nenue@99: for _, name in ipairs(args.BagFrames) do Nenue@102: RegisterInventoryFrame(name, BAG_FRAMES, args) Nenue@99: end Nenue@99: for _, name in ipairs(args.BankFrames) do Nenue@102: RegisterInventoryFrame(name, BANK_FRAMES, args) Nenue@99: end Nenue@102: Nenue@102: -- should only specify non-secure functions in this table Nenue@99: for _, name in ipairs(args.PostHooks) do Nenue@99: local oFunc = _G[name] Nenue@103: print('hook entry', name, tostring(oFunc)) Nenue@103: CreateHook(name, function(...) Nenue@103: print('|cFFFF0088' .. name .. '|r', ..., 'original', tostring(oFunc)) Nenue@99: oFunc(...) Nenue@99: self:TryToShow() Nenue@103: end) Nenue@99: end Nenue@99: local frame = _G[args.MethodClass] Nenue@99: if frame then Nenue@103: print() Nenue@99: for _, name in ipairs(args.MethodHooks) do Nenue@103: CreateHook(frame, name, DoTryToShow) Nenue@99: end Nenue@97: end Nenue@97: end Nenue@97: end Nenue@101: Nenue@101: if self.db.firstUse then Nenue@101: self.db.firstUse = nil Nenue@101: Nenue@101: end Nenue@99: end Nenue@97: Nenue@97: local UNDERLIGHT_ANGLER_ID = 133755 Nenue@97: Nenue@116: function Module:ResetCache() Nick@111: table.wipe(self.cache.items) Nick@111: table.wipe(self.cache.fishing) Nick@111: table.wipe(self.cache.bags) Nick@111: table.wipe(self.cache.bagItems) Nick@111: self:ScanAllBags() Nick@111: end Nick@111: Nenue@116: function Module:QueueBag(containerID) Nenue@97: containerID = tonumber(containerID) Nenue@97: if not containerID then Nenue@97: return Nenue@97: end Nenue@97: Nenue@97: if not tContains(BAGS_TO_SCAN, containerID) then Nenue@97: print(' queueing', containerID, type(containerID), #BAGS_TO_SCAN , 'in line') Nenue@97: BAGS_TO_SCAN[#BAGS_TO_SCAN + 1] = containerID Nenue@97: end Nenue@97: end Nenue@97: Nenue@116: function Module:Reanchor() Nenue@99: if Veneer then Nenue@99: Veneer:DynamicReanchor() Nenue@99: end Nenue@99: end Nenue@99: Nenue@116: function Module:OnShow() Nenue@99: print('|cFFFFFF00OnShow()|r') Nenue@102: Nenue@102: for name, args in pairs(PENDING_HOOKS) do Nenue@102: if _G[name] then Nenue@102: AddFrameHooks(_G[name], args) Nenue@102: PENDING_HOOKS[name] = nil Nenue@102: end Nenue@102: end Nenue@102: Nenue@102: Nenue@97: self.enabled = true Nenue@99: self:ScanAllBags() Nenue@99: self:Reanchor() Nenue@97: end Nenue@116: function Module:OnHide() Nick@111: print('|cFF88FF00OnHide()|r', debugstack()) Nenue@99: self:Reanchor() Nenue@97: end Nenue@116: function Module:OnEnter() Nenue@97: Nenue@97: GameTooltip:SetOwner(self, 'ANCHOR_CURSOR') Nenue@97: Nenue@99: Nenue@97: GameTooltip:AddLine(self.bagAP) Nenue@97: GameTooltip:AddLine(self.bankAP) Nenue@97: Nenue@97: end Nenue@97: Nenue@116: function Module:TryToShow() Nenue@99: Nenue@99: print('|cFFFFFF00TryToShow()') Nenue@99: Nenue@99: if not InCombatLockdown() then Nenue@99: for _, name in ipairs(FRAME_LIST) do Nenue@103: print('test:', name, (_G[name] and _G[name]:IsShown())) Nick@111: if _G[name] and _G[name]:IsVisible() then Nenue@99: if self:IsShown() then Nenue@99: self:Update() Nenue@99: else Nenue@99: self:Show() Nenue@99: end Nenue@99: return Nenue@99: end Nenue@99: end Nenue@99: end Nenue@99: Nick@111: print('failed tests') Nenue@99: self:Hide() Nenue@99: end Nenue@99: Nenue@99: Nenue@116: function Module:OnEvent(event, ...) Nenue@99: print('|cFF00FF88OnEvent()', event, ...) Nenue@99: if event == 'PLAYER_ENTERING_WORLD' then Nenue@99: self:TryToShow() Nenue@99: elseif event == 'BAG_UPDATE' then Nenue@97: local containerID = ... Nick@108: Nick@108: Nenue@97: self:QueueBag(containerID) Nick@108: elseif event == 'ITEM_LOCK_CHANGED' then Nick@108: Nick@108: local containerID, slotID = ... Nick@108: Nick@108: if self.cache.bags[containerID] and self.cache.bags[containerID][slotID] then Nick@108: self.cache.bags[containerID][slotID] = nil Nick@108: self.cache.fishing[containerID][slotID] = nil Nick@108: end Nick@108: Nick@108: Nenue@97: elseif event == 'PLAYER_BANKSLOTS_CHANGED' then Nenue@99: self:ScanAllBags() Nenue@97: elseif event == 'BAG_UPDATE_DELAYED' then Nenue@99: if not self.firstHit then Nenue@99: self.firstHit = true Nenue@99: else Nenue@99: self:ScanAllBags() Nenue@99: end Nenue@97: elseif event == 'BANKFRAME_OPENED' then Nenue@97: self.bankAccess = true Nenue@99: self:ScanAllBags() Nenue@97: elseif event == 'BANKFRAME_CLOSED' then Nenue@99: self.bankAccess = nil Nenue@97: elseif event == 'ARTIFACT_UPDATE' then Nenue@98: local newItem = ... Nenue@98: if newItem then Nenue@98: local itemID, _, name, texture, currentXP, pointsSpent = C_ArtifactUI:GetArtifactInfo() Nenue@98: self:SetArtifact(itemID, name, texture, currentXP, pointsSpent) Nenue@98: self:ScanAllBags(self.bankAccess) Nenue@98: end Nenue@98: elseif event == 'ARTIFACT_XP_UPDATE' then Nenue@98: local itemID, _, name, texture, currentXP, pointsSpent = C_ArtifactUI:GetEquippedArtifactInfo() Nenue@98: self:SetArtifact(itemID, name, texture, currentXP, pointsSpent) Nenue@98: self:ScanAllBags(self.bankAccess) Nenue@97: elseif event == 'PLAYER_REGEN_ENABLED' then Nenue@103: Nenue@103: if self.queuedScan then Nenue@103: self:ScanAllBags(self.backAccess) Nenue@103: else Nenue@103: self:TryToShow() Nenue@97: end Nenue@97: Nenue@103: if #queued_hooks >= 1 then Nenue@103: CreateHook() Nenue@103: end Nenue@97: elseif event == 'PLAYER_REGEN_DISABLED' then Nenue@97: self:Hide() Nenue@97: end Nenue@97: end Nenue@97: Nenue@116: function Module:OnUpdate() Nenue@101: if #self.scanQueue >= 1 then Nenue@101: local scanInfo = tremove(self.scanQueue, 1) Nick@111: end Nick@111: if IsShiftKeyDown() then Nick@111: self.Refresh:Show() Nick@111: else Nick@111: self.Refresh:Hide() Nick@111: end Nenue@101: Nenue@101: end Nenue@101: Nenue@116: function Module:OnMouseDown() Nenue@97: self.enabled = nil Nenue@97: self:Hide() Nenue@97: end Nenue@97: Nenue@116: function Module:Update() Nenue@97: if not self:IsShown() then Nenue@99: print('|cFFFF4400Update()|r') Nenue@97: return Nenue@97: end Nenue@97: print('|cFF00FFFFUpdate()|r') Nenue@97: Nenue@97: local bankText, bagText Nenue@101: if not self.profile.knowledgeMultiplier then Nenue@101: bankText = '|cFF00FF00Shift-Right-Click an artifact weapon to start building data.' Nenue@101: elseif not (self.bankAP and self.bagAP) then Nenue@97: bankText = '|cFFFF0000Open bank frame to count all AP|r ' Nenue@97: else Nick@111: Nick@111: if self.bagAP and (self.bagAP > 0) then Nick@111: bankText = 'Inventory: |cFFFFFFFF' .. ShortNumberString(self.bagAP) .. '|r' Nick@111: end Nick@111: if self.bankAP and (self.bankAP > 0) then Nick@111: bankText = (bankText and (bankText .. ' | ') or '') .. '|cFFFFFF00'..ShortNumberString(self.bankAP)..' banked|r' Nick@111: end Nick@111: if self.fishingAP and self.fishingAP > 0 then Nick@111: bankText = (bankText and (bankText .. ' | ') or '') .. '|cFF0088FF' .. ShortNumberString(self.fishingAP) .. ' fishing|r' Nick@111: end Nick@111: end Nick@111: Nick@111: self.worldQuestAP = 0 Nick@111: if WorldPlan then Nick@111: Nick@111: if not self.worldPlanHooked then Nick@111: WorldPlan:RegisterDataCallback(function() Nenue@116: print('data udpate callback') Nick@111: self:Update() Nick@111: end) Nenue@116: self.worldPlanHooked = true Nick@111: end Nick@111: Nick@111: Nick@111: local showWQ Nick@111: print('world plan is loaded') Nick@111: local worldQuests = WorldPlan:GetQuestPins() Nick@111: for index, pin in ipairs(worldQuests) do Nenue@116: if (pin.rewardType == WORLD_QUEST_REWARD_TYPE_FLAG_ARTIFACT_POWER) and (pin.isActive) and (pin.dataLoaded) then Nick@111: showWQ = true Nick@111: print(pin.itemNumber) Nick@111: self.worldQuestAP = self.worldQuestAP + pin.itemNumber Nenue@98: end Nenue@98: end Nick@111: Nick@111: if showWQ then Nick@111: bankText = (bankText and (bankText .. '\n') or '') .. '|cFFFFBB00World Quests:|r |cFFFFFFFF' .. ShortNumberString(self.worldQuestAP) .. '' Nick@111: end Nick@111: Nenue@99: end Nenue@99: Nenue@97: self.SummaryHeader:SetText(bankText) Nenue@97: Nenue@101: local numButtons = 0 Nick@111: local contentsHeight = 16 + self.SummaryHeader:GetHeight() Nick@111: local contentsWidth = self.SummaryHeader:GetWidth() + 16 Nenue@101: if self.profile.knowledgeMultiplier then Nenue@116: local artifactsWidth = self:UpdateArtifactButtons() Nick@108: Nenue@116: if artifactsWidth ~= 0 then Nick@111: contentsHeight = contentsHeight + 64 Nick@111: end Nick@111: Nenue@116: contentsWidth = max(contentsWidth, artifactsWidth) Nick@108: Nick@108: local itemsWidth, itemsHeight = self:UpdateItemButtons() Nick@108: contentsHeight = contentsHeight + itemsHeight Nick@108: contentsWidth = max(contentsWidth, itemsWidth) Nenue@101: end Nenue@101: Nenue@101: Nick@111: if not self.hasArtifacts then Nick@111: self:SetShown(false) Nick@111: end Nick@111: Nenue@101: Nick@108: self:SetWidth(contentsWidth) Nick@108: self:SetHeight(contentsHeight) Nenue@101: self:Reanchor() Nenue@101: end Nenue@101: Nenue@116: function Module:UpdateArtifactButtons() Nenue@101: Nenue@97: -- Artifact icons, in no particular order Nenue@99: self.equippedID = C_ArtifactUI.GetEquippedArtifactInfo() Nick@111: self.canAddAP = nil Nick@111: self.canAddFishingAP = nil Nick@111: local hasArtifacts Nenue@97: local numButtons = 0 Nenue@99: local lastFrame = self Nenue@99: local fishingID, fishingData Nenue@98: local index, button Nenue@116: local equipped =self.profile.artifacts[self.equippedID] Nenue@116: local buttonsWidth = 0 Nenue@116: if equipped then Nenue@116: numButtons = numButtons + 1 Nenue@116: button = self.Artifact[numButtons] Nenue@116: button.relativeFrame = self Nenue@116: lastFrame = button:SetButton(self.equippedID, equipped, numButtons, true, nil) Nenue@116: hasArtifacts = true Nenue@116: Nenue@116: buttonsWidth = EQUIPPED_SIZE + (FRAME_PADDING * 2) Nenue@116: end Nenue@116: Nenue@116: Nenue@97: for itemID, artifact in pairs(self.profile.artifacts) do Nenue@116: if (itemID == UNDERLIGHT_ANGLER_ID) then Nenue@116: -- only add if we have fishing AP items and it's not being shown in the equipped slot Nenue@116: if VeneerData.ArtifactPower.EnableFishing and (itemID ~= self.equippedID) then Nenue@98: fishingID = itemID Nenue@98: fishingData = artifact Nenue@98: end Nenue@97: Nick@111: if artifact.level < FISHING_MAX_TRAITS then Nick@111: if itemID == self.equippedID then Nick@111: self.canAddFishingAP = true Nick@111: end Nick@111: end Nenue@98: else Nick@111: if artifact.level < WEAPON_MAX_TRAITS then Nick@111: if itemID == self.equippedID then Nick@111: self.canAddAP = true Nenue@116: else Nenue@116: Nenue@116: hasArtifacts = true Nenue@116: numButtons = numButtons + 1 Nenue@116: button = self.Artifact[numButtons] Nenue@116: button.relativeFrame = lastFrame Nenue@116: lastFrame = button:SetButton(itemID, artifact, numButtons, (self.equippedID == itemID), nil) Nenue@116: buttonsWidth = buttonsWidth + lastFrame:GetWidth() + FRAME_PADDING Nick@111: end Nick@108: end Nenue@97: end Nick@111: end Nenue@97: Nenue@97: Nick@108: if fishingData and (self.fishingAP and self.fishingAP > 0) then Nenue@98: numButtons = numButtons + 1 Nick@111: hasArtifacts = true Nenue@99: local button = self.Artifact[numButtons] Nenue@99: button.relativeFrame = lastFrame Nick@111: button.isFishing = true Nenue@99: button:SetButton(fishingID, fishingData, numButtons, self.equippedID == fishingID) Nenue@98: end Nenue@97: Nick@111: self.hasArtifacts = hasArtifacts Nenue@99: for i = numButtons+ 1, #self.Artifact do Nenue@97: print('hide', i) Nenue@97: self.Artifact[i]:Hide() Nenue@97: end Nenue@97: Nick@111: Nenue@116: return buttonsWidth Nenue@97: end Nenue@97: Nenue@99: Nenue@116: function Module:UpdateItemButtons() Nenue@99: print('|cFF00FFFFUpdateItemButtons()|r') Nick@111: Nick@111: local apType Nick@111: if self.canAddFishingAP then Nick@111: apType = true Nick@111: elseif not self.canAddAP then Nick@111: for index, button in ipairs(self.Tokens) do Nick@111: button:Hide() Nick@111: end Nick@111: return 0, 0 Nick@111: end Nick@111: Nick@111: Nenue@99: local lastFrame, upFrame Nenue@99: local numButtons = 0 Nenue@101: local buttonsHeight = 0 Nick@108: local buttonsWidth = 0 Nick@111: Nenue@99: for index, button in ipairs(self.Tokens) do Nick@111: if (button.numItems >= 1) and (button.isFishingAP == apType) then Nenue@99: if button.itemName then Nenue@99: self:SetItemAction(button) Nenue@99: end Nenue@99: Nenue@99: button:ClearAllPoints() Nenue@99: numButtons = numButtons + 1 Nick@111: local col = mod(numButtons,8) Nenue@99: print(index, button:GetID(), button.Icon:GetTexture()) Nenue@99: if numButtons == 1 then Nenue@101: button:SetPoint('TOPLEFT', self, 'TOPLEFT', 4, -76) Nenue@99: upFrame = button Nenue@101: buttonsHeight = 52 Nenue@99: else Nick@108: if col == 1 then Nick@108: button:SetPoint('TOPLEFT', upFrame, 'BOTTOMLEFT', 0, -2) Nick@108: upFrame = button Nick@108: buttonsHeight = buttonsHeight + 52 Nick@108: Nick@108: else Nick@108: button:SetPoint('TOPLEFT', lastFrame, 'TOPRIGHT', 2, 0) Nick@108: Nick@108: end Nenue@99: end Nick@111: Nenue@99: button.Count:SetText(button.numItems) Nenue@99: lastFrame = button Nenue@99: button:Show() Nenue@99: else Nenue@99: button:Hide() Nenue@99: end Nick@111: buttonsWidth = min(numButtons, 8) * (BUTTON_SIZE) Nick@111: end Nick@111: Nick@111: Nick@111: Nick@111: if buttonsWidth ~= 0 then Nick@111: buttonsWidth = buttonsWidth + 8+ ((min(numButtons, 8)-1)*2) Nenue@99: end Nenue@99: Nenue@101: Nenue@101: Nick@108: return buttonsWidth, buttonsHeight Nenue@99: end Nenue@99: Nenue@116: function Module:SetItemAction(button, name) Nenue@99: name = name or self.itemName Nenue@99: if InCombatLockdown() then Nenue@99: self.itemName = name Nenue@99: return Nenue@99: else Nenue@99: button:SetAttribute('*type*','item') Nenue@99: button:SetAttribute('*item*', name) Nenue@99: end Nenue@99: end Nenue@99: Nenue@116: function Module:GetItemButton(itemID, texture, itemAP, fishing) Nenue@99: print('|cFF00FFFFGetItemButton()|r', itemID, texture, itemAP) Nenue@99: local button = self.ItemButtons[itemID] Nenue@101: Nenue@99: if not button then Nenue@99: button = CreateFrame('Button', 'VeneerAPToken'..itemID, self, 'VeneerItemButton') Nenue@101: button.baseAP = itemAP Nenue@101: Nenue@99: button:SetPushedTexture([[Interface\Buttons\UI-Quickslot-Depress]]) Nenue@99: button:SetHighlightTexture([[Interface\Buttons\ButtonHilight-Square]],"ADD") Nenue@99: button:SetID(itemID) Nenue@99: button.numItems = 0 Nenue@99: button.Icon:SetTexture(texture) Nenue@99: button:RegisterForClicks("AnyUp") Nick@111: button.isFishingAP = fishing Nenue@99: self:SetItemAction(button, GetItemInfo(itemID)) Nenue@99: Nenue@99: print(' created') Nenue@99: self.ItemButtons[itemID] = button Nenue@99: self.numItems = self.numItems + 1 Nenue@99: end Nenue@99: Nenue@116: button.Label:SetText(ShortNumberString(itemAP)) Nenue@101: Nenue@99: button.numItems = button.numItems + 1 Nenue@99: return button Nenue@99: end Nenue@99: Nenue@116: function Module:GetItemAP(itemID, itemLink, bagData) Nick@108: if not self.cache.items[itemID] then Nenue@101: Nick@111: print('doing tooltip scan', itemLink, itemID) Nenue@101: self.tooltip:SetOwner(self, 'ANCHOR_NONE') Nenue@101: self.tooltip:SetHyperlink(itemLink) Nenue@101: self.tooltip:Show() Nenue@101: local numLines = self.tooltip:NumLines() Nenue@101: if numLines >= 3 then Nenue@101: for i = 3, numLines do Nenue@101: local text = _G[TOOLTIP_NAME .. 'TextLeft'.. i]:GetText() Nick@111: if text then Nick@111: Nick@111: text = text:lower():gsub(',', '') Nenue@116: Nick@111: if text:match('equipped artifact') then Nick@111: print(itemLink, '-', tonumber(text)) Nenue@116: Nenue@116: local itemAP = text:match('[%d%.]+') Nick@111: if itemAP then Nenue@116: -- tokens > 1M are described as '%f million' Nenue@116: if text:match("million") then Nenue@116: itemAP = tonumber(itemAP) * 1000000 Nenue@116: end Nenue@116: Nick@111: itemAP = itemAP Nick@111: self.cache.items[itemID] = tonumber(itemAP) Nick@111: end Nick@111: end Nick@111: if text:match('fishing artifact') then Nick@111: local fishingAP = text:match("%d+") Nick@111: fishingAP = fishingAP Nick@111: print(itemLink, 'fishing', tonumber(text)) Nick@111: if fishingAP then Nick@111: self.cache.items[itemID] = tonumber(fishingAP) Nick@111: self.cache.fishing[itemID] = true Nick@111: end Nenue@101: end Nenue@101: end Nenue@101: end Nenue@101: else Nenue@101: Nick@108: self.cache.items[itemID] = 0 Nenue@101: end Nenue@101: end Nick@108: return self.cache.items[itemID], self.cache.fishing[itemID] Nenue@101: end Nenue@101: Nenue@116: function Module:SetArtifact(itemID, name, texture, currentXP, pointsSpent) Nenue@103: print('|cFF00FF00SetArtifact()|r') Nenue@103: if not self.profile then Nenue@103: return Nenue@103: end Nenue@103: local artifacts = self.profile.artifacts Nenue@103: Nenue@103: local multi = C_ArtifactUI.GetArtifactKnowledgeMultiplier() Nick@108: if multi and (self.profile.knowledgeMultiplier ~= multi) then Nick@108: table.wipe(self.cache.items) Nick@108: table.wipe(self.cache.fishing) Nick@108: end Nick@108: Nenue@103: self.profile.knowledgeMultiplier = multi or self.profile.knowledgeMultiplier Nenue@103: print('multiplier:', multi) Nenue@103: Nenue@103: if itemID then Nenue@103: Nenue@103: self.currentEquipped = itemID Nenue@103: Nenue@103: artifacts[itemID] = artifacts[itemID] or {} Nenue@103: table.wipe(artifacts[itemID]) Nenue@103: local artifact = artifacts[itemID] Nenue@103: Nenue@103: artifact.name = name Nenue@103: artifact.texture = texture Nenue@103: artifact.currentXP = currentXP Nenue@103: artifact.level = pointsSpent Nenue@116: artifact.tier = C_ArtifactUI.GetArtifactTier() or ((pointsSpent >= 36) and 2 or 1) Nenue@116: Nenue@116: print('tier', artifact.tier) Nenue@116: local cost = C_ArtifactUI.GetCostForPointAtRank(pointsSpent, artifact.tier) Nick@108: artifact.currentCost = cost Nenue@103: Nenue@116: Nenue@103: Nenue@103: end Nenue@103: end Nenue@103: Nenue@116: function Module:ScanBag(id) Nenue@97: print('|cFF00FFFFScanBag()|r', id, IsBagOpen(id), GetContainerNumSlots(id)) Nenue@97: local numSlots = GetContainerNumSlots(id) Nenue@97: local requiresUpdate Nenue@97: if numSlots == 0 then Nenue@97: return nil Nenue@97: end Nenue@97: Nenue@97: Nenue@97: self.profile.bagslots[id] = self.profile.bagslots[id] or {} Nenue@97: table.wipe(self.profile.bagslots[id]) Nenue@97: local bagData = self.profile.bagslots[id] Nenue@97: bagData.totalAP = 0 Nenue@99: bagData.fishingAP = 0 Nenue@99: bagData.items = bagData.items or {} Nenue@99: table.wipe(bagData.items) Nick@111: local c = self.cache Nenue@99: Nick@111: c.bagItems[id] = c.bagItems[id] or {} Nick@111: c.bags[id] = c.bags[id] or {} Nick@111: c.fishing[id] = c.fishing[id] or {} Nick@108: Nenue@97: for slotID = 1, numSlots do Nenue@97: local texture, count, locked, quality, readable, lootable, link = GetContainerItemInfo(id, slotID) Nenue@101: if link then Nenue@101: local itemID = GetContainerItemID(id, slotID) Nenue@101: local name, _, quality, iLevel, reqLevel, class, subclass = GetItemInfo(link) Nenue@97: Nick@111: if class == 'Consumable' or subclass == 'Cooking' then Nenue@102: --print(GetItemInfo(link)) Nick@108: local itemAP, isFishingAP Nick@111: if c.bags[id][slotID] and (c.bagItems[id][slotID] == itemID) then Nick@111: --print('cached slot', id, slotID, name) Nick@111: itemAP = c.bags[id][slotID] Nick@111: isFishingAP = c.fishing[id] and c.fishing[id][slotID] Nick@108: else Nick@108: itemAP, isFishingAP = self:GetItemAP(itemID, link) Nick@111: c.bagItems[id][slotID] = itemID Nick@111: c.bags[id][slotID] = itemAP Nick@111: c.fishing[id][slotID] = isFishingAP Nick@108: end Nick@108: Nick@108: Nenue@102: --print(itemAP, isFishingAP) Nenue@102: if itemAP and (itemAP > 0) then Nick@111: local itemButton = self:GetItemButton(itemID, texture, itemAP, isFishingAP) Nenue@102: Nenue@101: if isFishingAP then Nenue@101: bagData.fishingItems = (bagData.fishingItems or 0) + 1 Nenue@101: bagData.fishingAP = (bagData.fishingAP or 0) + itemAP Nenue@101: else Nick@108: itemAP = itemAP Nenue@101: bagData.numItems = (bagData.numItems or 0) + 1 Nenue@101: bagData.totalAP = (bagData.totalAP or 0) + itemAP Nenue@101: end Nenue@101: bagData.items[itemID] = (bagData.items[itemID] or 0) + 1 Nenue@101: end Nenue@101: elseif self.profile.artifacts[itemID] then Nick@111: --print('artifact weapon', itemID, link, id, slotID) Nenue@101: self.profile.artifacts[itemID].containerID = id Nenue@101: self.profile.artifacts[itemID].slotID = slotID Nick@111: else Nick@111: --print('skipping', class, subclass, link) Nenue@101: end Nenue@99: Nenue@97: end Nenue@97: Nenue@97: end Nenue@97: Nenue@97: end Nenue@97: Nenue@98: local BAG_SLOTS = {0, 1, 2, 3, 4 } Nenue@98: local BANK_SLOTS = {-1, 5, 6,7, 8, 9, 10, 11, 12} Nenue@99: local ItemCounts = {} Nenue@116: function Module:ScanAllBags() Nenue@99: if InCombatLockdown() then Nenue@99: self.queuedScan = true Nenue@99: return Nenue@99: end Nenue@101: if not self.profile.knowledgeMultiplier then Nenue@101: print('need to get knowledge level') Nenue@101: return Nenue@101: end Nenue@101: Nenue@99: self.queuedScan = nil Nenue@98: Nenue@101: print('|cFFFF0088ScanAllBags()|r', self.profile.knowledgeMultiplier) Nenue@97: Nenue@99: for _, button in ipairs(self.Tokens) do Nenue@99: button.numItems = 0 Nenue@99: end Nenue@99: Nenue@99: Nenue@98: for _, bagID in ipairs(BAG_SLOTS) do Nenue@98: self:ScanBag(bagID) Nenue@97: end Nenue@97: Nenue@99: if self.bankAccess then Nenue@98: for _, bagID in ipairs(BANK_SLOTS) do Nenue@98: self:ScanBag(bagID) Nenue@98: end Nenue@98: end Nenue@98: Nenue@98: self.bankAP = 0 Nenue@98: self.bagAP = 0 Nenue@99: self.fishingAP = 0 Nenue@99: Nenue@99: table.wipe(ItemCounts) Nenue@98: for id, bagData in pairs(self.profile.bagslots) do Nick@111: print(id, GetBagName(id), bagData.totalAP, bagData.fishingAP) Nenue@98: id = tonumber(id) Nenue@98: if bagData.totalAP then Nenue@98: if (id == BANK_CONTAINER) or (id >= 5) then Nenue@98: self.bankAP = self.bankAP + bagData.totalAP Nenue@98: else Nenue@98: self.bagAP = self.bagAP + bagData.totalAP Nenue@97: end Nenue@98: end Nenue@99: if bagData.fishingAP then Nenue@99: self.fishingAP = self.fishingAP + bagData.fishingAP Nenue@99: end Nenue@97: Nenue@97: end Nenue@98: self.lastUpdate = GetTime() Nenue@103: self.queuedScan = nil Nenue@99: self:TryToShow() Nenue@97: end Nenue@97: Nenue@97: VeneerArtifactButtonMixin = {} Nenue@116: local Artifact = VeneerArtifactButtonMixin Nenue@98: Nenue@116: function Artifact:SetButton(itemID, artifact, index, equipped, fishing) Nenue@99: print(itemID, index) Nenue@98: print(artifact.name, artifact.texture, artifact.currentXP) Nenue@98: self:SetID(itemID) Nick@108: if not artifact.currentCost then Nick@108: artifact.currentCost = artifact.cost Nick@108: end Nick@108: Nenue@98: for k,v in pairs(artifact) do Nenue@98: --print('::',k,v) Nenue@98: self[k] = v Nenue@98: end Nenue@98: Nick@111: self.isFishing = fishing Nenue@98: -- this can change between artifact parses Nenue@99: local totalAP = (itemID ~= UNDERLIGHT_ANGLER_ID) and ((self:GetParent().bankAP or 0) + (self:GetParent().bagAP or 0)) or (self:GetParent().fishingAP or 0) Nenue@99: print(totalAP) Nenue@99: Nenue@116: -- currentXP what has been spent on the artifact Nenue@116: -- actualXP amount Nenue@116: -- totalXP Nenue@116: local actualXP = artifact.currentXP + totalAP Nenue@116: local actualLevel = artifact.level Nenue@116: local actualCost = C_ArtifactUI.GetCostForPointAtRank(actualLevel, artifact.tier) Nenue@116: Nenue@116: while actualXP >= actualCost do Nenue@116: actualXP = actualXP - actualCost Nenue@116: actualLevel = actualLevel + 1 Nenue@116: actualCost = C_ArtifactUI.GetCostForPointAtRank(actualLevel, artifact.tier) Nenue@116: print('* ', actualLevel, actualXP, actualCost) Nenue@98: end Nenue@116: self.actualCost = actualCost Nenue@116: self.actualLevel = actualLevel Nenue@116: self.actualXP = actualXP Nenue@116: self.totalXP = artifact.currentXP + totalAP Nenue@98: Nenue@98: Nenue@99: if index ~= 1 then Nenue@99: self:ClearAllPoints() Nenue@99: self:SetPoint('TOPLEFT', self.relativeFrame, 'TOPRIGHT', 4, 0) Nenue@99: else Nenue@99: self:ClearAllPoints() Nenue@99: self:SetPoint('TOPLEFT', self.relativeFrame, 'TOPLEFT', 4, -4) Nenue@99: end Nenue@98: Nenue@99: self.isEquipped = equipped Nenue@98: self:Update() Nenue@98: self:Show() Nenue@98: return self Nenue@98: end Nenue@98: Nenue@116: function Artifact:Update() Nenue@116: local r1, g1, b1 = 1, 1, 1 Nenue@116: local r2, g2, b2 = 1, 1, 0 Nenue@99: local levelText = self.level Nenue@116: local xpText = ShortNumberString(self.currentXP) Nenue@116: local costText = ShortNumberString(self.currentCost) Nenue@116: local remainingText = ShortNumberString(self.currentCost - self.currentXP) Nenue@116: -- current: amount shown in blizz ui Nenue@116: -- actual: amount contributing the next level, will be same until current point cap is reached Nenue@116: -- potential: total of ap on hand Nenue@116: print(self.currentXP, self.actualXP, self.potentialXP) Nenue@97: if self.actualLevel ~= self.level then Nenue@116: Nenue@116: levelText = self.actualLevel Nenue@116: r1, g1, b1 = 0, 1, 0 Nenue@116: r2, g2, b2 = 0, 1, 0 Nenue@116: xpText = ShortNumberString(self.actualXP) Nenue@116: costText = ShortNumberString(self.actualCost) Nenue@116: remainingText = ShortNumberString(self.actualCost-self.actualXP) Nenue@116: --[[elseif self.potentialLevel ~= self.level then Nenue@116: r1, g1, b1 = 0, 1, 1 Nenue@116: r2, g2, b2 = 0, 1, 1 Nenue@116: costText = ShortNumberString(self.potentialCost) Nenue@116: remainingText = ShortNumberString(self.potentialCost-self.potentialXP) Nenue@116: --]] Nenue@97: end Nenue@97: Nenue@99: self.Level:SetText(levelText) Nenue@116: self.CurrentXP:SetText( xpText ) Nenue@116: self.RemainingCost:SetText(remainingText) Nenue@116: self.Level:SetTextColor(r1, g1, b1) Nenue@116: self.CurrentXP:SetTextColor(r1, g1, b1) Nenue@99: Nenue@97: if self.isEquipped then Nenue@116: self:SetSize(64,64) Nenue@97: self:SetNormalTexture([[Interface\Buttons\ButtonHilight-Square]]) Nenue@97: self:GetNormalTexture():SetBlendMode('ADD') Nenue@97: self:GetNormalTexture():SetVertexColor(0,1,0) Nenue@97: else Nenue@116: self:SetSize(48,48) Nenue@97: self:SetNormalTexture(nil, 'ADD') Nenue@97: end Nenue@97: Nick@108: local currentProgress = (self.currentXP < self.currentCost) and (self.currentXP / self.currentCost) or 1 Nenue@98: if self.level <= 53 then Nenue@98: self.CurrentProgress.animateFrom = self.CurrentProgress:GetHeight() or 1 Nenue@98: self.CurrentProgress.animateTo = currentProgress * self:GetHeight() Nenue@98: self.CurrentProgress:Show() Nenue@101: self.ProgressLine:Show() Nenue@98: else Nenue@98: self.CurrentProgress:Hide() Nenue@101: self.ProgressLine:Hide() Nenue@98: end Nenue@99: Nenue@116: if self.actualXP ~= self.currentXP then Nenue@116: local projectedProgress = (self.actualXP ~= self.actualCost) and (self.actualXP / self.actualCost) or 1 Nenue@98: if (projectedProgress > currentProgress) then Nenue@98: self.AdjustedProgress:SetPoint('BOTTOM', self.CurrentProgress, 'TOP') Nenue@98: projectedProgress = projectedProgress - currentProgress Nenue@98: else Nenue@116: self.CurrentProgress:Hide() Nenue@116: self.ProgressLine:Hide() Nenue@98: self.AdjustedProgress:SetPoint('BOTTOM', self, 'BOTTOM') Nenue@98: end Nenue@116: print('show actual', currentProgress, projectedProgress) Nenue@98: self.AdjustedProgress.animateFrom = self.AdjustedProgress:GetHeight() or 1 Nenue@98: self.AdjustedProgress.animateTo = projectedProgress * self:GetHeight() Nenue@101: self.AdjustedLine:Show() Nenue@98: self.AdjustedProgress:Show() Nenue@98: else Nenue@98: self.AdjustedProgress:Hide() Nenue@101: self.AdjustedLine:Hide() Nenue@98: end Nenue@116: Nenue@116: Nenue@116: Nenue@97: self.Icon:SetTexture(self.texture) Nenue@97: end Nenue@97: Nenue@98: Nenue@116: function Artifact:AnimateProgress(region) Nenue@98: local cTime = GetTime() Nenue@98: if not region.animateStart then Nenue@98: region.animateStart = cTime Nenue@98: end Nenue@98: local progressTo, progressFrom = region.animateTo, region.animateFrom Nenue@98: local elapsed = cTime - region.animateStart Nenue@98: if elapsed >= .5 then Nenue@98: region:SetHeight(progressTo) Nenue@98: region.animateTo = nil Nenue@98: region.animateStart = nil Nenue@98: region.animateFrom = nil Nenue@98: else Nenue@98: local progress = elapsed / .5 Nenue@98: local height = (progressFrom + (progressTo - progressFrom) * progress) Nenue@98: --print(self:GetName(), progressTo, progressFrom, (progressTo - progressFrom), ceil(progress*10)/10, ceil(height)) Nenue@98: region:SetHeight(height) Nenue@98: end Nenue@98: end Nenue@98: Nenue@116: function Artifact:OnUpdate(sinceLast) Nenue@98: if self.CurrentProgress.animateTo then Nenue@98: self:AnimateProgress(self.CurrentProgress) Nenue@98: end Nenue@98: Nenue@98: if self.AdjustedProgress.animateTo then Nenue@98: self:AnimateProgress(self.AdjustedProgress) Nenue@98: end Nenue@98: end Nenue@98: Nenue@116: function Artifact:OnEnter() Nenue@97: GameTooltip:SetOwner(self, 'ANCHOR_CURSOR') Nenue@97: GameTooltip:SetText(self.name) Nick@108: GameTooltip:AddLine(ShortNumberString(self.currentXP) .. ' / '..ShortNumberString(self.currentCost), 1, 1, 0) Nenue@116: if self.totalXP ~= self.currentXP then Nenue@116: GameTooltip:AddLine(ShortNumberString(self.totalXP) .. ' total XP', 0, 1, 1) Nenue@116: if self.actualXP ~= self.potentialXP then Nenue@116: GameTooltip:AddLine(ShortNumberString(self.actualXP) .. ' / ' .. ShortNumberString(self.actualCost).. ' after', 0, 1, 0) Nenue@98: end Nenue@97: end Nenue@99: if self.actualLevel ~= self.level then Nick@108: GameTooltip:AddLine(ShortNumberString(self.actualLevel - self.level) .. ' points unlocked', 0, 1, 1) Nick@108: end Nick@108: if self.currentXP < self.currentCost then Nick@108: GameTooltip:AddLine(ShortNumberString(self.currentCost - self.currentXP) .. ' needed') Nenue@99: end Nenue@99: Nenue@97: GameTooltip:Show() Nenue@97: end Nenue@116: function Artifact:OnLeave() Nenue@97: if GameTooltip:IsOwned(self) then Nenue@97: GameTooltip:Hide() Nenue@97: end Nenue@97: end Nenue@116: function Artifact:OnHide() Nick@108: Nick@108: if GameTooltip:IsOwned(self) then Nick@108: GameTooltip:Hide() Nick@108: end Nick@108: end Nenue@97: Nenue@116: function Artifact:OnClick(button, down) Nenue@97: if self.isEquipped then Nenue@97: SocketInventoryItem(16) Nenue@97: else Nick@108: if IsShiftKeyDown() then Nenue@97: SocketContainerItem(self.containerID, self.slotID) Nick@108: else Nick@108: Nick@108: end Nenue@97: end Nenue@97: end