LeoTrainer.ui.hidden = true local function addLine(tooltip, text, color, alignment) if not color then color = ZO_TOOLTIP_DEFAULT_COLOR end local r, g, b = color:UnpackRGB() tooltip:AddLine(text, "LeoTrainerNormalFont", r, g, b, CENTER, MODIFY_TEXT_TYPE_NONE, alignment, alignment ~= TEXT_ALIGN_LEFT) end local function addLineTitle(tooltip, text, color) if not color then color = ZO_SELECTED_TEXT end local r, g, b = color:UnpackRGB() tooltip:AddLine(text, "ZoFontHeader3", r, g, b, CENTER, MODIFY_TEXT_TYPE_NONE, TEXT_ALIGN_CENTER, true) end local function addLineSubTitle(tooltip, text, color, alignment) if not color then color = ZO_SELECTED_TEXT end if not alignment then alignment = TEXT_ALIGN_CENTER end local r, g, b = color:UnpackRGB() tooltip:AddLine(text, "ZoFontWinH3", r, g, b, CENTER, MODIFY_TEXT_TYPE_NONE, alignment, true) end function LeoTrainer.ui:OnWindowMoveStop() LeoTrainer.data.position = { left = LeoTrainerWindow:GetLeft(), top = LeoTrainerWindow:GetTop() } end function LeoTrainer.ui:OnHide(control, hidden) if hidden then LeoTrainer.ui.HideUI() end end function LeoTrainer.ui:OnShow(control, hidden) if not hidden then LeoTrainer.ui.ShowUI() end end function LeoTrainer.ui:isHidden() return LeoTrainer.ui.hidden end function LeoTrainer.ui.RestorePosition() local position = LeoTrainer.data.position or { left = 200; top = 200; } local left = position.left local top = position.top LeoTrainerWindow:ClearAnchors() LeoTrainerWindow:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, left, top) LeoTrainerWindow:SetDrawTier(DT_MEDIUM) end function LeoTrainer.ui.CloseUI() SCENE_MANAGER:HideTopLevel(LeoTrainerWindow) end function LeoTrainer.ui.ShowUI() LeoTrainer.ui.UpdateUI() LeoTrainer.hidden = false; end function LeoTrainer.ui.HideUI() LeoTrainer.hidden = true; end function LeoTrainer.ui.ToggleUI() SCENE_MANAGER:ToggleTopLevel(LeoTrainerWindow) end function LeoTrainer.ui:OnMouseEnterTrait(control) InitializeTooltip(ItemTooltip, control, LEFT, 5, 0) ItemTooltip:SetLink(ZO_LinkHandler_CreateLink("",nil,ITEM_LINK_TYPE,control.materialItemID,30,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)) ItemTooltip:SetHidden(false) end function LeoTrainer.ui.OnStationEnter(craftSkill) LeoTrainer.ui.queueScroll:RefreshData() LeoTrainerWindowQueuePanelQueueScrollCraftAll:SetState(BSTATE_NORMAL) end function LeoTrainer.ui.OnStationExit(craftSkill) LeoTrainerWindowQueuePanelQueueScrollCraftAll:SetState(BSTATE_DISABLED) LeoTrainer.ui.queueScroll:RefreshData() LeoTrainer.ui.HideUI() -- LeoTrainerStation:SetHidden(true) end function LeoTrainer.ui.Initialize() local showButton, feedbackWindow = LibFeedback:initializeFeedbackWindow(LeoTrainer, LeoTrainer.name,LeoTrainerWindow, "@LeandroSilva", {TOPRIGHT, LeoTrainerWindow, TOPRIGHT,-50,3}, {0,1000,10000,"https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y9KM4PZU2UZ6A"}, "If you found a bug, have a request or a suggestion, or simply wish to donate, send a mail.") LeoTrainer.feedback = feedbackWindow LeoTrainer.feedback:SetDrawTier(DT_MEDIUM) LeoTrainerWindowTitle:SetText(LeoTrainer.displayName .. " v" .. LeoTrainer.version) LeoTrainer.settingsMenu = LeoTrainer_SettingsMenu:New() LeoTrainer.settingsMenu:CreatePanel() LeoTrainer.launcher = LeoTrainer_Launcher:New() LeoTrainer.launcher:SetHidden(false) LeoTrainer.ui.RestorePosition() LeoTrainer.ui.CreateUI() LeoTrainer.ui.UpdateUI() end local function copy(obj) if type(obj) ~= 'table' then return obj end return ZO_ShallowTableCopy(obj) end LeoTrainerQueueList = ZO_SortFilterList:Subclass() function LeoTrainerQueueList:New(control) ZO_SortFilterList.InitializeSortFilterList(self, control) local sorterKeys = { ["trainer"] = {}, ["trainee"] = { tiebreaker = "trainer"}, ["researchName"] = { tiebreaker = "trainee"}, ["item"] = { tiebreaker = "researchName"}, } self.masterList = {} self.currentSortKey = "trainee" self.currentSortOrder = ZO_SORT_ORDER_UP ZO_ScrollList_AddDataType(self.list, 1, "LeoTrainerQueueListTemplate", 32, function(control, data) self:SetupEntry(control, data) end) self.sortFunction = function(listEntry1, listEntry2) return ZO_TableOrderingFunction(listEntry1.data, listEntry2.data, self.currentSortKey, sorterKeys, self.currentSortOrder) end return self end function LeoTrainerQueueList:SetupEntry(control, data) control.data = data control.trainer = GetControl(control, "Trainer") control.trainer:SetText(data.trainer) control.trainer.knownList = data.knownList if data.knownList ~= nil and #data.knownList > 1 then control.trainer:SetHandler('OnMouseEnter', function(self) InitializeTooltip(InformationTooltip, self, LEFT, 5, 0) addLineTitle(InformationTooltip, "Trainers", ZO_TOOLTIP_DEFAULT_COLOR) ZO_Tooltip_AddDivider(InformationTooltip) for _, knowName in pairs(data.knownList) do addLine(InformationTooltip, knowName, LeoTrainer.const.colors.green) end addLine(InformationTooltip, zo_iconTextFormat("esoui/art/icons/icon_lmb.dds", 26, 26, "Change Trainer")) InformationTooltip:SetHidden(false) end) control.trainer:SetHandler('OnMouseUp', function(control, button, upInside) if not upInside or (button ~= MOUSE_BUTTON_INDEX_RIGHT and button ~= MOUSE_BUTTON_INDEX_LEFT) then return end local newTrainer for trainerIndex, trainer in pairs(data.knownList) do if trainer == data.trainer then if trainerIndex < #data.knownList then newTrainer = data.knownList[trainerIndex + 1] else newTrainer = data.knownList[1] end break end end LeoTrainer.data.craftQueue[data.queueIndex].trainer = newTrainer LeoTrainer.ui.queueScroll:RefreshData() end) end control.trainee = GetControl(control, "Trainee") control.trainee:SetText(data.trainee) control.researchName = GetControl(control, "Trait") control.researchName:SetText(data.researchName) control.item = GetControl(control, "Item") control.item:SetText(data.itemLink) control.item:SetHandler('OnMouseUp', function(control, button, upInside) if upInside == false then return end if button == MOUSE_BUTTON_INDEX_RIGHT then LeoTrainer.RemoveFromQueue(data.queueIndex) end end) ZO_SortFilterList.SetupRow(self, control, data) end function LeoTrainerQueueList:BuildMasterList() self.masterList = {} local list = LeoTrainer.GetCraftQueue() if list then for k, v in ipairs(list) do local data = copy(v) data.queueIndex = k table.insert(self.masterList, data) end end end function LeoTrainerQueueList:SortScrollList() local scrollData = ZO_ScrollList_GetDataList(self.list) table.sort(scrollData, self.sortFunction) end function LeoTrainerQueueList:FilterScrollList() local scrollData = ZO_ScrollList_GetDataList(self.list) ZO_ClearNumericallyIndexedTable(scrollData) local station = GetCraftingInteractionType() for i = 1, #self.masterList do local data = self.masterList[i] local canShow = true if canShow == true and station > 0 and data.craft ~= station then canShow = false end if station > 0 and data.trainer ~= "Anyone" and data.trainer ~= LeoAltholic.CharName then canShow = false end if data.crafted then canShow = false end if canShow then table.insert(scrollData, ZO_ScrollList_CreateDataEntry(1, data)) end end end local function getTraitResearchData(research, craft, line, trait) local isKnown = research.done[craft][line][trait] or false local isResearching = false local doneAt if isKnown == false then for _, researching in pairs(research.doing[craft]) do if researching.line == line and researching.trait == trait then doneAt = researching.doneAt isResearching = true break end end end return isKnown, isResearching, doneAt end local function isLineBeingResearched(research, craft, line) for _, researching in pairs(research.doing[craft]) do if researching.line == line then if researching.doneAt and researching.doneAt - GetTimeStamp() > 0 then return true end end end return false end local function getNumOngoingResearches(research, craft) local num = 0 for _, researching in pairs(research.doing[craft]) do if researching.doneAt - GetTimeStamp() > 0 then num = num + 1 end end return num end local function getFirstUnknownTraitCanBeTrained(craft, line, unknownTraits, trainer) for _, trait in pairs(unknownTraits) do if trainer == nil and #LeoTrainer.knowledge[craft][line][trait] > 0 then return trait, LeoTrainer.knowledge[craft][line][trait] elseif trainer ~= nil then for _, charName in pairs(LeoTrainer.knowledge[craft][line][trait]) do if charName == trainer then return trait, LeoTrainer.knowledge[craft][line][trait] end end end end return nil, {} end function LeoTrainer.ui.CreateUI() local traitIcons = {} for traitItemIndex = 1, GetNumSmithingTraitItems() do local traitType, _, icon, _, _, _, _ = GetSmithingTraitItemInfo(traitItemIndex) if traitType and traitType ~= ITEM_TRAIT_TYPE_NONE then traitIcons[traitType] = icon end end for _,craft in pairs(LeoAltholic.craftResearch) do local panel = WINDOW_MANAGER:GetControlByName('LeoTrainerWindowCraft'..craft.."Panel") if craft == CRAFTING_TYPE_JEWELRYCRAFTING then panel = WINDOW_MANAGER:GetControlByName('LeoTrainerWindowCraft6PanelCraft7Panel') end for line = 1, GetNumSmithingResearchLines(craft) do local lineName, lineIcon, numTraits = GetSmithingResearchLineInfo(craft, line) local labelLine = panel:GetNamedChild('Line' .. line) labelLine.tooltip = lineName labelLine:SetText("|t30:30:"..lineIcon.."|t") for trait = 1, numTraits do local traitType = GetSmithingResearchLineTraitInfo(craft, line, trait) local traitName = GetString('SI_ITEMTRAITTYPE', traitType) local i = trait local posY = 14 + (trait * 28) if craft == CRAFTING_TYPE_BLACKSMITHING and line <= 7 then i = i + 10 elseif craft == CRAFTING_TYPE_WOODWORKING and line <= 5 then i = i + 10 end local labelTrait = panel:GetNamedChild('Trait' .. i) labelTrait:SetText(traitName .. " |t28:28:"..traitIcons[traitType].."|t") labelTrait.materialItemID = LeoTrainer.const.traitMaterials[traitType] local t = WINDOW_MANAGER:CreateControl('LeoTrainerWindowCraft'..craft..'Line'..line..'Trait'..trait..'Texture', labelLine, CT_TEXTURE) t:SetAnchor(CENTER, labelLine, CENTER, 0, posY) t:SetDimensions(25,25) t:SetMouseEnabled(true) t:SetHandler('OnMouseExit', function(self) ClearTooltip(InformationTooltip) InformationTooltip:SetHidden(true) end) end local label = WINDOW_MANAGER:CreateControl('LeoTrainerWindowCraft'..craft..'Line'..line..'Count', labelLine, CT_LABEL) label:SetAnchor(CENTER, labelLine, CENTER, 8, 300) label:SetDimensions(25,25) label:SetFont("LeoTrainerLargeFont") end end LeoTrainer.ui.queueScroll = LeoTrainerQueueList:New(LeoTrainerWindowQueuePanelQueueScroll) LeoTrainer.ui.queueScroll:RefreshData() local LeoTrainerCharDropdown = CreateControlFromVirtual('LeoTrainerCharDropdown', LeoTrainerWindow, 'LeoTrainerCharDropdown') LeoTrainerCharDropdown:SetDimensions(200,35) LeoTrainerCharDropdown:SetAnchor(RIGHT, LeoTrainerWindowBlacksmithingButton, LEFT, -50, 4) LeoTrainerCharDropdown.m_comboBox:SetSortsItems(false) local charDropdown = ZO_ComboBox_ObjectFromContainer(LeoTrainerCharDropdown) charDropdown:ClearItems() local defaultItem for _, char in pairs(LeoAltholic.ExportCharacters()) do local entry = charDropdown:CreateItemEntry(char.bio.name, function() LeoTrainer.ui.UpdateUI(char.bio.name) end) if char.bio.name == LeoAltholic.CharName then defaultItem = entry end charDropdown:AddItem(entry) end if defaultItem ~= nil then charDropdown:SelectItem(defaultItem) end end function LeoTrainer.ui.UpdateUI(charName) if charName == nil then charName = LeoAltholic.CharName end local items = {} -- TODO LeoTrainer.ScanBags() local traitIcons = {} for traitItemIndex = 1, GetNumSmithingTraitItems() do local traitType, _, icon, _, _, _, _ = GetSmithingTraitItemInfo(traitItemIndex) if traitType and traitType ~= ITEM_TRAIT_TYPE_NONE then traitIcons[traitType] = icon end end for _,craft in pairs(LeoAltholic.craftResearch) do local panel = WINDOW_MANAGER:GetControlByName('LeoTrainerWindowCraft'..craft.."Panel") if craft == CRAFTING_TYPE_JEWELRYCRAFTING then panel = WINDOW_MANAGER:GetControlByName('LeoTrainerWindowCraft6PanelCraft7Panel') end for line = 1, GetNumSmithingResearchLines(craft) do local lineName, lineIcon, numTraits = GetSmithingResearchLineInfo(craft, line) local knownTraits = 0 for trait = 1, numTraits do local traitType = GetSmithingResearchLineTraitInfo(craft, line, trait) local traitName = GetString('SI_ITEMTRAITTYPE', traitType) local t = WINDOW_MANAGER:GetControlByName('LeoTrainerWindowCraft'..craft..'Line'..line..'Trait'..trait..'Texture') local isKnown = #LeoTrainer.knowledge[craft][line][trait] > 0 local isUnknown = #LeoTrainer.knowledge[craft][line][trait] == 0 local allKnown = #LeoTrainer.missingKnowledge[craft][line][trait] == 0 local hasItem = false for _, itemData in pairs(items) do if itemData.craft == craft and itemData.line == line and itemData.trait == trait then hasItem = LeoTrainer.CanItemBeResearched(itemData.bagId, itemData.slotIndex, itemData.item) if hasItem then break end end end local myself = false for _,knowName in pairs(LeoTrainer.knowledge[craft][line][trait]) do if knowName == charName then myself = true break end end local icon local color if myself == true then icon = 'esoui/art/buttons/accept_up.dds' knownTraits = knownTraits + 1 if allKnown then color = {0,1,0,1} else color = {1,1,0,1} end else icon = 'esoui/art/buttons/decline_up.dds' if isUnknown then color = {1,0,0,1} else color = {1,0.7,0,1} end end if hasItem and not allKnown then icon = 'esoui/art/buttons/pointsplus_up.dds' end t:SetColor(unpack(color)) t:SetTexture(icon) t:SetHandler('OnMouseEnter', function(self) InitializeTooltip(InformationTooltip, self, LEFT, 5, 0) addLineTitle(InformationTooltip, lineName .." - ".. traitName, ZO_TOOLTIP_DEFAULT_COLOR) ZO_Tooltip_AddDivider(InformationTooltip) addLineSubTitle(InformationTooltip, "Trainers", ZO_TOOLTIP_DEFAULT_COLOR, TEXT_ALIGN_LEFT) if allKnown then addLine(InformationTooltip, "All", LeoTrainer.const.colors.green) elseif isKnown then for _, knowName in pairs(LeoTrainer.knowledge[craft][line][trait]) do addLine(InformationTooltip, knowName, LeoTrainer.const.colors.green) end else addLine(InformationTooltip, "None", LeoTrainer.const.colors.red) end addLineSubTitle(InformationTooltip, "Trainees", ZO_TOOLTIP_DEFAULT_COLOR, TEXT_ALIGN_LEFT) if allKnown then addLine(InformationTooltip, "None", LeoTrainer.const.colors.green) elseif isUnknown then addLine(InformationTooltip, "All", LeoTrainer.const.colors.red) else for _, knowName in pairs(LeoTrainer.missingKnowledge[craft][line][trait]) do addLine(InformationTooltip, knowName, LeoTrainer.const.colors.red) end end local inBag = "" local inBank = "" for _, itemData in pairs(items) do if itemData.craft == craft and itemData.line == line and itemData.trait == trait then if LeoTrainer.research.CanItemBeResearched(itemData.bagId, itemData.slotIndex, itemData.item) then if itemData.bagId == BAG_BANK or itemData.bagId == BAG_SUBSCRIBER_BANK then inBank = inBank .."[".. itemData.item .. "] " elseif itemData.bagId == BAG_BACKPACK then inBag = inBag .."[".. itemData.item .. "] " end end end end if inBag ~= "" or inBank ~= "" then addLineSubTitle(InformationTooltip, "Researchable Items", ZO_TOOLTIP_DEFAULT_COLOR, TEXT_ALIGN_LEFT) end if inBag ~= "" then addLine(InformationTooltip, GetString(SI_INVENTORY_MENU_INVENTORY) ..": ".. inBag, LeoTrainer.const.colors.green) end if inBank ~= "" then addLine(InformationTooltip, GetString(SI_CURRENCYLOCATION1) ..": ".. inBank, LeoTrainer.const.colors.green) end if not allKnown and not isUnknown then addLine(InformationTooltip, zo_iconTextFormat("esoui/art/icons/icon_lmb.dds", 26, 26, "Queue 1")) addLine(InformationTooltip, zo_iconTextFormat("esoui/art/icons/icon_rmb.dds", 26, 26, "Queue All")) end InformationTooltip:SetHidden(false) end) if isKnown then t:SetHandler('OnMouseUp', function(control, button, upInside) if not upInside or (button ~= MOUSE_BUTTON_INDEX_RIGHT and button ~= MOUSE_BUTTON_INDEX_LEFT) then return end if #LeoTrainer.missingKnowledge[craft][line][trait] > 0 then --local matReq = LeoTrainer.const.materialRequirements[craft][line] local styleId = LeoTrainer.craft.MaxStyle(line) if trait == 9 and LeoTrainer.data.trainNirnhoned == false then LeoTrainer.log("Nirnhoned training is disabled in settings.") return end local trainerName local _, knownList = getFirstUnknownTraitCanBeTrained(craft, line, {trait}, trainer) for _, knownName in pairs(knownList) do if knownName == LeoTrainer.settings.defaultTrainer then trainerName = knownName break end end if traitName == nil then trainerName = knownList[1] end for _, charName in pairs(LeoTrainer.missingKnowledge[craft][line][trait]) do local traineeName = "Anyone" if button == MOUSE_BUTTON_INDEX_RIGHT then traineeName = charName end LeoTrainer.AddToQueue({ trainer = trainerName, trainee = traineeName, craft = craft, line = line, trait = trait, patternIndex = -1, materialIndex = 1, materialQuantity = -1, itemStyleId = styleId, traitIndex = traitType, useUniversalStyleItem = false, researchName = lineName .. " " .. traitName, itemLink = LeoTrainer.const.craftItems[craft][line][trait], crafted = false }) if button == MOUSE_BUTTON_INDEX_LEFT then break end end LeoTrainer.ui.queueScroll:RefreshData() end end) end end local labelCount = WINDOW_MANAGER:GetControlByName('LeoTrainerWindowCraft'..craft..'Line'..line..'Count') labelCount:SetText(knownTraits) if knownTraits < 2 then labelCount:SetColor(1,0,0,1) elseif knownTraits < 4 then labelCount:SetColor(1,0.7,0,1) elseif knownTraits < 6 then labelCount:SetColor(1,1,0,1) elseif knownTraits == 9 then labelCount:SetColor(0,1,0,1) else labelCount:SetColor(1,1,1,1) end end end LeoTrainer.ui.queueScroll:RefreshData() end function LeoTrainer.GetCraftQueue() return LeoTrainer.data.craftQueue or {} end function LeoTrainer.ClearQueue() LeoTrainer.data.craftQueue = {} LeoTrainer.LLC:cancelItem() LeoTrainer.ui.queueScroll:RefreshData() end function LeoTrainer.AddToQueue(data) for _, item in pairs(LeoTrainer.GetCraftQueue()) do if data.trainer ~= "Anyone" and data.trainee ~= "Anyone" and item.trainer == data.trainer and item.trainee == data.trainee and item.craft == data.craft and item.line == data.line and item.trait == data.trait then return false end end table.insert(LeoTrainer.GetCraftQueue(), data) return true end function LeoTrainer.RemoveFromQueue(pos) local data = LeoTrainer.GetCraftQueue()[pos] table.remove(LeoTrainer.GetCraftQueue(), pos) LeoTrainer.ui.queueScroll:RefreshData() return data end function LeoTrainer.FillMySlots() LeoTrainer.FillSlots(nil, LeoAltholic.CharName) end function LeoTrainer.FillKnownSlots() LeoTrainer.FillSlots(LeoAltholic.CharName, nil) end function LeoTrainer.GetResearchPriority(charName, craftSkill) end local function get(tbl, k, ...) if tbl == nil or tbl[k] == nil then return nil end if select('#', ...) == 0 then return tbl[k] end return get(tbl[k], ...) end local function set(tbl, k, maybeValue, ...) if select('#', ...) == 0 then -- this will throw if the top-level tbl is nil, which is the desired behavior tbl[k] = maybeValue return end if tbl[k] == nil then tbl[k] = {} end set(tbl[k], maybeValue, ...) end function LeoTrainer.FillSlots(trainer, trainee) local lineList = LeoTrainer.GetPriorityLineList() local charList = LeoAltholic.ExportCharacters() local items = LeoTrainer.research.ScanBags() for _, char in pairs(charList) do if (trainee == nil or trainee == char.bio.name) and trainer == nil or (trainer ~= nil and trainer ~= char.bio.name) then for _, craft in pairs(LeoAltholic.craftResearch) do if LeoTrainer.isTrackingSkill(char.bio.name, craft) and LeoTrainer.canFillSlotWithSkill(char.bio.name, craft) then local styleId local max = char.research.done[craft].max - getNumOngoingResearches(char.research, craft) for i = 1, max do for j, lineData in ipairs(lineList[char.bio.name][craft]) do if not lineData.added and not lineData.isResearching then local trait, knownList = getFirstUnknownTraitCanBeTrained(craft, lineData.line, lineData.unknownTraits, trainer) local hasItem = false if trait ~= nil and (trait ~= 9 or LeoTrainer.data.trainNirnhoned == true) then for itemIndex, itemData in pairs(items) do if itemData.selected == false and itemData.craftSkill == craft and itemData.line == lineData.line and itemData.trait == trait then LeoTrainer.debug("Found item for research " .. itemData.itemLink) hasItem = true items[itemIndex].selected = true break end end if not hasItem then local traitType = GetSmithingResearchLineTraitInfo(craft, lineData.line, trait) local traitName = GetString('SI_ITEMTRAITTYPE', traitType) if not styleId then styleId = LeoTrainer.craft.MaxStyle(lineData.line) end local trainerName if trainer ~= nil then trainerName = trainer else for _, knownName in pairs(knownList) do if knownName == LeoTrainer.settings.defaultTrainer then trainerName = knownName break end end if trainerName == nil then trainerName = knownList[1] end end local data = { trainer = trainerName, trainee = char.bio.name, craft = craft, line = lineData.line, trait = trait, patternIndex = -1, materialIndex = 1, materialQuantity = -1, itemStyleId = styleId, traitIndex = traitType, useUniversalStyleItem = false, researchName = lineData.lineName .. " " .. traitName, itemLink = LeoTrainer.const.craftItems[craft][lineData.line][trait], knownList = knownList, crafted = false } if trainer ~= nil then data.trainer = trainer end if trainee ~= nil then data.trainee = trainee end LeoTrainer.AddToQueue(data) end lineList[char.bio.name][craft][j].added = true break end end end end LeoTrainer.ui.queueScroll:RefreshData() end end end end end