-- ------------------------------------------------------------------------------ -- -- TradeSkillMaster_Crafting -- -- http://www.curse.com/addons/wow/tradeskillmaster_crafting -- -- -- -- A TradeSkillMaster Addon (http://tradeskillmaster.com) -- -- All Rights Reserved* - Detailed license information included with addon. -- -- ------------------------------------------------------------------------------ -- -- create a local reference to the TradeSkillMaster_Crafting table and register a new module local TSM = select(2, ...) local GUI = TSM:NewModule("CraftingGUI", "AceEvent-3.0", "AceHook-3.0") local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_Crafting") -- loads the localization table local priceTextCache = { lastClear = 0 } local private = {} private.gather = {} private.shown = {} private.eventObj = nil -- list of profession skills that do not have crafting. used by UpdateTradeSkills local invalidTrade = { ["Herbalism"] = true, ["Skinning"] = true, ["Fishing"] = true, ["Riding"] = true } -- Helper function to find spellID associated to spellname local function GetTradeSkillSpellID(spellName) -- GetTradeSkillRecipeLink ONLY works when a trade skill window is open, but this should always happen for i = 1,GetNumTradeSkills() do local link = GetTradeSkillRecipeLink(i) if link and link:match(spellName) then -- Not a header and spell name found local spellID = tonumber(link:match("enchant:(%d+)")) if spellID then return spellID end end end return nil end function GUI:OnEnable() GUI:RegisterEvent("TRADE_SKILL_SHOW", "ShowProfessionWindow") GUI:RegisterEvent("TRADE_SKILL_CLOSE", "EventHandler") GUI:RegisterEvent("TRADE_SKILL_UPDATE", "EventHandler") GUI:RegisterEvent("TRADE_SKILL_FILTER_UPDATE", "EventHandler") GUI:RegisterEvent("UPDATE_TRADESKILL_RECAST", "EventHandler") GUI:RegisterEvent("CHAT_MSG_SKILL", "EventHandler") GUI:RegisterEvent("UNIT_SPELLCAST_START", "EventHandler") GUI:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED", "EventHandler") GUI:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED", "EventHandler") GUI:RegisterEvent("UNIT_SPELLCAST_FAILED", "EventHandler") GUI:RegisterEvent("GUILDBANKFRAME_OPENED", "GatheringEventHandler") GUI:RegisterEvent("GUILDBANKFRAME_CLOSED", "GatheringEventHandler") GUI:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED", "GatheringEventHandler") GUI:RegisterEvent("MERCHANT_SHOW", "GatheringEventHandler") GUI:RegisterEvent("MERCHANT_UPDATE", "GatheringEventHandler") GUI:RegisterEvent("MERCHANT_CLOSED", "GatheringEventHandler") GUI:RegisterEvent("MAIL_SHOW", "GatheringEventHandler") GUI:RegisterEvent("MAIL_CLOSED", "GatheringEventHandler") GUI:RegisterEvent("BANKFRAME_OPENED", "GatheringEventHandler") GUI:RegisterEvent("BANKFRAME_CLOSED", "GatheringEventHandler") GUI:RegisterEvent("UPDATE_PENDING_MAIL", "GatheringEventHandler") GUI:RegisterEvent("AUCTION_HOUSE_SHOW", "GatheringEventHandler") GUI:RegisterEvent("AUCTION_HOUSE_CLOSED", "GatheringEventHandler") GUI:RegisterEvent("MAIL_INBOX_UPDATE", "QueueUpdateHandler") TSMAPI:CreateTimeDelay("craftingUpdateTradeSkill", 1, function() GUI:UpdateSelectedTradeSkill() end, 0.1) TSMAPI:RegisterForBagChange(function() TSMAPI:CreateTimeDelay("craftingProfessionUpdateThrottle", 0.05, GUI.UpdateProfessionsTabST) TSMAPI:CreateTimeDelay("craftingQueueUpdateThrottle", 0.1, GUI.UpdateQueue) TSMAPI:CreateTimeDelay("gatheringUpdateThrottle", 0.3, GUI.UpdateGathering) end) TSMAPI:RegisterForBankChange(function() TSMAPI:CreateTimeDelay("gatheringUpdateThrottle", 0.3, GUI.UpdateGathering) end) private.eventObj = private.eventObj or TSMAPI:GetEventObject() private.eventObj:SetCallback("TSM:AUCTIONCONTROL:ITEMBOUGHT", private.OnAuctionBought) GUI:UpdateTradeSkills() GUI.gatheringFrame = GUI:CreateGatheringFrame() if next(TSM.db.realm.gathering.neededMats) then TSMAPI:CreateTimeDelay("gatheringShowThrottle", 0.3, GUI:ShowGatheringFrame()) end end function private.OnAuctionBought() if not GUI.frame or not GUI.frame:IsVisible() then return end TSMAPI:CreateTimeDelay("craftingQueueUpdateThrottle", 0.1, GUI.UpdateQueue) TSMAPI:CreateTimeDelay("craftingProfessionUpdateThrottle", 0.2, GUI.UpdateProfessionsTabST) end function GUI:QueueUpdateHandler() if not GUI.frame or not GUI.frame:IsVisible() then return end TSMAPI:CreateTimeDelay("craftingQueueUpdateThrottle", 0.1, GUI.UpdateQueue) TSMAPI:CreateTimeDelay("craftingProfessionUpdateThrottle", 0.2, GUI.UpdateProfessionsTabST) end function GUI:ShowGatheringFrame() if GUI.gatheringFrame then GUI.gatheringFrame:Show() if AuctionFrame and AuctionFrame:IsVisible() then GUI:GatheringEventHandler("AUCTION_HOUSE_SHOW") elseif BankFrame and BankFrame:IsVisible() then GUI:GatheringEventHandler("BANKFRAME_OPENED") elseif MerchantFrame and MerchantFrame:IsVisible() then GUI:GatheringEventHandler("MERCHANT_SHOW") elseif GuildBankFrame and GuildBankFrame:IsVisible() then GUI:GatheringEventHandler("GUILDBANKFRAME_OPENED") end GUI:UpdateGathering() end end function GUI:ShowProfessionWindow() if not TradeSkillFrame and not AscensionTradeSkillFrame then return TSMAPI:CreateTimeDelay("craftingShowProfessionDelay", 0, GUI.ShowProfessionWindow) end -- if GetTradeSkillLine() == GetSpellInfo(53428) or IsTradeSkillGuild() then if GetTradeSkillLine() == GetSpellInfo(53428) then -- runeforging or guild profession if GUI.frame then GUI.noClose = true GUI.frame:Hide() GUI.noClose = nil end if GUI.switchBtn then GUI.switchBtn:Hide() end return end TradeSkillFrame:UnregisterEvent("TRADE_SKILL_SHOW") -- AscensionTradeSkillFrame:UnregisterEvent("TRADE_SKILL_SHOW") -- AscensionTradeSkillFrame:OpenOldUI() GUI:ShowSwitchButton() if TSM.db.global.showingDefaultFrame then return end GUI:UpdateTradeSkills(GetTradeSkillLine()) TradeSkillFrame:SetScript("OnHide", nil) HideUIPanel(TradeSkillFrame) TradeSkillFrame:SetScript("OnHide", function() if not GUI.noClose and not GUI.switchingProfession then GUI.switchBtn:Hide() CloseTradeSkill() end end) priceTextCache.lastClear = 0 GUI.switchBtn:Update() if not GUI.frame then GUI:CreateGUI() if TSM.isSyncing then GUI.frame:Hide() return TSMAPI:CreateTimeDelay("craftingSyncDelay", 0.1, function() TSM.Sync:OpenTradeSkill() end) end elseif GUI.frame:IsVisible() then if TSM.isSyncing then GUI.frame:Hide() TSMAPI:CreateTimeDelay("craftingSyncDelay", 0.1, function() TSM.Sync:OpenTradeSkill() end) elseif not IsTradeSkillLinked() then GUI:SaveFilters() GUI:ClearFilters() GUI.frame.content.professionsTab.linkBtn:Enable() TSMAPI:CreateTimeDelay("craftingScanDelay", 0.1, TSM.Util.ScanCurrentProfession) else GUI.frame.content.professionsTab.linkBtn:Disable() end return end if TSM.isSyncing then TSMAPI:CreateTimeDelay("craftingScanDelay", 0, TSM.Util.StartScanSyncedProfessionThread) else GUI.frame:Show() GUI:ShowProfessionsTab() end if not IsTradeSkillLinked() then GUI:SaveFilters() GUI:ClearFilters() GUI.frame.content.professionsTab.linkBtn:Enable() TSMAPI:CreateTimeDelay("craftingScanDelay", 0.1, TSM.Util.ScanCurrentProfession) elseif not TSM.isSyncing then GUI.frame.content.professionsTab.linkBtn:Disable() end end function GUI:OpenFirstProfession() TSM.db.global.showingDefaultFrame = nil local link for playerName, professions in pairs(TSM.db.realm.tradeSkills) do for _, data in pairs(professions) do link = data.link if link then break end end if link then break end end if not link then return end local tradeString = strsub(select(3, ("|"):split(link)), 2) SetItemRef(tradeString, link, "LeftButton", ChatFrame1) end function GUI:EventHandler(event, ...) if not GUI.frame or not GUI.frame:IsVisible() then return end local unittest = ... if unittest == "player" or unittest==nil then --Changing tradeskill frames and stuff has "nil" unit, when other players cast this also triggers with nil if event == "TRADE_SKILL_CLOSE" then if GUI.switchingProfession then return end GUI.frame:Hide() elseif event == "TRADE_SKILL_UPDATE" or event == "TRADE_SKILL_FILTER_UPDATE" then if GetTradeSkillLine() ~= GUI.currentTradeSkill or select(2, IsTradeSkillLinked()) ~= GUI.currentLinkedPlayer then StopTradeSkillRepeat() GUI.currentTradeSkill = GetTradeSkillLine() GUI.currentLinkedPlayer = select(2, IsTradeSkillLinked()) end GUI.frame.content.professionsTab:UpdateProfession() if (event ~= "TRADE_SKILL_FILTER_UPDATE") and (GetTradeSkillSelectionIndex() > 1) and (GetTradeSkillSelectionIndex() <= GetNumTradeSkills()) then TradeSkillFrame_SetSelection(GetTradeSkillSelectionIndex()) else TradeSkillFrame_SetSelection(GetFirstTradeSkill()) end TradeSkillFrame_Update() TSMAPI:CreateTimeDelay("craftingProfessionUpdateThrottle", 0.2, GUI.UpdateProfessionsTabST) TSMAPI:CreateTimeDelay("craftingQueueUpdateThrottle", 0.2, GUI.UpdateQueue) if not private.shown[GetTradeSkillLine()] then TSMAPI:CreateTimeDelay("firstTimeCraftingProfessionUpdateThrottle", 0.5, GUI.UpdateProfessionsTabST) private.shown[GetTradeSkillLine()] = true end elseif event == "UPDATE_TRADESKILL_RECAST" then GUI.frame.content.professionsTab.craftInfoFrame.buttonsFrame.inputBox:SetNumber(GetTradeskillRepeatCount()) elseif event == "CHAT_MSG_SKILL" and not IsTradeSkillLinked() then local skillName, level, maxLevel = GetTradeSkillLine() if skillName and skillName ~= "UNKNOWN" and TSM.db.realm.tradeSkills[UnitName("player")] and TSM.db.realm.tradeSkills[UnitName("player")][skillName] then TSM.db.realm.tradeSkills[UnitName("player")][skillName].level = level TSM.db.realm.tradeSkills[UnitName("player")][skillName].maxLevel = maxLevel end elseif event == "UNIT_SPELLCAST_START" then local unit = ... if unit ~= "player" then return end TSM.currentspell = UnitCastingSpellID("player") elseif event == "UNIT_SPELLCAST_SUCCEEDED" then -- we only care about our spells local unit = ... if unit ~= "player" then return end -- if spell is not related to crafting, ignore local craft = TSM.currentspell and TSM.db.realm.crafts[TSM.currentspell] if not craft then return end -- if spellID == nil then -- TSM:Printf("Could not find spellID for %s", spellName) -- end -- decrements the number of this craft that are queued to be crafted craft.queued = craft.queued - 1 if GUI.isCrafting and GUI.isCrafting.quantity > 0 then GUI.isCrafting.quantity = GUI.isCrafting.quantity - 1 if GUI.isCrafting.quantity == 0 then --GUI:UpdateQueue() end end -- no longer casting a spell so discard spellID TSM.currentspell = nil -- TSMAPI:CreateTimeDelay("craftingQueueUpdateThrottle", 0.2, GUI.UpdateQueue) elseif event == "UNIT_SPELLCAST_INTERRUPTED" or event == "UNIT_SPELLCAST_FAILED" then local unit = ... if unit ~= "player" then return end -- if spellID == nil then -- TSM:Printf("Could not find spellID for %s", spellName) -- end if GUI.isCrafting and TSM.currentspell == GUI.isCrafting.spellID then GUI.isCrafting.quantity = 0 TSMAPI:CreateTimeDelay("craftingQueueUpdateThrottle", 0.2, GUI.UpdateQueue) end -- no longer casting a spell so discard spellID TSM.currentspell = nil end end end function GUI:UpdateTradeSkills(...) -- Get player name local playerName = UnitName("player") if not playerName then return end local filterTrade = ... -- only re-index the specific trade skill if told to local inProfessions = false local inSecondary = false local old = TSM.db.realm.tradeSkills[playerName] TSM.db.realm.tradeSkills[playerName] = TSM.db.realm.tradeSkills[playerName] or {} -- initialize player data if not found -- for each trade skill found, add it to the db for i = 1, GetNumSkillLines() do local skillName, _, _, skillRank, _, _, skillMaxRank = GetSkillLineInfo(i) if skillName == "Professions" then inProfessions = true elseif skillName == "Secondary Skills" then inProfessions = false inSecondary = true elseif skillName == "Weapon Skills" then inSecondary = false elseif inProfessions == true or inSecondary == true then if skillName ~= nil and (not filterTrade or filterTrade == skillName) and not invalidTrade[skillName] then -- if skillName == "Mining" then skillName = "Smelting" end -- bandaid for mining as related spell is different than craft TSM.db.realm.tradeSkills[playerName][skillName] = old[skillName] or {} TSM.db.realm.tradeSkills[playerName][skillName].level = skillRank TSM.db.realm.tradeSkills[playerName][skillName].maxLevel = skillMaxRank TSM.db.realm.tradeSkills[playerName][skillName].isSecondary = inSecondary -- local spellBookSlot = btns[i]:GetID() + btns[i]:GetParent().spellOffset local _, link = GetSpellLink(skillName) if link then TSM.db.realm.tradeSkills[playerName][skillName].link = link if skillName == GetTradeSkillLine() and inProfessions == true and not TSM.isSyncing then TSM.db.realm.tradeSkills[playerName][skillName].account = nil TSM.db.realm.tradeSkills[playerName][skillName].accountKey = TSMAPI.Sync:GetAccountKey() TSM.Sync:BroadcastTradeSkillData() end end end end end --tidy up crafts if player unlearned a profession for spellid, data in pairs(TSM.db.realm.crafts) do for player in pairs(data.players) do if not TSM.db.realm.tradeSkills[player] or not TSM.db.realm.tradeSkills[player][data.profession] then TSM.db.realm.crafts[spellid].players[player] = nil end end end --remove craft if no players for spellid, data in pairs(TSM.db.realm.crafts) do if not next(data.players) then TSM.db.realm.crafts[spellid] = nil end end end function GUI:SaveFilters() local filters = {} filters.search = GetTradeSkillItemNameFilter() filters.headers = {} local hasHeaderCollapsed for i = 1, GetNumTradeSkills() do local name, t, _, e = GetTradeSkillInfo(i) if t == "header" or t == "subheader" then filters.headers[name] = e if not e then hasHeaderCollapsed = true end end end if not hasHeaderCollapsed then filters.headers = nil end private.professionFilters = filters end function GUI:RestoreFilters() if not private.professionFilters then return end GUI:ClearFilters() SetTradeSkillItemNameFilter(private.professionFilters.search) if private.professionFilters.headers then for i = 1, GetNumTradeSkills() do local name, t, _, e = GetTradeSkillInfo(i) if t == "header" or t == "subheader" then if private.professionFilters.headers[name] ~= e then if private.professionFilters.headers[name] then ExpandTradeSkillSubClass(i) else CollapseTradeSkillSubClass(i) end end end end end if private.professionFilters.search then GUI.frame.content.professionsTab.searchBar:SetTextColor(1, 1, 1, 1) GUI.frame.content.professionsTab.searchBar:SetText(private.professionFilters.search) else GUI.frame.content.professionsTab.searchBar:SetTextColor(1, 1, 1, 0.5) GUI.frame.content.professionsTab.searchBar:SetText(SEARCH) end GUI.frame.content.professionsTab.searchBar:ClearFocus() end function GUI:ClearFilters() -- close the dropdown and uncheck the buttons CloseDropDownMenus() -- local id = TradeSkillLinkDropDown:GetID() -- local id = 1 -- local skillupButton = _G["DropDownList" .. id .. "Button1"] -- local makeableButton = _G["DropDownList" .. id .. "Button2"] -- if skillupButton and skillupButton.checked and skillupButton.value == CRAFT_IS_MAKEABLE then -- UIDropDownMenuButton_OnClick(_G["DropDownList" .. id .. "Button1"]) -- end -- if makeableButton and makeableButton.checked and makeableButton.value == TRADESKILL_FILTER_HAS_SKILL_UP then -- UIDropDownMenuButton_OnClick(_G["DropDownList" .. id .. "Button2"]) -- end -- TradeSkillOnlyShowMakeable(false) -- TradeSkillOnlyShowSkillUps(false) SetTradeSkillInvSlotFilter(0,1,1) SetTradeSkillSubClassFilter(0,1,1) GUI.frame.content.professionsTab.HaveMatsCheckBox:SetValue(false) TradeSkillFrameAvailableFilterCheckButton:SetChecked(false) TradeSkillOnlyShowMakeable(false) TradeSkillFrame_Update() -- TradeSkillSetFilter(-1, -1) SetTradeSkillItemNameFilter("") ExpandTradeSkillSubClass(0) for i = 1, GetNumTradeSkills() do local _, t, _, e = GetTradeSkillInfo(i) if not e and (t == "header" or t == "subheader") then ExpandTradeSkillSubClass(i) end end GUI.frame.content.professionsTab.searchBar:SetTextColor(1, 1, 1, 0.5) GUI.frame.content.professionsTab.searchBar:SetText(SEARCH) GUI.frame.content.professionsTab.searchBar:ClearFocus() end function GUI:CastTradeSkill(index, quantity, vellum) SelectTradeSkill(index) quantity = vellum and 1 or quantity DoTradeSkill(index, quantity) GUI.isCrafting = { quantity = quantity, spellID = TSM.Util:GetSpellID(index) } if vellum then UseItemByName(vellum) end end function GUI:ShowSwitchButton() if not GUI.switchBtn then local btn = TSMAPI.GUI:CreateButton(UIParent, 16) btn:SetText(TSMAPI.Design:GetInlineColor("link") .. DEFAULT .. "|r") btn.Update = function(self) self:Show() if TSM.db.global.showingDefaultFrame then self:SetParent(TradeSkillFrame) self:SetPoint("TOPLEFT", 55, -3) self:SetWidth(60) self:SetHeight(18) self:SetText(TSMAPI.Design:GetInlineColor("link") .. "TSM|r") else if not GUI.frame then return TSMAPI:CreateTimeDelay("craftingSwitchBtn", 0.05, function() self:Update() end) end self:SetParent(GUI.frame) self:SetPoint("TOPLEFT", 4, -4) self:SetWidth(60) self:SetHeight(18) self:SetText(TSMAPI.Design:GetInlineColor("advanced") .. DEFAULT .. "|r") end end btn:SetScript("OnClick", function(self) GUI.noClose = true if TSM.db.global.showingDefaultFrame then TSM.db.global.showingDefaultFrame = nil GUI:ShowProfessionWindow() else TSM.db.global.showingDefaultFrame = true ShowUIPanel(TradeSkillFrame) GUI.frame:Hide() end GUI.noClose = nil btn:Update() end) GUI.switchBtn = btn end GUI.switchBtn:Show() GUI.switchBtn:Update() end function GUI:CreateGUI() local frameDefaults = { x = 100, y = 300, width = 520, height = 500, scale = 1, } local frame = TSMAPI:CreateMovableFrame("TSMCraftingTradeSkillFrame", frameDefaults) frame:SetResizable(true) frame:SetMinResize(520, 400) TSMAPI.Design:SetFrameBackdropColor(frame) frame:Show() frame:SetScript("OnHide", function() if not GUI.noClose then GUI.switchBtn:Hide() TradeSkillFrame:Show() CloseTradeSkill() end end) tinsert(UISpecialFrames, "TSMCraftingTradeSkillFrame") GUI.frame = frame frame.prompt = GUI:CreatePromptFrame(frame) frame.queue = GUI:CreateQueueFrame(frame) frame.queue:Hide() frame.gather = GUI:CreateGatheringSelectionFrame(frame) frame.gather:Hide() GUI:UpdateGatherSelectionWindow() frame.navFrame = GUI:CreateNavFrame(frame) TSMAPI.GUI:CreateHorizontalLine(frame, -55) local content = CreateFrame("Frame", nil, frame) content:SetPoint("TOPLEFT", 0, -59) content:SetPoint("BOTTOMRIGHT") frame.content = content local line = TSMAPI.GUI:CreateVerticalLine(frame, 0) line:ClearAllPoints() line:SetPoint("TOPRIGHT", -25, -1) line:SetWidth(2) line:SetHeight(25) local closeBtn = TSMAPI.GUI:CreateButton(frame, 18) closeBtn:SetPoint("TOPRIGHT", -3, -3) closeBtn:SetWidth(19) closeBtn:SetHeight(19) closeBtn:SetText("X") closeBtn:SetScript("OnClick", function() frame:Hide() end) frame.closeBtn = closeBtn content.professionsTab = GUI:CreateProfessionsTab(content) content.groupsTab = GUI:CreateGroupsTab(content) end function GUI:CreateQueueFrame(parent) local frame = CreateFrame("Frame", nil, parent) frame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 2, 0) frame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 2, 0) frame:SetWidth(300) frame:EnableMouse(true) frame:SetScript("OnMouseDown", function() parent:StartMoving() end) frame:SetScript("OnMouseUp", function() parent:StopMovingOrSizing() end) TSMAPI.Design:SetFrameBackdropColor(frame) local stContainer = CreateFrame("Frame", nil, frame) stContainer:SetPoint("TOPLEFT", 5, -5) stContainer:SetPoint("BOTTOMRIGHT", frame, "RIGHT", -5, 5) TSMAPI.Design:SetFrameColor(stContainer) local stCols = { { name = L["Craft Queue"], width = 1, align = "Left" }, } local function OnCraftRowEnter(self, data) if not data.spellID then return end local color local totalProfit local moneyCoinsTooltip = TSMAPI:GetMoneyCoinsTooltip() if data.profit then totalProfit = data.numQueued * data.profit if data.profit < 0 then color = "|cffff0000" else color = "|cff00ff00" end end GameTooltip:SetOwner(self, "ANCHOR_NONE") -- GameTooltip:SetPoint("LEFT", self, "RIGHT") GameTooltip:SetPoint("LEFT", self, "LEFT") GameTooltip:AddLine(TSM.db.realm.crafts[data.spellID].name .. " (x" .. data.numQueued .. ")") local cost = TSM.Cost:GetCraftPrices(data.spellID) if data.profit then local profitPercent = data.profit / cost * 100 local profitPercText = format("%s%.0f%%|r", color, profitPercent) local profitPercentM = data.profit / cost * data.numQueued * 100 local profitPercTextM = format("%s%.0f%%|r", color, profitPercentM) if data.profit>0 then if moneyCoinsTooltip then GameTooltip:AddLine("Profit: " .. (TSMAPI:FormatTextMoneyIcon(data.profit, color) or "---") .. " (" .. (profitPercText or "---") .. ")") else GameTooltip:AddLine("Profit: " .. (TSMAPI:FormatTextMoney(data.profit, color) or "---") .. " (" .. (profitPercText or "---") .. ")") end if data.numQueued>1 then if moneyCoinsTooltip then GameTooltip:AddLine("Total Profit: " .. (TSMAPI:FormatTextMoneyIcon(totalProfit, color) or "---") .. " (" .. (profitPercTextM or "---") .. ")") else GameTooltip:AddLine("Total Profit: " .. (TSMAPI:FormatTextMoney(totalProfit, color) or "---") .. " (" .. (profitPercTextM or "---") .. ")") end end else if moneyCoinsTooltip then GameTooltip:AddLine("Loss: " .. (TSMAPI:FormatTextMoneyIcon(data.profit, color) or "---") .. " (" .. (profitPercText or "---") .. ")") else GameTooltip:AddLine("Loss: " .. (TSMAPI:FormatTextMoney(data.profit, color) or "---") .. " (" .. (profitPercText or "---") .. ")") end if data.numQueued>1 then if moneyCoinsTooltip then GameTooltip:AddLine("Total Loss: " .. (TSMAPI:FormatTextMoneyIcon(totalProfit, color) or "---") .. " (" .. (profitPercTextM or "---") .. ")") else GameTooltip:AddLine("Total Loss: " .. (TSMAPI:FormatTextMoney(totalProfit, color) or "---") .. " (" .. (profitPercTextM or "---") .. ")") end end end end GameTooltip:AddLine(" ") if moneyCoinsTooltip then GameTooltip:AddLine("Crafting Cost: " .. (TSMAPI:FormatTextMoneyIcon(cost, "|cffffff00") or "---")) else GameTooltip:AddLine("Crafting Cost: " .. (TSMAPI:FormatTextMoney(cost, "|cffffff00") or "---")) end if data.numQueued>1 then local totalcost = cost and cost * data.numQueued if moneyCoinsTooltip then GameTooltip:AddLine("Total Cost: " .. (TSMAPI:FormatTextMoneyIcon(totalcost, "|cffffff00") or "---")) else GameTooltip:AddLine("Total Cost: " .. (TSMAPI:FormatTextMoney(totalcost, "|cffffff00") or "---")) end end for itemID, matQuantity in pairs(TSM.db.realm.crafts[data.spellID].mats) do local name = TSMAPI:GetSafeItemInfo(itemID) or (TSM.db.realm.mats[itemID] and TSM.db.realm.mats[itemID].name) or "?" local itemIDx = itemID -- Get Cheapest vellum, lower vellum types can be replaced by III local velName if strfind(name, "Vellum") then velName = name end if (velName ~= nil) then if strfind(velName, "Weapon") then itemIDx = "item:52511:0:0:0:0:0:0" name = TSMAPI:GetSafeItemInfo(itemIDx) else itemIDx = "item:52510:0:0:0:0:0:0" name = TSMAPI:GetSafeItemInfo(itemIDx) end end local inventory = TSM.Inventory:GetPlayerBagNum(itemIDx) local need = matQuantity * data.numQueued local color if inventory >= need then color = "|cff00ff00" else color = "|cffff0000" end name = color .. inventory .. "/" .. need .. "|r " .. name GameTooltip:AddLine(name, 1, 1, 1) end GameTooltip:Show() end local function OnCraftRowLeave() GameTooltip:Hide() end local function OnCraftRowClicked(_, data, _, button) if button == "RightButton" and data.index then if data.profession == GetTradeSkillLine() then TradeSkillFrame_SetSelection(data.index) TradeSkillFrame_Update() GUI:UpdateSelectedTradeSkill(true) GUI.frame.content.professionsTab.st:SetScrollOffset(max(0, data.index - 1)) end else if data.isTitle then if data.stage then TSM.db.realm.queueStatus.collapsed[data.profession .. data.stage] = not TSM.db.realm.queueStatus.collapsed[data.profession .. data.stage] else TSM.db.realm.queueStatus.collapsed[data.profession] = not TSM.db.realm.queueStatus.collapsed[data.profession] end GUI:UpdateQueue() elseif data.index then GUI:CastTradeSkill(data.index, min(data.canCraft, data.numQueued), data.velName) end end end frame.craftST = TSMAPI:CreateScrollingTable(stContainer, stCols, { OnClick = OnCraftRowClicked, OnEnter = OnCraftRowEnter, OnLeave = OnCraftRowLeave }, 14) frame.craftST:SetData({}) frame.craftST:DisableSelection(true) local line = TSMAPI.GUI:CreateHorizontalLine(frame, 0) local height = line:GetHeight() line:ClearAllPoints() line:SetPoint("LEFT") line:SetPoint("RIGHT") line:SetHeight(height) local stContainer2 = CreateFrame("Frame", nil, frame) stContainer2:SetPoint("TOPLEFT", frame, "LEFT", 5, -5) stContainer2:SetPoint("BOTTOMRIGHT", -5, 68) TSMAPI.Design:SetFrameColor(stContainer2) local line = TSMAPI.GUI:CreateHorizontalLine(frame, 0) local height = line:GetHeight() line:ClearAllPoints() line:SetPoint("BOTTOMLEFT", 0, 63) line:SetPoint("BOTTOMRIGHT", 0, 63) line:SetHeight(height) local stCols = { { name = L["Material Name"], width = 0.49, align = "Left" }, { name = L["Need"], width = 0.115, align = "LEFT" }, { name = L["Total"], width = 0.115, align = "LEFT" }, { name = L["Cost"], width = 0.28, align = "LEFT" }, } local function MatOnEnter(_, data, col) GameTooltip:SetOwner(col, "ANCHOR_RIGHT") TSMAPI:SafeTooltipLink(data.itemString) GameTooltip:Show() end local function MatOnLeave(_, data) GameTooltip:Hide() end local function MatOnClick(_, data) if IsModifiedClick() then local link = select(2, TSMAPI:GetSafeItemInfo(data.itemString)) HandleModifiedItemClick(link or data.itemString) end end frame.matST = TSMAPI:CreateScrollingTable(stContainer2, stCols, { OnEnter = MatOnEnter, OnLeave = MatOnLeave, OnClick = MatOnClick }, 12) frame.matST:SetData({}) frame.matST:DisableSelection(true) local profitLabel = TSMAPI.GUI:CreateLabel(frame, "medium") profitLabel:SetPoint("TOPLEFT", stContainer2, "BOTTOMLEFT", 0, -7) profitLabel:SetPoint("TOPRIGHT", stContainer2, "BOTTOMRIGHT", 0, -7) profitLabel:SetJustifyH("LEFT") profitLabel:SetJustifyV("CENTER") profitLabel.SetAmounts = function(self, cost, profit) if type(cost) == "number" then cost = TSMAPI:FormatTextMoney(cost, TSMAPI.Design:GetInlineColor("link")) else cost = TSMAPI.Design:GetInlineColor("link") .. "---|r" end if type(profit) == "number" then if profit < 0 then profit = "|cffff0000-|r" .. TSMAPI:FormatTextMoney(-profit, "|cffff0000") else profit = TSMAPI:FormatTextMoney(profit, "|cff00ff00") end else profit = TSMAPI.Design:GetInlineColor("link") .. "---|r" end self:SetText(format(L["Estimated Cost: %s\nEstimated Profit: %s"], cost, profit)) end profitLabel:SetAmounts("---", "---") frame.profitLabel = profitLabel local line = TSMAPI.GUI:CreateHorizontalLine(frame, 0) local height = line:GetHeight() line:ClearAllPoints() line:SetPoint("BOTTOMLEFT", 0, 28) line:SetPoint("BOTTOMRIGHT", 0, 28) line:SetHeight(height) local btn = TSMAPI.GUI:CreateButton(frame, 14) btn:SetPoint("BOTTOMLEFT", 5, 5) btn:SetWidth(120) btn:SetHeight(20) btn:SetText(L["Clear Queue"]) btn:SetScript("OnClick", function() TSM.Queue:ClearQueue() GUI:UpdateQueue() if GUI.frame.gather:IsVisible() then GUI.frame.gather:Hide() end private.gather = {} GUI:UpdateGatherSelectionWindow() if GUI.gatheringFrame:IsShown() then GUI.gatheringFrame:Hide() TSM.db.realm.gathering.crafter = nil TSM.db.realm.gathering.neededMats = {} TSM.db.realm.gathering.gatheredMats = false TSM.db.realm.sourceStatus.collapsed = {} end end) frame.clearBtn = btn local btn = TSMAPI.GUI:CreateButton(frame, 18, "TSMCraftNextButton") btn:SetPoint("BOTTOMLEFT", frame.clearBtn, "BOTTOMRIGHT", 5, 0) btn:SetPoint("BOTTOMRIGHT", -5, 5) btn:SetHeight(20) btn:SetText(L["Craft Next"]) -- btn:SetScript("OnUpdate", function(self) -- if UnitCastingInfo("player") or not GUI.craftNextInfo then -- self:Disable() -- elseif GUI.isCrafting and GUI.isCrafting.quantity > 0 then -- self:Disable() -- else -- self:Enable() -- end -- end) btn:SetScript("OnClick", function(self) if UnitCastingInfo("player") or not GUI.craftNextInfo or not self:IsVisible() then return end GUI:CastTradeSkill(GUI.craftNextInfo.index, GUI.craftNextInfo.quantity, GUI.craftNextInfo.velName) self:Disable() end) frame.craftNextbtn = btn return frame end function GUI:CreateNavFrame(frame) local navFrame = CreateFrame("Frame", nil, frame) navFrame:SetPoint("TOPLEFT", 0, -25) navFrame:SetPoint("TOPRIGHT", 0, -25) navFrame:SetHeight(30) TSMAPI.GUI:CreateHorizontalLine(frame, -25) local title = navFrame:CreateFontString() title:SetFont(TSMAPI.Design:GetContentFont(), 18) TSMAPI.Design:SetWidgetLabelColor(title) title:SetPoint("TOP", frame, 0, -3) local version = TSM._version if strfind(version, "@") then version = "Dev" end title:SetText(format("TSM_Crafting - %s", version)) local btn = TSMAPI.GUI:CreateButton(navFrame, 16) btn:SetPoint("TOPLEFT", 5, -5) btn:SetPoint("BOTTOMLEFT", 5, 5) btn:SetWidth(105) btn:SetText(L["Professions"]) btn:SetScript("OnClick", GUI.ShowProfessionsTab) navFrame.professionsBtn = btn local btn = TSMAPI.GUI:CreateButton(navFrame, 16) btn:SetPoint("TOPLEFT", navFrame.professionsBtn, "TOPRIGHT", 5, 0) btn:SetPoint("BOTTOMLEFT", navFrame.professionsBtn, "BOTTOMRIGHT", 5, 0) btn:SetWidth(105) btn:SetText(L["TSM Groups"]) btn:SetScript("OnClick", GUI.ShowGroupsTab) navFrame.groupsBtn = btn TSMAPI.GUI:CreateVerticalLine(navFrame, 224) local btn = TSMAPI.GUI:CreateButton(navFrame, 16) btn:SetPoint("TOPLEFT", navFrame.groupsBtn, "TOPRIGHT", 10, 0) btn:SetPoint("BOTTOMLEFT", navFrame.groupsBtn, "BOTTOMRIGHT", 10, 0) btn:SetWidth(60) btn:SetText(L["Gather"]) btn:SetScript("OnClick", function(self) local queuedCrafts = TSM.Queue:GetQueue() if not next(queuedCrafts) then return end if GUI.frame.queue:IsVisible() then GUI.frame.gather:SetPoint("TOPLEFT", GUI.frame.queue, "TOPRIGHT", 2, 0) else GUI.frame.gather:SetPoint("TOPLEFT", frame, "TOPRIGHT", 2, 0) end if GUI.frame.gather:IsVisible() then GUI.frame.gather:Hide() else GUI.frame.gather:Show() GUI:UpdateGatherSelectionWindow() end end) navFrame.gatherBtn = btn TSMAPI.GUI:CreateVerticalLine(navFrame, 294) local btn = TSMAPI.GUI:CreateButton(navFrame, 16) btn:Hide() btn:SetPoint("TOPLEFT", navFrame.gatherBtn, "TOPRIGHT", 10, 0) btn:SetPoint("BOTTOMLEFT", navFrame.gatherBtn, "BOTTOMRIGHT", 10, 0) btn:SetPoint("TOPRIGHT", -5, -5) btn.UpdateQueueStatus = function(self) if TSM.db.global.frameQueueOpen then GUI.frame.queue:Show() self:SetText(L["<< Hide Queue"]) GUI:UpdateQueue() if GUI.frame.gather:IsVisible() then GUI.frame.gather:SetPoint("TOPLEFT", GUI.frame.queue, "TOPRIGHT", 2, 0) end else GUI.frame.queue:Hide() self:SetText(L["Show Queue >>"]) if GUI.frame.gather:IsVisible() then GUI.frame.gather:SetPoint("TOPLEFT", frame, "TOPRIGHT", 2, 0) end end end btn:SetScript("OnClick", function(self) if GUI.frame.queue:IsVisible() then TSM.db.global.frameQueueOpen = nil else TSM.db.global.frameQueueOpen = true end self:UpdateQueueStatus() end) btn:SetScript("OnShow", btn.UpdateQueueStatus) btn:Show() navFrame.queueBtn = btn return navFrame end local QuickRestock = false function GUI:CreateProfessionsTab(parent) local frame = CreateFrame("Frame", nil, parent) frame:SetAllPoints() frame:Hide() local currentSelection local player = UnitName("player") local function SetNoClose() GUI.noClose = true GUI.switchingProfession = true TSMAPI:CreateTimeDelay("craftingNoCloseClear", 0.6, function() GUI.noClose = nil end) TSMAPI:CreateTimeDelay("craftingSwitchingClear", 0.8, function() GUI.switchingProfession = nil end) end local function SelectSpellInProfession(profession, spellID) if GetTradeSkillLine() ~= profession then local link = TSM.db.realm.tradeSkills[player] and TSM.db.realm.tradeSkills[player][profession] and TSM.db.realm.tradeSkills[player][profession].link if not link then return end local tradeString = strsub(select(3, ("|"):split(link)), 2) SetNoClose() SetItemRef(tradeString, link, "LeftButton", ChatFrame1) return end for i = 1, GetNumTradeSkills() do if TSM.Util:GetSpellID(i) == spellID then TradeSkillFrame_SetSelection(i) TradeSkillFrame_Update() GUI:UpdateSelectedTradeSkill(true) return end end end local HaveMatsCheckBox local function UpdateProfession(self) local list = {} list["ALL"] = L["All Professions"] for playerName, professionData in pairs(TSM.db.realm.tradeSkills) do for name, data in pairs(professionData) do if playerName == player then -- only display current player profs until blizz fix it list[playerName .. "~" .. name] = format("%s %d/%d - %s", name, data.level or "?", data.maxLevel or "?", playerName) end end end self.dropdown:SetList(list) if TSM.db.global.showAllProfessions then self.dropdown:SetValue("ALL") self.dropdown:SetText(L["All Professions"]) return end local playerName = select(2, IsTradeSkillLinked()) or player local professionName, level, maxLevel = GetTradeSkillLine() local professionString = format("%s %d/%d - %s", professionName, level, maxLevel, playerName) currentSelection = playerName .. "~" .. professionName self.dropdown:SetValue(currentSelection) if not list[playerName .. "~" .. professionName] then self.dropdown:SetText(professionString) end end frame.UpdateProfession = UpdateProfession frame:SetScript("OnShow", UpdateProfession) local function OnValueChanged(_, _, index) if index == "ALL" then TSM.db.global.showAllProfessions = true frame:UpdateProfession() GUI:UpdateProfessionsTabST() return end if TSM.db.global.showAllProfessions then SetNoClose() TSM.db.global.showAllProfessions = false end local playerName, profession = ("~"):split(index) local currentPlayer = select(2, IsTradeSkillLinked()) or player local currentProfession = GetTradeSkillLine() if playerName == currentPlayer and profession == currentProfession then frame:UpdateProfession() GUI:ShowProfessionsTab() currentSelection = index return end if playerName == player then local link = TSM.db.realm.tradeSkills[playerName] and TSM.db.realm.tradeSkills[playerName][profession] and TSM.db.realm.tradeSkills[playerName][profession].link if not link then TSM:Printf(L["Profession data not found for %s on %s. Logging into this player and opening the profession may solve this issue."], profession, playerName) return OnValueChanged(_, _, currentSelection) end local tradeString = strsub(select(3, ("|"):split(link)), 2) SetNoClose() SetItemRef(tradeString, link, "LeftButton", ChatFrame1) else local link = TSM.db.realm.tradeSkills[playerName][profession].link if not link then TSM:Printf(L["Profession data not found for %s on %s. Logging into this player and opening the profession may solve this issue."], profession, playerName) return OnValueChanged(_, _, currentSelection) end local tradeString = strsub(select(3, ("|"):split(link)), 2) SetNoClose() SetItemRef(tradeString, link, "LeftButton", ChatFrame1) end currentSelection = index end local dd = TSMAPI.GUI:CreateDropdown(frame, {}, L["Select one of your characters' professions to browse."]) dd.frame:SetPoint("TOPLEFT", 3, -4) -- dd.frame:SetPoint("TOPRIGHT", -47, -4) dd.frame:SetWidth(256) dd:SetCallback("OnValueChanged", OnValueChanged) frame.dropdown = dd HaveMatsCheckBox = TSMAPI.GUI:CreateCheckBox(frame) HaveMatsCheckBox:SetLabel(" Have Mats") HaveMatsCheckBox:SetPoint("TOPLEFT", 252, -4) HaveMatsCheckBox:SetWidth(90) HaveMatsCheckBox:SetHeight(26) frame.HaveMatsCheckBox = HaveMatsCheckBox HaveMatsCheckBox:SetCallback("OnValueChanged", function(_, _, value) if TSM.db.global.showAllProfessions then GUI:UpdateProfessionsTabST() else TradeSkillFrameAvailableFilterCheckButton:SetChecked(value) TradeSkillOnlyShowMakeable(value) end end) local RestockBtn = TSMAPI.GUI:CreateButton(frame, 14) RestockBtn:SetPoint("TOPRIGHT", -50, -4) RestockBtn:SetWidth(56) RestockBtn:SetHeight(26) RestockBtn:SetText("Restock") RestockBtn:SetScript("OnClick", function(self) QuickRestock = true GUI.ShowGroupsTab() end) frame.restockBtn = RestockBtn local linkBtn = TSMAPI.GUI:CreateButton(frame, 14) linkBtn:SetPoint("TOPRIGHT", -5, -4) linkBtn:SetWidth(40) linkBtn:SetHeight(26) linkBtn:SetText(L["Link"]) linkBtn:SetScript("OnClick", function(self) local link = GetTradeSkillListLink() if not link then return TSM:Print(L["Could not get link for profession."]) end local activeEditBox = ChatEdit_GetActiveWindow() if MacroFrameText and MacroFrameText:IsShown() and MacroFrameText:HasFocus() then local text = MacroFrameText:GetText() .. link if strlenutf8(text) <= 255 then MacroFrameText:Insert(link) end elseif activeEditBox then ChatEdit_InsertLink(link) end end) frame.linkBtn = linkBtn local function InsertLink(link) local putIntoChat, v1, v2, v3 = GUI.hooks.ChatEdit_InsertLink(link) local hoverButton = GetMouseFocus() if not putIntoChat and frame:IsVisible() and not (hoverButton and hoverButton:GetName() and strfind(hoverButton:GetName(), "MerchantItem([0-9]+)ItemButton")) then local name = TSMAPI:GetSafeItemInfo(link) if name then frame.searchBar:SetText(name) frame.searchBar:SetTextColor(1, 1, 1, 1) return true end end return putIntoChat end GUI:RawHook("ChatEdit_InsertLink", InsertLink, true) local searchBar = TSMAPI.GUI:CreateInputBox(frame, "TSMCraftingSearchBar") searchBar:SetPoint("TOPLEFT", 5, -35) searchBar:SetWidth(220) --(240) searchBar:SetHeight(24) searchBar:SetText(SEARCH) searchBar:SetTextColor(1, 1, 1, 0.5) searchBar:SetScript("OnEditFocusGained", function(self) self:SetTextColor(1, 1, 1, 1) if self:GetText() == SEARCH then self:SetText("") end end) searchBar:SetScript("OnEditFocusLost", function(self) if self:GetText() == "" or self:GetText() == SEARCH then self:SetTextColor(1, 1, 1, 0.5) self:SetText(SEARCH) end end) searchBar:SetScript("OnTextChanged", function(self) local text = self:GetText() if not TSM.db.global.showAllProfessions then SetTradeSkillItemNameFilter(text == SEARCH and "" or text) end GUI:UpdateProfessionsTabST() end) searchBar:SetScript("OnEnterPressed", searchBar.ClearFocus) frame.searchBar = searchBar local btn = TSMAPI.GUI:CreateButton(frame, 14) btn:SetPoint("TOPLEFT", searchBar, "TOPRIGHT", 5, 0) btn:SetWidth(80) btn:SetHeight(24) btn:SetText(L["Clear Filters"]) btn:SetScript("OnClick", GUI.ClearFilters) frame.clearFilterBtn = btn -- local btn = TSMAPI.GUI:CreateButton(frame, 14, "TSMCraftingFilterButton") -- btn:SetPoint("TOPLEFT", frame.clearFilterBtn, "TOPRIGHT", 5, 0) -- btn:SetPoint("TOPRIGHT", -5, -35) -- btn:SetHeight(24) -- btn:SetText(L["Filters >>"]) -- btn:SetScript("OnClick", function(self) ToggleDropDownMenu(1, nil, TradeSkillFilterDropDown, "TSMCraftingFilterButton", btn:GetWidth(), 0) end) -- frame.filterBtn = btn local btn = TSMAPI.GUI:CreateButton(frame, 14, "TSMCraftingFilterButton") btn:SetPoint("TOPLEFT", frame.clearFilterBtn, "TOPRIGHT", 5, 0) btn:SetWidth(80) btn:SetHeight(24) btn:SetText("Subclass >>") btn:SetScript("OnClick", function(self) ToggleDropDownMenu(1, nil, TradeSkillSubClassDropDown, "TSMCraftingFilter2Button", -84, 0) end) frame.filterBtn = btn local btn = TSMAPI.GUI:CreateButton(frame, 14, "TSMCraftingFilter2Button") btn:SetPoint("TOPLEFT", frame.filterBtn, "TOPRIGHT", 5, 0) btn:SetPoint("TOPRIGHT", -5, -35) btn:SetHeight(24) btn:SetText("Slot >>") btn:SetScript("OnClick", function(self) ToggleDropDownMenu(1, nil, TradeSkillInvSlotDropDown, "TSMCraftingFilter2Button", 0, 0) end) frame.filter2Btn = btn TSMAPI.GUI:CreateHorizontalLine(frame, -64) local function OnSTRowClick(_, data, _, button) if TSM.db.global.showAllProfessions and data.spellID then if IsModifiedClick() then local itemID = TSM.db.realm.crafts[data.spellID] and TSM.db.realm.crafts[data.spellID].itemID if itemID then HandleModifiedItemClick(itemID) end else SelectSpellInProfession(data.profession, data.spellID) end return elseif data.isCollapseAll then TradeSkillCollapseAllButton:Click() GUI:UpdateProfessionsTabST() elseif button == "LeftButton" then if IsModifiedClick() then HandleModifiedItemClick(GetTradeSkillRecipeLink(data.index)) else TradeSkillFrame_SetSelection(data.index) TradeSkillFrame_Update() GUI:UpdateSelectedTradeSkill(true) end end end local function OnSTColumnClick(self) if TSM.db.global.showAllProfessions then local sortKey if self.colNum == 1 then sortKey = "available" elseif self.colNum == 3 then sortKey = "cost" elseif self.colNum == 4 then sortKey = "profit" elseif self.colNum == 5 then sortKey = "profitPercent" end if sortKey then if TSM.db.global.showAllProfessionsSortKey ~= sortKey then TSM.db.global.showAllProfessionsSortKey = sortKey TSM.db.global.showAllProfessionsSortDescending = true else TSM.db.global.showAllProfessionsSortDescending = not TSM.db.global.showAllProfessionsSortDescending end GUI:UpdateProfessionsTabST() end end end local stContainer = CreateFrame("Frame", nil, frame) stContainer:SetPoint("TOPLEFT", 5, -70) stContainer:SetPoint("BOTTOMRIGHT", -5, 150) -- 177) frame.stContainer = stContainer TSMAPI.Design:SetFrameColor(stContainer) local stCols = { { name = "#", width = 0.08, align = "LEFT", headAlign = "LEFT" }, { name = L["Name"], width = 0.40, align = "LEFT", headAlign = "LEFT" }, { name = L["Cost"], width = 0.16, align = "LEFT", headAlign = "LEFT" }, { name = L["Profit"], width = 0.18, align = "LEFT", headAlign = "LEFT" }, { name = "%", width = 0.08, align = "LEFT", headAlign = "LEFT" } } frame.st = TSMAPI:CreateScrollingTable(stContainer, stCols, { OnClick = OnSTRowClick, OnColumnClick = OnSTColumnClick }) frame.craftInfoFrame = GUI:CreateCraftInfoFrame(frame) return frame end function GUI:CreateCraftInfoFrame(parent) local frame = CreateFrame("Frame", nil, parent) frame:SetPoint("TOPLEFT", parent.stContainer, "BOTTOMLEFT", 0, -4) frame:SetPoint("BOTTOMRIGHT", -3, 3) TSMAPI.Design:SetFrameColor(frame) local function OnClick() if not frame.index then return end HandleModifiedItemClick(GetTradeSkillItemLink(frame.index)) end local function OnEnter(self) if not frame.index then return end local spellID = TSM.Util:GetSpellID(frame.index) local itemID = spellID and TSM.db.realm.crafts[spellID] and TSM.db.realm.crafts[spellID].itemID if itemID then GameTooltip:SetOwner(self, "ANCHOR_RIGHT") TSMAPI:SafeTooltipLink(itemID) else GameTooltip:SetOwner(self, "ANCHOR_RIGHT") GameTooltip:SetTradeSkillItem(frame.index) end end local function OnLeave() if not frame.index then return end GameTooltip:Hide() end local infoFrame = CreateFrame("Frame", nil, frame) infoFrame:SetPoint("TOPLEFT", 3, -3) infoFrame:SetPoint("BOTTOMLEFT", 3, 53) infoFrame:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -220, -3) frame.infoFrame = infoFrame local iconBtn = CreateFrame("Button", nil, infoFrame) iconBtn:SetPoint("TOPLEFT") iconBtn:SetWidth(32) --40 iconBtn:SetHeight(32) --40 iconBtn:SetScript("OnClick", OnClick) iconBtn:SetScript("OnEnter", OnEnter) iconBtn:SetScript("OnLeave", OnLeave) infoFrame.iconBtn = iconBtn local icon = iconBtn:CreateTexture() icon:SetAllPoints() infoFrame.icon = icon local nameText = infoFrame:CreateFontString() nameText:SetPoint("TOPLEFT", icon, "TOPRIGHT", 4, 0) nameText:SetPoint("TOPRIGHT") nameText:SetJustifyH("LEFT") nameText:SetFont(TSMAPI.Design:GetContentFont("small")) infoFrame.nameText = nameText local toolsText = infoFrame:CreateFontString() toolsText:SetPoint("TOPLEFT", nameText, "BOTTOMLEFT", 0, -2) toolsText:SetPoint("TOPRIGHT", nameText, "BOTTOMRIGHT", 0, -2) toolsText:SetJustifyH("LEFT") toolsText:SetFont(TSMAPI.Design:GetContentFont("small")) infoFrame.toolsText = toolsText local cooldownText = infoFrame:CreateFontString() cooldownText:SetPoint("TOPLEFT", toolsText, "BOTTOMLEFT", 0, -2) cooldownText:SetPoint("TOPRIGHT", toolsText, "BOTTOMRIGHT", 0, -2) cooldownText:SetJustifyH("LEFT") cooldownText:SetFont(TSMAPI.Design:GetContentFont("small")) cooldownText:SetTextColor(1, 0, 0, 1) infoFrame.cooldownText = cooldownText local descText = infoFrame:CreateFontString() descText:SetPoint("TOPLEFT", iconBtn, "BOTTOMLEFT", 0, -2) descText:SetPoint("BOTTOMRIGHT") descText:SetFont(TSMAPI.Design:GetContentFont("small")) descText:SetJustifyH("LEFT") descText:SetJustifyV("TOP") infoFrame.descText = descText local vBar = TSMAPI.GUI:CreateVerticalLine(frame, infoFrame:GetWidth() + 3) vBar:ClearAllPoints() vBar:SetPoint("TOPLEFT", infoFrame, "TOPRIGHT", 3, 3) vBar:SetPoint("BOTTOMLEFT", infoFrame, "BOTTOMRIGHT", 3, -53) TSMAPI.GUI:CreateHorizontalLine(infoFrame, -infoFrame:GetHeight()) local matsFrame = CreateFrame("Frame", nil, frame) matsFrame:SetPoint("TOPLEFT", infoFrame, "TOPRIGHT", 5, 0) matsFrame:SetPoint("TOPRIGHT") matsFrame:SetPoint("BOTTOMRIGHT") frame.matsFrame = matsFrame local function Sizer_OnMouseUp() GUI.frame:StopMovingOrSizing() end local function Sizer_OnMouseDown() GUI.frame:StartSizing("BOTTOMRIGHT") end local sizer = CreateFrame("Frame", nil, frame) sizer:SetPoint("BOTTOMRIGHT", -2, 2) sizer:SetWidth(16) sizer:SetHeight(16) sizer:EnableMouse() sizer:SetScript("OnMouseDown", Sizer_OnMouseDown) sizer:SetScript("OnMouseUp", Sizer_OnMouseUp) local image = sizer:CreateTexture(nil, "BACKGROUND") image:SetAllPoints() image:SetTexture("Interface\\Addons\\TradeSkillMaster\\Media\\Sizer") local castText = frame:CreateFontString() castText:SetPoint("BOTTOMRIGHT", GUI.frame, -22, 3) castText:SetHeight(18) castText:SetJustifyH("RIGHT") castText:SetJustifyV("BOTTOM") castText:SetFont(TSMAPI.Design:GetContentFont("small")) castText.timeout = 0 castText.endTime = 0 castText.UpdateTime = function() local startTime, endTime, isTradeSkill = select(5, UnitCastingInfo("player")) if isTradeSkill then local timePerCraft = endTime - startTime endTime = endTime + (timePerCraft * (GetTradeskillRepeatCount() - 1)) castText.endTime = ceil(endTime / 1000) elseif not startTime then -- not casting a tradeskill if castText.endTime > GetTime() then castText.timeout = castText.timeout + 1 if castText.timeout > 3 then castText.endTime = 0 castText.timeout = 0 end else castText.timeout = 0 end end if castText.endTime > GetTime() then castText:SetText(TSM.Util:FormatTime(castText.endTime - GetTime())) else castText:SetText() end end TSMAPI:CreateTimeDelay("craftTimeText", 0.5, castText.UpdateTime, 0.5) matsFrame.castText = castText local matsText = matsFrame:CreateFontString() matsText:SetPoint("TOPLEFT") matsText:SetPoint("TOPRIGHT") matsText:SetFont(TSMAPI.Design:GetContentFont(), 13) matsText:SetJustifyH("LEFT") matsText:SetJustifyV("TOP") matsText:SetText(TSMAPI.Design:GetInlineColor("link") .. L["Materials:"] .. "|r") matsFrame.matsText = matsText local reagentButtons = {} for i = 1, MAX_TRADE_SKILL_REAGENTS do local btn = TSMAPI.GUI:CreateItemLinkLabel(matsFrame, 13) if i == 1 then btn:SetPoint("TOPLEFT", 0, -15) btn:SetPoint("TOPRIGHT", 0, -15) else btn:SetPoint("TOPLEFT", reagentButtons[i - 1], "BOTTOMLEFT", 0, -3) btn:SetPoint("TOPRIGHT", reagentButtons[i - 1], "BOTTOMRIGHT", 0, -3) end tinsert(reagentButtons, btn) end matsFrame.reagentButtons = reagentButtons local buttonsFrame = CreateFrame("Frame", nil, frame) buttonsFrame:SetPoint("TOPRIGHT", infoFrame, "BOTTOMRIGHT", -2, -5) buttonsFrame:SetPoint("BOTTOMLEFT", 2, 2) frame.buttonsFrame = buttonsFrame local lessBtn = CreateFrame("Button", nil, buttonsFrame) lessBtn:SetWidth(28) lessBtn:SetHeight(28) lessBtn:SetPoint("TOPLEFT", -4, 4) lessBtn:SetNormalTexture("Interface\\Buttons\\UI-SpellbookIcon-PrevPage-Up") lessBtn:SetPushedTexture("Interface\\Buttons\\UI-SpellbookIcon-PrevPage-Down") lessBtn:SetDisabledTexture("Interface\\Buttons\\UI-SpellbookIcon-PrevPage-DisabledTexture") lessBtn:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight") lessBtn:SetScript("OnClick", function() local num = buttonsFrame.inputBox:GetNumber() - 1 buttonsFrame.inputBox:SetNumber(max(num, 1)) end) buttonsFrame.lessBtn = lessBtn local inputBox = TSMAPI.GUI:CreateInputBox(buttonsFrame, "TSMCraftingCreateInputBox") inputBox:SetPoint("TOPLEFT", lessBtn, "TOPRIGHT", -2, -4) inputBox:SetPoint("BOTTOMLEFT", lessBtn, "BOTTOMRIGHT", -2, 4) inputBox:SetWidth(40) inputBox:SetScript("OnEditFocusGained", function(self) self:HighlightText() end) buttonsFrame.inputBox = inputBox local moreBtn = CreateFrame("Button", nil, buttonsFrame) moreBtn:SetWidth(28) moreBtn:SetHeight(28) moreBtn:SetPoint("TOPLEFT", inputBox, "TOPRIGHT", -2, 4) moreBtn:SetPoint("BOTTOMLEFT", inputBox, "BOTTOMRIGHT", -2, -4) moreBtn:SetNormalTexture("Interface\\Buttons\\UI-SpellbookIcon-NextPage-Up") moreBtn:SetPushedTexture("Interface\\Buttons\\UI-SpellbookIcon-NextPage-Down") moreBtn:SetDisabledTexture("Interface\\Buttons\\UI-SpellbookIcon-NextPage-DisabledTexture") moreBtn:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight") moreBtn:SetScript("OnClick", function() local num = buttonsFrame.inputBox:GetNumber() + 1 buttonsFrame.inputBox:SetNumber(max(num, 1)) end) buttonsFrame.moreBtn = moreBtn local queueBtn = TSMAPI.GUI:CreateButton(buttonsFrame, 15) queueBtn:SetText(L["Queue"]) queueBtn:SetPoint("TOPLEFT", moreBtn, "TOPRIGHT", 0, -4) queueBtn:SetPoint("BOTTOMLEFT", moreBtn, "BOTTOMRIGHT", 0, 4) queueBtn:SetPoint("TOPRIGHT") queueBtn:RegisterForClicks("AnyUp") queueBtn:SetScript("OnClick", function(_, button) local spellID = TSM.Util:GetSpellID(frame.index) if not spellID or not TSM.db.realm.crafts[spellID] then return end TSM.db.realm.crafts[spellID].queued = max(TSM.db.realm.crafts[spellID].queued, 0) if button == "LeftButton" then if IsModifiedClick() then TSM.db.realm.crafts[spellID].queued = select(3, GetTradeSkillInfo(frame.index)) or 0 else TSM.db.realm.crafts[spellID].queued = (TSM.db.realm.crafts[spellID].queued or 0) + buttonsFrame.inputBox:GetNumber() end elseif button == "RightButton" then if IsModifiedClick() then TSM.db.realm.crafts[spellID].queued = 0 else TSM.db.realm.crafts[spellID].queued = max((TSM.db.realm.crafts[spellID].queued or 0) - buttonsFrame.inputBox:GetNumber(), 0) end end GUI:UpdateQueue() end) local color = TSMAPI.Design:GetInlineColor("link") local tooltipLines = { color .. L["Left-Click|r to add this craft to the queue."], color .. L["Shift-Left-Click|r to queue all you can craft."], color .. L["Right-Click|r to subtract this craft from the queue."], color .. L["Shift-Right-Click|r to remove all from queue."], } queueBtn.tooltip = table.concat(tooltipLines, "\n") buttonsFrame.queueBtn = queueBtn local createBtn = TSMAPI.GUI:CreateButton(buttonsFrame, 15) createBtn:SetText("Create")--(CREATE_PROFESSION) createBtn:SetPoint("BOTTOMLEFT") createBtn:SetPoint("BOTTOMRIGHT", buttonsFrame, "BOTTOM", -2, 0) createBtn:SetHeight(20) createBtn:SetScript("OnClick", function() GUI:CastTradeSkill(frame.index, buttonsFrame.inputBox:GetNumber()) end) buttonsFrame.createBtn = createBtn local createAllBtn = TSMAPI.GUI:CreateButton(buttonsFrame, 15) createAllBtn:SetText(CREATE_ALL) createAllBtn:SetPoint("BOTTOMLEFT", buttonsFrame, "BOTTOM", 2, 0) createAllBtn:SetPoint("BOTTOMRIGHT") createAllBtn:SetHeight(20) createAllBtn:SetScript("OnClick", function(self) local quantity = select(3, GetTradeSkillInfo(frame.index)) GUI:CastTradeSkill(frame.index, quantity, self.vellum) GUI.frame.content.professionsTab.craftInfoFrame.buttonsFrame.inputBox:SetNumber(GetTradeskillRepeatCount()) end) buttonsFrame.createAllBtn = createAllBtn frame.SetTradeSkillIndex = function(self, skillIndex) local name, _, numAvailable, _, altVerb = GetTradeSkillInfo(skillIndex) -- Enable display of items created local lNum, hNum = GetTradeSkillNumMade(skillIndex) local numMade = floor(((lNum or 1) + (hNum or 1)) / 2) if altVerb ~= nil and strfind(name,"Enchant ") then numMade = 1 end if numMade > 1 then name = numMade .. " x " .. name end self.index = skillIndex self.infoFrame.icon:SetTexture(GetTradeSkillIcon(skillIndex)) self.infoFrame.nameText:SetText(TSMAPI.Design:GetInlineColor("link") .. (name or "") .. "|r") self.infoFrame.descText:SetText(GetTradeSkillDescription(skillIndex)) -- The code below is heavily based on the code in Blizzard_TradeSkillUI.lua. local toolsInfo = BuildColoredListString(GetTradeSkillTools(skillIndex)) self.infoFrame.toolsText:SetText(toolsInfo and REQUIRES_LABEL .. " " .. toolsInfo or "") local cooldown = GetTradeSkillCooldown(skillIndex) if not cooldown then self.infoFrame.cooldownText:SetText(""); elseif cooldown > 60 * 60 * 24 then --Cooldown is greater than 1 day. self.infoFrame.cooldownText:SetText(COOLDOWN_REMAINING .. " " .. SecondsToTime(cooldown, true, false, 1, true)) else self.infoFrame.cooldownText:SetText(COOLDOWN_REMAINING .. " " .. SecondsToTime(cooldown)) end for i, btn in ipairs(self.matsFrame.reagentButtons) do local name, texture, needed, player = GetTradeSkillReagentInfo(skillIndex, i) if name then btn:Show() btn.link = GetTradeSkillReagentItemLink(skillIndex, i) local linkText = (texture and "|T" .. texture .. ":0|t" or "") .. " " .. (GetTradeSkillReagentItemLink(skillIndex, i) or name) local color = (needed > player) and "|cffff0000" or "|cff00ff00" btn:SetText(format("%s(%d/%d) %s|r", color, player, needed, linkText)) else btn:Hide() btn:SetText("") end end -- if altVerb == ENSCRIBE then if altVerb ~= nil and strfind(name,"Enchant ") then createAllBtn:SetText(L["Enchant Vellum"]) if strfind(name, "Weapon") or strfind(name, "Staff") then createAllBtn.vellum = TSMAPI:GetSafeItemInfo("item:52511:0:0:0:0:0:0") -- Weapon Vellum else createAllBtn.vellum = TSMAPI:GetSafeItemInfo("item:52510:0:0:0:0:0:0") -- Armor Vellum end else createAllBtn:SetText(CREATE_ALL) createAllBtn.vellum = nil end if numAvailable > 0 and not IsTradeSkillLinked() then local num = self.buttonsFrame.inputBox:GetNumber() self.buttonsFrame.inputBox:SetNumber(max(min(num, numAvailable), 1)) self.buttonsFrame.createBtn:Enable() self.buttonsFrame.createAllBtn:Enable() else self.buttonsFrame.inputBox:SetNumber(1) self.buttonsFrame.createBtn:Disable() self.buttonsFrame.createAllBtn:Disable() end end return frame end local RestockGroups function GUI:CreateGroupsTab(parent) local frame = CreateFrame("Frame", nil, parent) frame:SetAllPoints() TSMAPI.Design:SetFrameBackdropColor(frame) local stContainer = CreateFrame("Frame", nil, frame) stContainer:SetPoint("TOPLEFT", 5, -5) stContainer:SetPoint("BOTTOMRIGHT", -5, 35) TSMAPI.Design:SetFrameColor(stContainer) local groupTree = TSMAPI:CreateGroupTree(stContainer, "Crafting", "Crafting_Profession") RestockGroups = groupTree local function OnCreateBtnClick() if TSM.db.realm.tradeSkills[UnitName("player")][GetTradeSkillLine()] then TSM.db.realm.tradeSkills[UnitName("player")][GetTradeSkillLine()].prompted = nil end private.forceCreateGroups = true TSM.Util:ScanCurrentProfession() end local function OnRestockBtnClick() TSM.Queue:CreateRestockQueue(groupTree:GetSelectedGroupInfo()) GUI:UpdateQueue() end local btn = TSMAPI.GUI:CreateButton(frame, 13) btn:SetPoint("BOTTOMLEFT", 5, 5) btn:SetWidth(160) btn:SetHeight(24) btn:SetText(L["Create Profession Groups"]) btn:SetScript("OnClick", OnCreateBtnClick) frame.createBtn = btn local btn = TSMAPI.GUI:CreateButton(frame, 20) btn:SetPoint("BOTTOMLEFT", frame.createBtn, "BOTTOMRIGHT", 5, 0) btn:SetPoint("BOTTOMRIGHT", -5, 5) btn:SetHeight(24) btn:SetText(L["Restock Selected Groups"]) btn:SetScript("OnClick", OnRestockBtnClick) frame.restockBtn = btn return frame end function GUI:UpdateProfessionsTabST() if not GUI.frame or not GUI.frame:IsVisible() then return end local stData = {} TSM:UpdateCraftReverseLookup() local showAll = TSM.db.global.showAllProfessions local player = UnitName("player") local function RGBPercToHex(tbl) local r = tbl.r local g = tbl.g local b = tbl.b r = r <= 1 and r >= 0 and r or 0 g = g <= 1 and g >= 0 and g or 0 b = b <= 1 and b >= 0 and b or 0 return string.format("%02x%02x%02x", r * 255, g * 255, b * 255) end if priceTextCache.lastClear + 60 < time() then wipe(priceTextCache) priceTextCache.lastClear = time() end local function GetInventoryTotals() local totals = {} local bags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", player) local bank = TSMAPI:ModuleAPI("ItemTracker", "playerbank", player) if bags or bank then for itemString, quantity in pairs(bags or {}) do totals[itemString] = (totals[itemString] or 0) + quantity end for itemString, quantity in pairs(bank or {}) do totals[itemString] = (totals[itemString] or 0) + quantity end return totals end return select(4, TSM.Inventory:GetTotals()) end local ts = "" local numAvailableAllCache = {} local inventoryTotals = GetInventoryTotals() if showAll then local searchText = GUI.frame and GUI.frame.content and GUI.frame.content.professionsTab and GUI.frame.content.professionsTab.searchBar and GUI.frame.content.professionsTab.searchBar:GetText() or "" if searchText == SEARCH then searchText = "" end searchText = strlower(searchText or "") local filterHaveMats = GUI.frame and GUI.frame.content and GUI.frame.content.professionsTab and GUI.frame.content.professionsTab.HaveMatsCheckBox and GUI.frame.content.professionsTab.HaveMatsCheckBox:GetValue() local craftList = {} for spellID, data in pairs(TSM.db.realm.crafts) do if data.players and data.players[UnitName("player")] then tinsert(craftList, { spellID = spellID, name = data.name or "", profession = data.profession or UNKNOWN, numResult = data.numResult or 1, }) end end for _, craft in ipairs(craftList) do craft.cost, craft.buyout, craft.profit = TSM.Cost:GetCraftPrices(craft.spellID) if craft.profit and craft.cost and craft.cost > 0 then craft.profitPercent = (craft.profit / craft.cost) * 100 else craft.profitPercent = nil end local available = math.huge if TSM.db.realm.crafts[craft.spellID] then for itemString, quantity in pairs(TSM.db.realm.crafts[craft.spellID].mats) do available = min(available, floor((inventoryTotals[itemString] or 0) / quantity)) end end craft.available = available ~= math.huge and available or 0 end if searchText ~= "" or filterHaveMats then local filtered = {} for _, craft in ipairs(craftList) do if (searchText == "" or strfind(strlower(craft.name or ""), searchText, 1, true)) and (not filterHaveMats or craft.available > 0) then tinsert(filtered, craft) end end craftList = filtered end if TSM.db.global.showAllProfessionsSortKey == "cost" then sort(craftList, function(a, b) local aValue = tonumber(a.cost) or math.huge local bValue = tonumber(b.cost) or math.huge if aValue == bValue then return a.name < b.name end if TSM.db.global.showAllProfessionsSortDescending then return aValue > bValue end return aValue < bValue end) elseif TSM.db.global.showAllProfessionsSortKey == "profit" then sort(craftList, function(a, b) local aValue = tonumber(a.profit) or -math.huge local bValue = tonumber(b.profit) or -math.huge if aValue == bValue then return a.name < b.name end if TSM.db.global.showAllProfessionsSortDescending then return aValue > bValue end return aValue < bValue end) elseif TSM.db.global.showAllProfessionsSortKey == "available" then sort(craftList, function(a, b) local aValue = tonumber(a.available) or -math.huge local bValue = tonumber(b.available) or -math.huge if aValue == bValue then return a.name < b.name end if TSM.db.global.showAllProfessionsSortDescending then return aValue > bValue end return aValue < bValue end) elseif TSM.db.global.showAllProfessionsSortKey == "profitPercent" then sort(craftList, function(a, b) local aValue = tonumber(a.profitPercent) or -math.huge local bValue = tonumber(b.profitPercent) or -math.huge if aValue == bValue then return a.name < b.name end if TSM.db.global.showAllProfessionsSortDescending then return aValue > bValue end return aValue < bValue end) else sort(craftList, function(a, b) if TSM.db.global.showAllProfessionsSortDescending then return a.name > b.name end return a.name < b.name end) end for _, craft in ipairs(craftList) do local spellID = craft.spellID local craftName = craft.name if not numAvailableAllCache[spellID] then local numAvailableAll = math.huge if spellID and TSM.db.realm.crafts[spellID] then for itemString, quantity in pairs(TSM.db.realm.crafts[spellID].mats) do numAvailableAll = min(numAvailableAll, floor((inventoryTotals[itemString] or 0) / quantity)) end end if numAvailableAll ~= math.huge then numAvailableAllCache[spellID] = numAvailableAll end end local available = craft.available or 0 local displayName = craftName local costText local profitText local cost, _, profit = craft.cost, craft.buyout, craft.profit if cost and cost > 0 then costText = TSMAPI:FormatTextMoney(cost, TSMAPI.Design:GetInlineColor("link")) else costText = "---" end if profit then if profit < 0 then profitText = "|cffff0000-|r" .. TSMAPI:FormatTextMoney(-profit, "|cffff0000") else profitText = TSMAPI:FormatTextMoney(profit, "|cff00ff00") end else profitText = "---" end local profitPercent = "---" if profit and cost and cost > 0 then profitPercent = craft.profitPercent if profit < 0 then profitPercent = format("%s%.0f%%|r", "|cffff0000", profitPercent) else profitPercent = format("%s%.0f%%|r", "|cff00ff00", profitPercent) end end tinsert(stData, { cols = { { value = available }, { value = displayName }, { value = costText or "" }, { value = profitText or "" }, { value = profitPercent or "" }, }, spellID = spellID, profession = craft.profession, }) end local frame = GUI.frame.content.professionsTab frame.st:SetData(stData) return end local collapseAllRow = { cols = { { value = "" }, { value = "|cff" .. RGBPercToHex(TradeSkillTypeColor.header) .. ALL .. " [" .. (TradeSkillCollapseAllButton.collapsed and "+" or "-") .. "]|r", }, { value = "" }, { value = "" }, { value = "" }, }, isCollapseAll = true, } tinsert(stData, collapseAllRow) for i = 1, GetNumTradeSkills() do -- local skillName, skillType, numAvailable, isExpanded, _, numSkillUps, _, showProgressBar, currentRank, maxRank = GetTradeSkillInfo(i) local skillName, skillType, numAvailable, isExpanded, _ = GetTradeSkillInfo(i) if skillName then local spellID = TSM.Util:GetSpellID(i) local key = skillName .. i if skillType == "header" then ts = "" elseif skillType == "subheader" then ts = " " end if skillType == "header" or skillType == "subheader" then -- if showProgressBar then -- skillName = skillName .. " (" .. currentRank .. "/" .. maxRank .. ") " .. (isExpanded and " [-]" or " [+]") -- else skillName = skillName .. (isExpanded and " [-]" or " [+]") -- end end -- if numSkillUps > 1 and skillType == "optimal" then -- skillName = skillName .. " <" .. numSkillUps .. ">" -- end if not numAvailableAllCache[spellID] then local numAvailableAll = math.huge if spellID and TSM.db.realm.crafts[spellID] then for itemString, quantity in pairs(TSM.db.realm.crafts[spellID].mats) do numAvailableAll = min(numAvailableAll, floor((inventoryTotals[itemString] or 0) / quantity)) end end if numAvailableAll ~= math.huge then numAvailableAllCache[spellID] = numAvailableAll end end local available = numAvailableAllCache[spellID] or 0 skillName = ts .. "|cff" .. RGBPercToHex(TradeSkillTypeColor[skillType]) .. skillName .. "|r" local costText local profitText local cost, _, profit = TSM.Cost:GetCraftPrices(spellID) if cost and cost > 0 then costText = TSMAPI:FormatTextMoney(cost, TSMAPI.Design:GetInlineColor("link")) else costText = "---" end if profit then if profit < 0 then profitText = "|cffff0000-|r" .. TSMAPI:FormatTextMoney(-profit, "|cffff0000") else profitText = TSMAPI:FormatTextMoney(profit, "|cff00ff00") end else profitText = "---" end local profitPercent = "---" if profit and cost and cost > 0 then profitPercent = profit / cost * 100 if profit < 0 then profitPercent = format("%s%.0f%%|r", "|cffff0000", profitPercent) else profitPercent = format("%s%.0f%%|r", "|cff00ff00", profitPercent) end end local row = { cols = { { value = spellID and available or "", }, { value = skillName, }, { value = spellID and costText or "", }, { value = spellID and profitText or "", }, { value = spellID and profitPercent or "", }, }, index = i, } tinsert(stData, row) if skillType == "header" then ts = " " elseif skillType == "subheader" then ts = " " end end end local frame = GUI.frame.content.professionsTab frame.st:SetData(stData) GUI:UpdateSelectedTradeSkill(true) end function GUI:UpdateSelectedTradeSkill(forceUpdate) if not GUI.frame or not GUI.frame.content or not GUI.frame.content.professionsTab:IsVisible() then return end local frame = GUI.frame.content.professionsTab TradeSkillFrame.selectedSkill = TradeSkillFrame.selectedSkill or 1 if TSM.db.global.showAllProfessions then frame.craftInfoFrame:SetTradeSkillIndex(TradeSkillFrame.selectedSkill) return end local selection = frame.st:GetSelection() or 0 if forceUpdate or selection - 1 ~= TradeSkillFrame.selectedSkill then frame.st:SetSelection(TradeSkillFrame.selectedSkill + 1) frame.craftInfoFrame:SetTradeSkillIndex(TradeSkillFrame.selectedSkill) end end function GUI:UpdateQueue() if not GUI.frame or not GUI.frame.queue or not GUI.frame.queue:IsVisible() then return end TSM.Options:UpdateCraftST() TSM:UpdateCraftReverseLookup() GUI.craftNextInfo = nil local skillIndexLookup = {} for i = 1, GetNumTradeSkills() do local spellID = TSM.Util:GetSpellID(i) if spellID then skillIndexLookup[spellID] = i end end local queuedCrafts, queuedMats, totalCost, totalProfit = TSM.Queue:GetQueue() GUI.frame.queue.profitLabel:SetAmounts(totalCost, totalProfit) local currentProfession = GetTradeSkillLine() local stData = {} local bagTotals = TSM.Inventory:GetTotals(itemID) for profession, crafts in pairs(queuedCrafts) do local professionColor, playerColor local players = {} for player, data in pairs(TSM.db.realm.tradeSkills) do if data[profession] then tinsert(players, player) end end if TSM.db.realm.tradeSkills[UnitName("player")][profession] then playerColor = "|cffffffff" if profession == currentProfession then professionColor = "|cffffffff" else professionColor = "|cffff0000" end else playerColor = "|cffff0000" professionColor = "|cffff0000" end local professionCollapsed = TSM.db.realm.queueStatus.collapsed[profession] local row = { cols = { { value = format("%s (%s) %s%s|r", professionColor .. profession .. "|r", playerColor .. table.concat(players, ", ") .. "|r", TSMAPI.Design:GetInlineColor("link"), professionCollapsed and "[+]" or "[-]") } }, isTitle = true, profession = profession, } tinsert(stData, row) if not professionCollapsed then for _, stage in ipairs(crafts) do local stageCollapsed = TSM.db.realm.queueStatus.collapsed[profession .. stage.name] local row = { cols = { { value = format(" %s %s%s|r", stage.name, TSMAPI.Design:GetInlineColor("link"), stageCollapsed and "[+]" or "[-]") } }, isTitle = true, stage = stage.name, profession = profession, } tinsert(stData, row) if not stageCollapsed then local craftRows = {} for spellID, numQueued in pairs(stage.crafts) do local canCraft = math.huge local velName if TSM.VellumInfo[spellID] then velName = GetItemInfo(TSM.VellumInfo[spellID]) end for itemID, quantity in pairs(TSM.db.realm.crafts[spellID].mats) do local MatName = GetItemInfo(itemID) if MatName ~= nil and velName ~= nil and strfind(MatName, "Vellum") then local NewItemString = CheapestVellum(itemID) if itemID ~= NewItemString then itemID = NewItemString velName = GetItemInfo(itemID) end end local numHave = bagTotals[itemID] or 0 canCraft = min(canCraft, floor(numHave / quantity)) end local color local craftIndex = skillIndexLookup[spellID] if canCraft >= numQueued then -- green (can craft all) if craftIndex then color = "|cff00ff00" else color = "|cff008800" end elseif canCraft > 0 then -- blue (can craft some) if craftIndex then color = "|cff5599ff" else color = "|cff224488" end else -- orange (can't craft any) if craftIndex then color = "|cffff7700" else color = "|cff883300" end end local extra = "" if not craftIndex then if TSM.db.realm.crafts[spellID].players[UnitName("player")] and TSM.db.realm.crafts[spellID].profession == currentProfession then extra = "|cffff0000[Filtered]|r " end end local row = { cols = { { value = " " .. extra .. color .. TSM.db.realm.crafts[spellID].name .. " (x" .. numQueued .. ")" .. "|r", }, }, spellID = spellID, canCraft = (canCraft > 0) and canCraft or 0, numQueued = numQueued, index = craftIndex, velName = velName, profit = select(3, TSM.Cost:GetCraftPrices(spellID)), profession = GetTradeSkillLine(), } tinsert(craftRows, row) end sort(craftRows, function(a, b) if (a.canCraft == 0 and b.canCraft == 0) or (a.canCraft >= a.numQueued and b.canCraft >= b.numQueued) then if a.profit and b.profit and a.profit ~= b.profit then return a.profit > b.profit else return a.spellID > b.spellID end elseif a.canCraft >= a.numQueued then return true elseif b.canCraft >= b.numQueued then return false else return a.canCraft > b.canCraft end end) for _, row in ipairs(craftRows) do if not GUI.craftNextInfo and row.index and row.canCraft > 0 then GUI.craftNextInfo = { spellID = row.spellID, index = row.index, quantity = min(row.numQueued, row.canCraft), velName = row.velName, isCrafting = 0 } end tinsert(stData, row) end end end end end GUI.frame.queue.craftST:SetData(stData) stData = {} local totalMats = {} for _, data in pairs(queuedMats) do for itemString, quantity in pairs(data) do local MatName = GetItemInfo(itemString) if MatName ~= nil and strfind(MatName, "Vellum") then local NewItemString = CheapestVellum(itemString) if itemString ~= NewItemString then itemString = NewItemString end end totalMats[itemString] = (totalMats[itemString] or 0) + quantity end end for itemString, quantity in pairs(totalMats) do local cost = TSM.Cost:GetMatCost(itemString) local need = max(quantity - TSM.Inventory:GetTotalQuantity(itemString), 0) local color, order if need == 0 then if TSM.Inventory:GetPlayerBagNum(itemString) >= quantity then color = "|cff00ff00" order = 1 else color = "|cffffff00" order = 2 end else color = "|cffff0000" order = 3 end local row = { cols = { { value = color .. TSM.db.realm.mats[itemString].name .. "|r", args = { TSM.db.realm.mats[itemString].name }, }, { value = color .. need .. "|r", args = { need }, }, { value = color .. quantity .. "|r", args = { quantity }, }, { value = TSMAPI:FormatTextMoney(cost) or "---", args = { cost }, }, }, itemString = itemString, order = order, } tinsert(stData, row) end sort(stData, function(a, b) return a.order < b.order end) GUI.frame.queue.matST:SetData(stData) -- TSMAPI:CreateTimeDelay("gatheringUpdateThrottle", 0.3, GUI.UpdateGathering) TSMAPI:CreateTimeDelay("UpdateCraftButtonThrottle", 0.2, GUI.UpdateCraftButton) end function GUI:UpdateCraftButton() if UnitCastingInfo("player") or not GUI.craftNextInfo then TSMCraftNextButton:Disable() elseif GUI.isCrafting and GUI.isCrafting.quantity > 0 then TSMCraftNextButton:Disable() else TSMCraftNextButton:Enable() end end function GUI:ShowProfessionsTab() GUI.frame.navFrame.groupsBtn:UnlockHighlight() GUI.frame.navFrame.professionsBtn:LockHighlight() GUI.frame.content.groupsTab:Hide() GUI.frame.content.professionsTab:Show() GUI:UpdateProfessionsTabST() GUI.frame.content.professionsTab.craftInfoFrame.buttonsFrame.inputBox:SetNumber(1) end function GUI:ShowGroupsTab() GUI.frame.navFrame.professionsBtn:UnlockHighlight() GUI.frame.navFrame.groupsBtn:LockHighlight() GUI.frame.content.professionsTab:Hide() GUI.frame.content.groupsTab:Show() if QuickRestock then QuickRestock = false TSM.Queue:CreateRestockQueue(RestockGroups:GetSelectedGroupInfo()) GUI:UpdateQueue() GUI.ShowProfessionsTab() end end function GUI:CreatePromptFrame(parent) local frame = CreateFrame("Frame", nil, parent) TSMAPI.Design:SetFrameBackdropColor(frame) frame:SetAllPoints() frame:SetFrameLevel(20) frame:EnableMouse(true) frame:Hide() local text = frame:CreateFontString() text:SetPoint("LEFT", 5, 50) text:SetPoint("RIGHT", -5, 50) text:SetHeight(100) text:SetFont(TSMAPI.Design:GetContentFont("normal")) text:SetText(L["Would you like to automatically create some TradeSkillMaster groups for this profession?"]) frame.text = text frame.SetText = function(_, ...) text:SetText(...) end local yesBtn = TSMAPI.GUI:CreateButton(frame, 16) yesBtn:SetPoint("CENTER", -110, 0) yesBtn:SetWidth(100) yesBtn:SetHeight(20) yesBtn:SetText(YES) yesBtn:SetScript("OnClick", function() TSM:Printf(L["Created profession group for %s."], frame.profession) TSMAPI:CreatePresetGroups(frame.presetGroupInfo) TSM.db.realm.tradeSkills[UnitName("player")][frame.profession].prompted = true frame:Hide() GUI:UpdateProfessionsTabST() end) frame.yesBtn = yesBtn local laterBtn = TSMAPI.GUI:CreateButton(frame, 16) laterBtn:SetPoint("CENTER") laterBtn:SetWidth(100) laterBtn:SetHeight(20) laterBtn:SetText(L["Ask Later"]) laterBtn:SetScript("OnClick", function() frame:Hide() end) frame.laterBtn = laterBtn local noBtn = TSMAPI.GUI:CreateButton(frame, 16) noBtn:SetPoint("CENTER", 110, 0) noBtn:SetWidth(100) noBtn:SetHeight(20) noBtn:SetText(L["No Thanks"]) noBtn:SetScript("OnClick", function() TSM.db.realm.tradeSkills[UnitName("player")][frame.profession].prompted = true frame:Hide() end) frame.noBtn = noBtn return frame end function GUI:PromptPresetGroups(currentTradeSkill, presetGroupInfo) GUI:RestoreFilters() if TSM.db.realm.tradeSkills[UnitName("player")][currentTradeSkill] and not TSM.db.realm.tradeSkills[UnitName("player")][currentTradeSkill].prompted then GUI.frame.prompt.profession = currentTradeSkill GUI.frame.prompt.presetGroupInfo = presetGroupInfo GUI.frame.prompt:Show() if private.forceCreateGroups then private.forceCreateGroups = nil GUI.frame.prompt.yesBtn:Click() end end end function GUI:CreateGatheringSelectionFrame(parent) local frame = CreateFrame("Frame", nil, parent) frame:SetFrameStrata("HIGH") frame:SetHeight(200) frame:SetWidth(250) frame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 2, 0) frame:EnableMouse(true) frame:SetScript("OnMouseDown", function() parent:StartMoving() end) frame:SetScript("OnMouseUp", function() parent:StopMovingOrSizing() end) TSMAPI.Design:SetFrameBackdropColor(frame) local title = TSMAPI.GUI:CreateLabel(frame) title:SetText("TSM_Crafting - " .. L["Gathering"]) title:SetPoint("TOPLEFT") title:SetPoint("TOPRIGHT") title:SetHeight(20) TSMAPI.GUI:CreateHorizontalLine(frame, -23) local text1 = TSMAPI.GUI:CreateLabel(frame) text1:SetText(L["First select a crafter"]) text1:SetPoint("TOPLEFT", 5, -28) text1:SetPoint("TOPRIGHT", -5, -28) text1:SetHeight(20) text1:SetJustifyH("CENTER") text1:SetJustifyV("CENTER") frame.text1 = text1 TSMAPI.GUI:CreateHorizontalLine(frame, -52) local dropdown = TSMAPI.GUI:CreateDropdown(frame) dropdown:SetPoint("TOPLEFT", 5, -55) dropdown:SetPoint("TOPRIGHT", -5, -55) dropdown:SetLabel(L["Crafter"]) dropdown:SetCallback("OnValueChanged", function(_, _, value) private.gather.player = value private.gather.professions = nil GUI:UpdateGatherSelectionWindow() end) frame.playerDropdown = dropdown local dropdown = TSMAPI.GUI:CreateDropdown(frame) dropdown:SetPoint("TOPLEFT", 5, -100) dropdown:SetPoint("TOPRIGHT", -5, -100) dropdown:SetLabel(L["Professions"]) dropdown:SetMultiselect(true) dropdown:SetCallback("OnValueChanged", function(_, _, profession, value) private.gather.professions[profession] = value or nil GUI:UpdateGatherSelectionWindow() end) frame.professionDropdown = dropdown TSMAPI.GUI:CreateHorizontalLine(frame, -150) local btn = TSMAPI.GUI:CreateButton(frame, 18) btn:SetPoint("BOTTOMLEFT", 5, 5) btn:SetPoint("BOTTOMRIGHT", -5, 5) btn:SetHeight(24) btn:SetText(L["Start Gathering"]) btn:SetScript("OnClick", GUI.StartGathering) frame.gatherButton = btn return frame end function GUI:UpdateGatherSelectionWindow() -- create table of crafters local queuedCrafts = TSM.Queue:GetQueue() local crafters = {} local numCrafters = 0 for profession, _ in pairs(queuedCrafts) do for player, data in pairs(TSM.db.realm.tradeSkills) do if data[profession] then crafters[player] = player numCrafters = numCrafters + 1 end end end local frame = GUI.frame.gather frame.playerDropdown:SetList(crafters) if not private.gather.player then if crafters[UnitName("player")] then private.gather.player = UnitName("player") elseif numCrafters == 1 then private.gather.player = next(crafters) end end if private.gather.player then frame.playerDropdown:SetValue(private.gather.player) -- create table of professions local professions = {} local numProfessions = 0 for profession, _ in pairs(queuedCrafts) do if TSM.db.realm.tradeSkills[private.gather.player][profession] then professions[profession] = profession numProfessions = numProfessions + 1 end end frame.professionDropdown:SetList(professions) if not private.gather.professions then private.gather.professions = {} for profession in pairs(professions) do private.gather.professions[profession] = true end end local currentProfession = GetTradeSkillLine() if currentProfession and professions[currentProfession] then private.gather.professions[currentProfession] = true end if next(private.gather.professions) then frame.gatherButton:Enable() else frame.gatherButton:Disable() end frame.professionDropdown:SetDisabled(false) for profession in pairs(professions) do frame.professionDropdown:SetItemValue(profession, private.gather.professions[profession]) end else frame.playerDropdown:SetValue() frame.professionDropdown:SetDisabled(true) frame.professionDropdown:SetValue({}) frame.gatherButton:Disable() end end function GUI:CreateGatheringFrame() local frameDefaults = { x = 850, y = 450, width = 325, height = 400, scale = 1, } local frame = TSMAPI:CreateMovableFrame("TSMCraftingGatherFrame", frameDefaults) frame:SetFrameStrata("HIGH") TSMAPI.Design:SetFrameBackdropColor(frame) local title = TSMAPI.GUI:CreateLabel(frame) title:SetText("TSM_Crafting - " .. L["Gathering"]) title:SetPoint("TOPLEFT") title:SetPoint("TOPRIGHT") title:SetHeight(20) TSMAPI.Design:SetTitleTextColor(title) TSMAPI.GUI:CreateHorizontalLine(frame, -21) local label = TSMAPI.GUI:CreateLabel(frame) label:SetText("") label:SetPoint("TOPLEFT", 0, -22) label:SetPoint("TOPRIGHT", 0, -22) label:SetHeight(20) frame.label = label TSMAPI.GUI:CreateHorizontalLine(frame, -42) local containersFrame = CreateFrame("Frame", nil, frame) containersFrame:SetPoint("TOPLEFT", 2, -45) containersFrame:SetPoint("TOPRIGHT", -2, -45) containersFrame:SetPoint("BOTTOMLEFT", 2, 53) local matsFrame = CreateFrame("Frame", nil, containersFrame) matsFrame:SetPoint("TOPLEFT") matsFrame:SetPoint("BOTTOMRIGHT", containersFrame, "CENTER", -2, 2) local stContainer = CreateFrame("Frame", nil, matsFrame) stContainer:SetAllPoints() TSMAPI.Design:SetFrameColor(stContainer) local stCols = { { name = L["Material Name"], width = 0.69, headAlign = "Left" }, { name = L["Need"], width = 0.2, headAlign = "Left" }, { name = L["Total"], width = 0.2, headAlign = "Left" }, } local function MatOnEnter(_, data, col) local link = select(2, TSMAPI:GetSafeItemInfo(data.itemString)) if link then GameTooltip:SetOwner(col, "ANCHOR_RIGHT") TSMAPI:SafeTooltipLink(link) GameTooltip:Show() end end local function MatOnLeave(_, data) GameTooltip:Hide() end frame.needST = TSMAPI:CreateScrollingTable(stContainer, stCols, { OnEnter = MatOnEnter, OnLeave = MatOnLeave }, 12) frame.needST:SetData({}) frame.needST:DisableSelection(true) local sourcesFrame = CreateFrame("Frame", nil, containersFrame) sourcesFrame:SetPoint("TOPLEFT", containersFrame, "TOP", 2, 0) sourcesFrame:SetPoint("BOTTOMRIGHT") local stContainer2 = CreateFrame("Frame", nil, sourcesFrame) stContainer2:SetAllPoints() TSMAPI.Design:SetFrameColor(stContainer2) local stCols2 = { { name = L["Available Sources"], width = 1, align = "Left" }, } local function OnCraftRowClicked(_, data) if data.isTitle then if data.task then TSM.db.realm.sourceStatus.collapsed[data.source .. data.task] = not TSM.db.realm.sourceStatus.collapsed[data.source .. data.task] else TSM.db.realm.sourceStatus.collapsed[data.source] = not TSM.db.realm.sourceStatus.collapsed[data.source] end GUI:UpdateGathering() end end local function AvilableOnEnter(_, data, col) if not data.isTitle then local link = select(2, TSMAPI:GetSafeItemInfo(data.cols[1].itemString)) if link then GameTooltip:SetOwner(col, "ANCHOR_RIGHT") TSMAPI:SafeTooltipLink(link) GameTooltip:Show() end end end frame.sourcesST = TSMAPI:CreateScrollingTable(stContainer2, stCols2, { OnEnter = AvilableOnEnter, OnLeave = MatOnLeave, OnClick = OnCraftRowClicked }, 12) frame.sourcesST:SetData({}) frame.sourcesST:DisableSelection(true) local availFrame = CreateFrame("Frame", nil, containersFrame) availFrame:SetPoint("TOPRIGHT", containersFrame, "CENTER", -2, -2) availFrame:SetPoint("BOTTOMLEFT") TSMAPI.Design:SetFrameBackdropColor(availFrame) local stContainer3 = CreateFrame("Frame", nil, availFrame) stContainer3:SetAllPoints() TSMAPI.Design:SetFrameColor(stContainer3) local stCols3 = { { name = L["Current Source"], width = 1, align = "Left" }, } local function OnAvailRowClicked(_, data, _, button) if data.name and data.taskType == L["Search for Mats"] then if TSMAPI:AHTabIsVisible("Shopping") then if data.need > 0 then if button == "RightButton" then TSM.Gather:ShoppingSearch(data.itemString, data.need, true) else TSM.Gather:ShoppingSearch(data.itemString, data.need) end end else TSM:Printf(L["Please switch to the Shopping Tab to perform the gathering search."]) end end end frame.availableST = TSMAPI:CreateScrollingTable(stContainer3, stCols3, { OnEnter = MatOnEnter, OnLeave = MatOnLeave, OnClick = OnAvailRowClicked }, 12) frame.availableST:SetData({}) frame.availableST:DisableSelection(true) local checkboxFrame = CreateFrame("Frame", nil, frame) checkboxFrame:SetPoint("TOPLEFT", containersFrame, "BOTTOMLEFT", 2, -2) checkboxFrame:SetPoint("TOPRIGHT", containersFrame, "BOTTOMRIGHT", -2, 2) checkboxFrame:SetPoint("BOTTOMLEFT", 2, 28) local checkbox1 = TSMAPI.GUI:CreateCheckBox(checkboxFrame, L["If checked, only a normal AH search will be performed"]) checkbox1:SetPoint("LEFT", checkboxFrame, "LEFT", 0, 3) --checkbox:SetPoint("BOTTOMRIGHT", checkboxFrame, "BOTTOMRIGHT") checkbox1:SetHeight(18) checkbox1:SetWidth(185) checkbox1:SetValue(TSM.db.realm.gathering.destroyDisable) checkbox1:SetLabel(L[" Disable Destroying Search"]) checkbox1:SetCallback("OnValueChanged", function(_, _, value) TSM.db.realm.gathering.destroyDisable = value end) local checkbox2 = TSMAPI.GUI:CreateCheckBox(checkboxFrame, L["If checked, the AH destroying search will only look for even stacks"]) checkbox2:SetPoint("RIGHT", checkboxFrame, "RIGHT", 0, 3) -- checkbox2:SetPoint("CENTER", checkboxFrame, "RIGHT") --checkbox:SetPoint("BOTTOMRIGHT", checkboxFrame, "BOTTOMRIGHT") checkbox2:SetHeight(18) checkbox2:SetWidth(100) checkbox2:SetValue(TSM.db.realm.gathering.evenStacks) checkbox2:SetLabel(L["Even Stacks"]) checkbox2:SetCallback("OnValueChanged", function(_, _, value) TSM.db.realm.gathering.evenStacks = value end) TSMAPI.Design:SetFrameColor(checkboxFrame) local btn = TSMAPI.GUI:CreateButton(frame, 18) btn:SetPoint("BOTTOMLEFT", frame, "BOTTOM", 2, 4) btn:SetPoint("BOTTOMRIGHT", -4, 4) btn:SetHeight(20) btn:SetText(L["Stop Gathering"]) btn:SetScript("OnClick", function() private.gather = {} GUI.gatheringFrame:Hide() TSM.db.realm.gathering.availableMats = {} TSM.db.realm.gathering.crafter = nil TSM.db.realm.gathering.neededMats = {} TSM.db.realm.gathering.gatheredMats = false TSM.db.realm.gathering.destroyingMats = {} private.currentSource = nil end) local btn = TSMAPI.GUI:CreateButton(frame, 18) btn:SetPoint("BOTTOMLEFT", 4, 4) btn:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -2, 4) btn:SetHeight(20) btn:SetText(L["Gather Items"]) btn:Disable() btn:SetScript("OnClick", function() TSM.Gather:gatherItems(private.currentSource, private.currentTask) end) frame.gatherButton = btn return frame end function GUI:StartGathering() GUI.frame.gather:Hide() TSM.db.realm.gathering.gatheredMats = false local _, queuedMats = TSM.Queue:GetQueue() local neededMats = {} for profession, data in pairs(queuedMats) do if private.gather.professions[profession] then for itemString, quantity in pairs(data) do neededMats[itemString] = (neededMats[itemString] or 0) + quantity end end end if not next(neededMats) then TSM:Print(L["Nothing To Gather"]) else TSM.db.realm.gathering.crafter = private.gather.player TSM.db.realm.gathering.professions = private.gather.professions TSM.db.realm.gathering.neededMats = neededMats GUI.gatheringFrame:Show() GUI:UpdateGathering() end private.gather = {} end function GUI:UpdateGathering() if not GUI.gatheringFrame or not GUI.gatheringFrame:IsVisible() then return end if not TSM.db.realm.gathering.crafter or not next(TSM.db.realm.gathering.neededMats) then return end -- recheck the craft queue and update neededMats local _, queuedMats = TSM.Queue:GetQueue() local neededMats = {} for profession, data in pairs(queuedMats) do if TSM.db.realm.gathering.professions[profession] then for itemString, quantity in pairs(data) do neededMats[itemString] = (neededMats[itemString] or 0) + quantity end end end local stData = {} local sources = {} local crafter = TSM.db.realm.gathering.crafter local professionList = {} for profession in pairs(TSM.db.realm.gathering.professions) do tinsert(professionList, profession) end -- double check if crafter already has all the items needed local shortItems = {} local crafterBags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", crafter) or {} for itemString, quantity in pairs(neededMats) do local need = max(quantity - (crafterBags[itemString] or 0), 0) if need > 0 then shortItems[itemString] = need end end if not next(shortItems) then GUI.gatheringFrame:Hide() if TSM.db.realm.gathering.gatheredMats == true then TSM:Print("Finished Gathering") TSM.db.realm.gathering.gatheredMats = false TSM.db.realm.gathering.crafter = nil TSM.db.realm.gathering.neededMats = {} TSM.db.realm.gathering.gatheredMats = false TSM.db.realm.sourceStatus.collapsed = {} TSM.db.realm.gathering.destroyingMats = {} end return else TSM.db.realm.gathering.neededMats = CopyTable(neededMats) end sort(professionList) local professionsUsed = table.concat(professionList, ", ") GUI.gatheringFrame.label:SetText(crafter .. " (" .. professionsUsed .. ")") for itemString, quantity in pairs(neededMats) do local need = max(quantity - (TSM.Inventory:GetTotalQuantity(itemString) or 0), 0) local color, order if need == 0 then if (crafterBags[itemString] or 0) >= quantity then color = "|cff00ff00" order = 1 else color = "|cffffff00" order = 2 end else color = "|cffff0000" order = 3 end local row = { cols = { { value = color .. TSM.db.realm.mats[itemString].name .. "|r", args = { TSM.db.realm.mats[itemString].name }, }, { value = color .. need .. "|r", args = { need }, }, { value = color .. quantity .. "|r", args = { quantity }, }, }, itemString = itemString, order = order, name = TSM.db.realm.mats[itemString].name, } tinsert(stData, row) end sort(stData, function(a, b) if a.order == 3 then return false end if b.order == 3 then return true end if a.order == 2 then return false end if b.order == 2 then return true end if a.order == 1 then return false end if b.order == 1 then return true end return a.name < b.name end) GUI.gatheringFrame.needST:SetData(stData) -- update sources local sources = TSM.Inventory:GetItemSources(crafter, neededMats) or {} stData = {} if next(sources) then for _, source in ipairs(sources) do local color if source.sourceName == UnitName("player") then color = "|cff00ff00" else color = "|cffffff00" end local sourceCollapsed = TSM.db.realm.sourceStatus.collapsed[source.sourceName] local row = { cols = { { value = format("%s %s%s|r", color .. source.sourceName, TSMAPI.Design:GetInlineColor("link"), sourceCollapsed and "[+]" or "[-]") } }, isTitle = true, source = source.sourceName, } tinsert(stData, row) if not sourceCollapsed then for _, task in ipairs(source.tasks) do local tasksCollapsed = TSM.db.realm.sourceStatus.collapsed[source.sourceName .. task.taskType] local row = { cols = { { value = format(" %s %s%s|r", color .. task.taskType, TSMAPI.Design:GetInlineColor("link"), tasksCollapsed and "[+]" or "[-]") } }, isTitle = true, task = task.taskType, source = source.sourceName, } tinsert(stData, row) if not tasksCollapsed then for itemString, quantity in pairs(task.items) do local needQty if source.sourceName == L["Destroying"] or task.taskType == L["Collect Mail"] or task.taskType == L["Mail Items"] then if neededMats[itemString] then needQty = min(quantity, neededMats[itemString]) else needQty = quantity end else needQty = neededMats[itemString] - (crafterBags[itemString] or 0) end local name = TSMAPI:GetSafeItemInfo(itemString) or itemString local row -- if task.taskType == L["Search for Mats"] or task.taskType == L["Visit Vendor"] or task.taskType == L["Collect Mail"] or task.taskType == L["Mail Items"] then row = { cols = { { value = format(" %s", color .. name .. " x" .. min(needQty, quantity)), itemString = itemString } }, } -- else -- row = { -- cols = { -- { -- value = format(" %s", color .. name .. " x" .. needQty .. " (" .. quantity .. " Avail)") -- } -- }, -- } -- end tinsert(stData, row) end end end end end end GUI.gatheringFrame.sourcesST:SetData(stData) -- update available mats if at a valid source stData = {} local availableMats = {} local playerBags = TSMAPI:ModuleAPI("ItemTracker", "playerbags", UnitName("player")) or {} local crafterMail = TSMAPI:ModuleAPI("ItemTracker", "playermail", crafter) or {} for itemString, quantity in pairs(neededMats) do local need = quantity - (crafterBags[itemString] or 0) if UnitName("player") ~= crafter then need = need - (crafterMail[itemString] or 0) end if need > 0 then if next(sources) then for _, source in ipairs(sources) do if private.currentSource and private.currentSource == source.sourceName then for _, task in ipairs(source.tasks) do if private.currentTask and private.currentTask == task.taskType then for taskItemString, taskQuantity in pairs(task.items) do if taskItemString == itemString then if task.taskType == L["Visit Vendor"] and not TSM.Gather:MerchantSells(itemString) then break end local availQty if task.taskType == L["Search for Mats"] then availQty = taskQuantity end if task.taskType == L["Mail Items"] then availQty = min(need, taskQuantity) elseif not crafter == UnitName("player") then availQty = min(need, taskQuantity) - (playerBags[itemString] or 0) else availQty = min(need, taskQuantity) -- (crafterBags[itemString] or 0) end availableMats[itemString] = availQty local name = select(1, TSMAPI:GetSafeItemInfo(itemString)) if not name then name = GetItemInfo(itemString) end local color if need == availQty then color = "|cff00ff00" else color = "|cffffff00" end local row = { cols = { { value = color .. name .. " x" .. availQty .. "|r", args = name, } }, name = name, itemString = taskItemString, need = availQty, taskType = task.taskType, } tinsert(stData, row) end end end end end end end end end -- store the available mats from source TSM.db.realm.gathering.availableMats = CopyTable(availableMats) GUI.gatheringFrame.gatherButton:SetText(L["Gather Items"]) if next(stData) then GUI.gatheringFrame.gatherButton:Enable() if private.currentTask == L["Visit Vendor"] then GUI.gatheringFrame.gatherButton:SetText(L["Buy Vendor Items"]) elseif private.currentTask == L["Mail Items"] then GUI.gatheringFrame.gatherButton:SetText(L["Mail Items"]) end else GUI.gatheringFrame.gatherButton:Disable() end sort(stData, function(a, b) return a.name < b.name end) GUI.gatheringFrame.availableST:SetData(stData) end function GUI:GatheringEventHandler(event) if not GUI.gatheringFrame or not GUI.gatheringFrame:IsShown() then return end if event == "GUILDBANKFRAME_OPENED" then private.currentSource = UnitName("player") private.currentTask = L["Visit Guild Bank"] elseif event == "GUILDBANKFRAME_CLOSED" then private.currentSource = nil private.currentTask = nil GUI.gatheringFrame.gatherButton:Disable() elseif event == "BANKFRAME_OPENED" then private.currentSource = UnitName("player") private.currentTask = L["Visit Bank"] elseif event == "BANKFRAME_CLOSED" then private.currentSource = nil private.currentTask = nil GUI.gatheringFrame.gatherButton:Disable() elseif event == "MERCHANT_SHOW" then private.currentSource = L["Vendor"] private.currentTask = L["Visit Vendor"] elseif event == "MERCHANT_CLOSED" then private.currentSource = nil private.currentTask = nil GUI.gatheringFrame.gatherButton:Disable() elseif event == "MAIL_SHOW" then private.currentSource = UnitName("player") private.currentTask = L["Mail Items"] elseif event == "MAIL_CLOSED" then private.currentSource = nil private.currentTask = nil GUI.gatheringFrame.gatherButton:Disable() elseif event == "AUCTION_HOUSE_SHOW" then TSM.Inventory.gatherQuantity = nil TSM.Inventory.gatherItem = nil private.currentSource = L["Auction House"] private.currentTask = L["Search for Mats"] elseif event == "AUCTION_HOUSE_CLOSED" then TSM.Inventory.gatherQuantity = nil TSM.Inventory.gatherItem = nil private.currentSource = nil private.currentTask = nil GUI.gatheringFrame.gatherButton:Disable() end TSMAPI:CreateTimeDelay("gatheringUpdateThrottle", 0.3, GUI.UpdateGathering) end function GUI:GetStatus() if not GUI.frame or not GUI.frame:IsVisible() then return end return { page = (GUI.frame.content.professionsTab:IsVisible() and "profession" or "groups"), gather = GUI.frame.gather:IsVisible() and true or false, queue = GUI.frame.queue:IsVisible() and true or false } end function CheapestVellum(itemPassed) -- Return one of the two vellum available local MatName = GetItemInfo(itemPassed) -- MatName is sometimes nil ??? if MatName ~= nil then local velName if strfind(MatName, "Vellum") then velName = MatName end if (velName ~= nil) then if strfind(velName, "Weapon") then itemPassed = "item:52511:0:0:0:0:0:0" else itemPassed = "item:52510:0:0:0:0:0:0" end end end return itemPassed end