-- AI Research Grid Addon for Elder Scrolls Online -- Author: Stormknight/LCAmethyst/CrazyDutchGuy local _ AIRG = {} AIRG.name = "AIResearchGrid" AIRG.version = "1.3.4" AIRG.initialised = false AIRG.processing = false -- Set-up the defaults options for saved variables. AIRG.defaults = { data = {}, styles = {}, showMotifs = true, } AIRG.gridAlignments = { grid_base_height = 636, grid_base_width = 760, styleGrid = { num_styles = 30, height = 120, width = 605, icon_height = 30, icon_width = 30, left_align = 160, top_align = 15, row_length = 15, icon_box_height = 37, icon_box_width = 37, }, } function AIRG.Initialise(eventCode, addOnName) -- Only initialize our own addon if (AIRG.name ~= addOnName) then return end -- Language text AIRG.InitialiseLanguage() -- Load the saved variables AIRG.vars = ZO_SavedVars:NewAccountWide("AIRG_SavedVariables", 2, nil, AIRG.defaults) -- Register Keybinding ZO_CreateStringId("SI_BINDING_NAME_TOGGLE_AIRG", "Toggle AI Research Grid") -- Set-up some variables we'll want to refer to. AIRG.craftNames = {} AIRG.craftNames[CRAFTING_TYPE_BLACKSMITHING] = "BLACKSMITHING" AIRG.craftNames[CRAFTING_TYPE_CLOTHIER] = "CLOTHING" AIRG.craftNames[CRAFTING_TYPE_WOODWORKING] = "WOODWORKING" AIRG.playerName = GetUnitName("player") AIRG.curCharacter = GetUnitName("player") -- Default the display to the current character AIRG.AssignGridTraits() AIRG.AssignStyleLookups() -- Query data for THIS character and populate the data matrix with fresh data. --AIRG.PopulateMatrix() -- Query data for THIS character for STYLES --AIRG.PopulateStyleData() -- UI set-up. Create frames, position labels & buttons etc. AIRG.initUI() -- REGISTER for events that aren't initialise. EVENT_MANAGER:RegisterForEvent("AIRG", EVENT_SMITHING_TRAIT_RESEARCH_STARTED, AIRG.ResearchStarted) EVENT_MANAGER:RegisterForEvent("AIRG", EVENT_SMITHING_TRAIT_RESEARCH_COMPLETED, AIRG.ResearchCompleted) EVENT_MANAGER:RegisterForEvent("AIRG", EVENT_STYLE_LEARNED, AIRG.StyleLearned) EVENT_MANAGER:RegisterForEvent("AIRG", EVENT_PLAYER_ACTIVATED, AIRG.PlayerActivated) -- Create the configuration/settings menu. AIRG.CreateConfigMenu() AIRG.initialised = true end -- AIRG.Initialise EVENT_MANAGER:RegisterForEvent("AIRG", EVENT_ADD_ON_LOADED, AIRG.Initialise) -- SLASH COMMAND FUNCTIONALITY function AIRGslash(extra) AIRG.ToggleMainWindow() end -- AIRGslash SLASH_COMMANDS["/airg"] = AIRGslash function AIRG.PlayerActivated() -- somehow somewhere it sometimes happens that the data is not correct completely for whatever reason -- so we force a reload of the current character data when we are actually loaded into the world. AIRG.PopulateMatrix() AIRG.PopulateStyleData() end function AIRG.ToggleMainWindow() if (AIResearchGrid:IsHidden()) then AIRG.OnCraftSelected() -- Redisplay data for the current profession SetGameCameraUIMode(true) -- Enable mouse pointer AIResearchGrid:SetHidden(false) -- Display the addon AIRG.OnCharacterSelect() else SetGameCameraUIMode(false) -- Enable mouse pointer AIResearchGrid:SetHidden(true) -- Display the addon end end -- AIRG.ToggleMainWindow -- Invoked by EVENT_SMITHING_TRAIT_RESEARCH_STARTED -- (integer eventCode, integer craftingSkillType, luaindex researchLineIndex, luaindex traitIndex) function AIRG.ResearchStarted(eventCode, craftingSkillType, researchLineIndex, traitIndex) AIRG.PopulateMatrix() -- TO DO: If it's visible, invoke a redisplay AIRG.OnCraftSelected() -- Redisplay data for the current profession end -- AIRG.ResearchStarted -- Invoked by EVENT_SMITHING_TRAIT_RESEARCH_COMPLETED -- (integer eventCode, integer craftingSkillType, luaindex researchLineIndex, luaindex traitIndex) function AIRG.ResearchCompleted() AIRG.PopulateMatrix() -- TO DO: If it's visible, invoke a redisplay AIRG.OnCraftSelected() -- Redisplay data for the current profession end -- AIRG.ResearchEnded function AIRG.StyleLearned(eventCode, styleIndex) AIRG.PopulateStyleData() AIRG.DisplayStyles() end -- AIRG.StyleLearned -- Invoked from AIRG.Initialise but lengthy so in it's own function to not clutter Initialise function AIRG.initUI() -- Some local variable declaration local i, j -- used in for loops local thisTrait, tType, tDesc, rowNum, charName -- Initialise a table to hold all the lua generated components AIRG.UI = {} -- Set the main window title AIRG.UI.WindowTitle = WINDOW_MANAGER:CreateControl("AIResearchGridWindowTitle", AIResearchGrid, CT_LABEL) AIRG.UI.WindowTitle:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 0, 0) AIRG.UI.WindowTitle:SetFont("ZoFontAnnounceMedium") AIRG.UI.WindowTitle:SetHorizontalAlignment(TEXT_ALIGN_LEFT) AIRG.UI.WindowTitle:SetText("|c8080ffAI|r RESEARCH GRID") -- Set the main window subtitle AIRG.UI.WindowSubTitle = WINDOW_MANAGER:CreateControl("AIResearchGridWindowSubTitle", AIResearchGrid, CT_LABEL) AIRG.UI.WindowSubTitle:SetAnchor(LEFT, AIRG.UI.WindowTitle, RIGHT, 10, 0) AIRG.UI.WindowSubTitle:SetFont("ZoFontAnnounceMedium") AIRG.UI.WindowSubTitle:SetHorizontalAlignment(TEXT_ALIGN_LEFT) AIRG.UI.WindowSubTitle:SetColor(0, 1, 0, 1); -- green AIRG.UI.WindowSubTitle:SetText("") -- Nice little line under the main title AIRG.UI.TopDivider = WINDOW_MANAGER:CreateControl("AIResearchGridTopDivider", AIResearchGrid, CT_TEXTURE) AIRG.UI.TopDivider:SetDimensions(760, 5) AIRG.UI.TopDivider:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 0, 32) AIRG.UI.TopDivider:SetTexture("/esoui/art/quest/questjournal_divider.dds") -- Nice little line under the grid AIRG.UI.BottomDivider = WINDOW_MANAGER:CreateControl("AIResearchGridBottomDivider", AIResearchGrid, CT_TEXTURE) AIRG.UI.BottomDivider:SetDimensions(760, 5) AIRG.UI.BottomDivider:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 0, 636) AIRG.UI.BottomDivider:SetTexture("/esoui/art/quest/questjournal_divider.dds") AIRG.UI.BottomDivider:SetHidden(not AIRG.vars.showMotifs) -- CREATE BUTTON FOR CLOSE ADDON AT TOP_RIGHT AIRG.UI.btnCloseAddonFrame = WINDOW_MANAGER:CreateControl("AIResearchGridButtonCloseAddon", AIResearchGrid, CT_BUTTON) AIRG.UI.btnCloseAddonFrame:SetDimensions(28, 28) AIRG.UI.btnCloseAddonFrame:SetAnchor(TOPRIGHT, AIResearchGrid, TOPRIGHT, 0 , 0) AIRG.UI.btnCloseAddonFrame:SetState(BSTATE_NORMAL) AIRG.UI.btnCloseAddonFrame:SetMouseOverBlendMode(0) -- AIRG.UI.btnCloseAddonFrame:SetHidden(false) AIRG.UI.btnCloseAddonFrame:SetEnabled(true) -- AIRG.UI.btnCloseAddonFrame:SetClickSound(SOUNDS.WOODWORKER_EXTRACTED_BOOSTER) AIRG.UI.btnCloseAddonFrame:SetNormalTexture("/esoui/art/buttons/clearslot_down.dds") AIRG.UI.btnCloseAddonFrame:SetMouseOverTexture("/esoui/art/buttons/clearslot_up.dds") AIRG.UI.btnCloseAddonFrame:SetHandler("OnClicked", function(self) AIRG.ToggleMainWindow() end) -- CREATE the DROPDOWN BOX for CHARACTER SELECT -- Uses code based on example from Seerah AIRG.UI.charDropdown = WINDOW_MANAGER:CreateControlFromVirtual("AIResearchGridDropdownCharacter", AIResearchGrid, "ZO_StatsDropdownRow") AIRG.UI.charDropdown:SetAnchor(TOPRIGHT, AIResearchGrid, TOPRIGHT, -32, 0) AIRG.UI.charDropdown:GetNamedChild("Dropdown"):SetWidth(200) AIRG.UI.charDropdown.dropdown:SetSelectedItem(AIRG.curCharacter) -- Set the current character as selected local function OnItemSelect(_, choiceText, choice) --this is the callback function for when an item gets selected in the dropdown AIRG.OnCharacterSelect(choiceText) end for charName, _ in pairs(AIRG.vars.data) do local entry = AIRG.UI.charDropdown.dropdown:CreateItemEntry(charName, OnItemSelect) AIRG.UI.charDropdown.dropdown:AddItem(entry) end -- PEOPLE ICON NEXT TO THE DROPDOWN BOX -- AIRG.UI.PeopleIcon = WINDOW_MANAGER:CreateControl("AIResearchGridPeopleIcon", AIResearchGrid, CT_TEXTURE) -- AIRG.UI.PeopleIcon:SetDimensions(40, 32) -- AIRG.UI.PeopleIcon:SetAnchor(TOPRIGHT, AIRG.UI.charDropdown, TOPLEFT, 0, 0) -- AIRG.UI.PeopleIcon:SetTexture("/esoui/art/contacts/tabicon_friends_down.dds") -- CREATE BUTTON FOR PROFESSION: BLACKSMITHING AIRG.UI.btnBlacksmithing = WINDOW_MANAGER:CreateControl("AIResearchGridButtonBlacksmithing", AIResearchGrid, CT_BUTTON) AIRG.UI.btnBlacksmithing:SetDimensions(48, 48) AIRG.UI.btnBlacksmithing:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 8 , 44) AIRG.UI.btnBlacksmithing:SetState(BSTATE_NORMAL) AIRG.UI.btnBlacksmithing:SetMouseOverBlendMode(0) AIRG.UI.btnBlacksmithing:SetHidden(false) AIRG.UI.btnBlacksmithing:SetEnabled(true) AIRG.UI.btnBlacksmithing:SetClickSound(SOUNDS.WOODWORKER_EXTRACTED_BOOSTER) AIRG.UI.btnBlacksmithing:SetNormalTexture("/esoui/art/icons/ability_smith_007.dds") AIRG.UI.btnBlacksmithing:SetMouseOverTexture("ESOUI/art/buttons/generic_highlight.dds") AIRG.UI.btnBlacksmithing:SetHandler("OnClicked", function(self) AIRG:OnCraftSelected(CRAFTING_TYPE_BLACKSMITHING) end) -- CREATE BUTTON FOR PROFESSION: WOODWORKING AIRG.UI.btnWoodworking = WINDOW_MANAGER:CreateControl("AIResearchGridButtonWoodworking", AIResearchGrid, CT_BUTTON) AIRG.UI.btnWoodworking:SetDimensions(48, 48) AIRG.UI.btnWoodworking:SetAnchor(TOPLEFT, AIRG.UI.btnBlacksmithing, TOPRIGHT, 12 , 0) AIRG.UI.btnWoodworking:SetState(BSTATE_NORMAL) AIRG.UI.btnWoodworking:SetMouseOverBlendMode(0) AIRG.UI.btnWoodworking:SetHidden(false) AIRG.UI.btnWoodworking:SetEnabled(true) AIRG.UI.btnWoodworking:SetClickSound(SOUNDS.BLACKSMITH_EXTRACTED_BOOSTER) AIRG.UI.btnWoodworking:SetNormalTexture("/esoui/art/icons/ability_tradecraft_009.dds") AIRG.UI.btnWoodworking:SetMouseOverTexture("ESOUI/art/buttons/generic_highlight.dds") AIRG.UI.btnWoodworking:SetHandler("OnClicked", function(self) AIRG:OnCraftSelected(CRAFTING_TYPE_WOODWORKING) end) -- CREATE BUTTON FOR PROFESSION: CLOTHING AIRG.UI.btnClothing = WINDOW_MANAGER:CreateControl("AIResearchGridButtonClothing", AIResearchGrid, CT_BUTTON) AIRG.UI.btnClothing:SetDimensions(48, 48) AIRG.UI.btnClothing:SetAnchor(TOPLEFT, AIRG.UI.btnWoodworking, TOPRIGHT, 12 , 0) AIRG.UI.btnClothing:SetState(BSTATE_NORMAL) AIRG.UI.btnClothing:SetMouseOverBlendMode(0) AIRG.UI.btnClothing:SetHidden(false) AIRG.UI.btnClothing:SetEnabled(true) AIRG.UI.btnClothing:SetClickSound(SOUNDS.CLOTHIER_EXTRACTED_BOOSTER) AIRG.UI.btnClothing:SetNormalTexture("/esoui/art/icons/ability_tradecraft_008.dds") AIRG.UI.btnClothing:SetMouseOverTexture("ESOUI/art/buttons/generic_highlight.dds") AIRG.UI.btnClothing:SetHandler("OnClicked", function(self) AIRG:OnCraftSelected(CRAFTING_TYPE_CLOTHIER) end) -- BUILD THE TRAIT LABELS ON THE LEFT-SIDE using built-in language strings AIRG.UI.rowLabels = {} for thisTrait, j in pairs(AIRG.gridTraits) do AIRG.UI.rowLabels[j] = WINDOW_MANAGER:CreateControl("AIResearchGridRowLabel" .. tostring(j), AIResearchGrid, CT_LABEL) AIRG.UI.rowLabels[j]:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 5, 28*j + 70) AIRG.UI.rowLabels[j]:SetText(GetString("SI_ITEMTRAITTYPE",thisTrait)) -- This is the text displayed on the screen as it's a label AIRG.UI.rowLabels[j]:SetDimensions(180, 24) AIRG.UI.rowLabels[j]:SetFont("ZoFontGame") AIRG.UI.rowLabels[j]:SetHorizontalAlignment(TEXT_ALIGN_RIGHT) AIRG.UI.rowLabels[j]:SetVerticalAlignment(TEXT_ALIGN_CENTER) AIRG.UI.rowLabels[j]:SetMouseEnabled(true) AIRG.UI.rowLabels[j]:SetHandler("OnMouseEnter", function (self) ZO_Tooltips_ShowTextTooltip(self, TOP, self.tooltipText) end) AIRG.UI.rowLabels[j]:SetHandler("OnMouseExit", function (self) ZO_Tooltips_HideTextTooltip() end) end -- Now add tooltip text to the row labels. -- The tooltip functionality is automatic as part of the label control. for j = 1, 9 do tType, tDesc, _ = GetSmithingResearchLineTraitInfo(CRAFTING_TYPE_BLACKSMITHING,1,j) -- weapons rowNum = AIRG.gridTraits[tType] AIRG.UI.rowLabels[rowNum].tooltipText = tDesc tType, tDesc, _ = GetSmithingResearchLineTraitInfo(CRAFTING_TYPE_BLACKSMITHING,9,j) -- armour rowNum = AIRG.gridTraits[tType] AIRG.UI.rowLabels[rowNum].tooltipText = tDesc end -- BUILD THE COLUMNS & GRID -- Determine the maximum number of item types across all three professions. This is currently always 14 AIRG.maxColumns= math.max(GetNumSmithingResearchLines(CRAFTING_TYPE_BLACKSMITHING), GetNumSmithingResearchLines(CRAFTING_TYPE_CLOTHIER), GetNumSmithingResearchLines(CRAFTING_TYPE_WOODWORKING)) AIRG.UI.columnButtons = {} AIRG.UI.gridButtons = {} AIRG.UI.columnFooters = {} for i = 1, AIRG.maxColumns do -- BUILD THE COLUMN BUTTONS AIRG.UI.columnButtons[i] = WINDOW_MANAGER:CreateControl("AIResearchGridHeaderButton" .. tostring(i), AIResearchGrid, CT_BUTTON) AIRG.UI.columnButtons[i]:SetDimensions(36, 36) AIRG.UI.columnButtons[i]:SetState(BSTATE_NORMAL) AIRG.UI.columnButtons[i]:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 40*i + 150, 55) AIRG.UI.columnButtons[i]:SetHidden(true) AIRG.UI.columnButtons[i]:SetEnabled(true) AIRG.UI.columnButtons[i]:SetMouseOverTexture("ESOUI/art/buttons/generic_highlight.dds") AIRG.UI.columnButtons[i].text = i AIRG.UI.columnButtons[i]:SetHandler("OnMouseEnter", function (self) ZO_Tooltips_ShowTextTooltip(self, TOP, self.text) end) AIRG.UI.columnButtons[i]:SetHandler("OnMouseExit", function (self) ZO_Tooltips_HideTextTooltip() end) -- BUILD THE GRID -- There are a total of 18 traits possible. 9 armour and 9 weapon (Infused, Training and Nirnhoned on both) AIRG.UI.gridButtons[i] = {} for j = 1, 18 do AIRG.UI.gridButtons[i][j] = WINDOW_MANAGER:CreateControl("AIResearchGridGridButton" .. tostring(i) .. "x" .. tostring(j), AIResearchGrid, CT_TEXTURE) AIRG.UI.gridButtons[i][j]:SetDimensions(24, 24) AIRG.UI.gridButtons[i][j]:SetAnchor(TOP, AIRG.UI.columnButtons[i], BOTTOM, 0, 28*j -20) AIRG.UI.gridButtons[i][j]:SetTexture("/esoui/art/buttons/swatchframe_down.dds") AIRG.UI.gridButtons[i][j]:SetColor(1, 1, 1, 0.4) AIRG.UI.gridButtons[i][j]:SetHidden(false) AIRG.UI.gridButtons[i][j]:SetMouseEnabled(false) -- Following tooltip code uses ideas contributed by Krysstof AIRG.UI.gridButtons[i][j]:SetHandler("OnMouseEnter", function (self) if (self.tooltipText > 0) then -- Check the item is being researched and has a timestamp local tRemaining = tonumber(self.tooltipText) - GetTimeStamp() local tFormatted = FormatTimeSeconds(tRemaining, TIME_FORMAT_STYLE_DESCRIPTIVE_SHORT, TIME_FORMAT_PRECISION_SECONDS, TIME_FORMAT_DIRECTION_DESCENDING) ZO_Tooltips_ShowTextTooltip(self, RIGHT, tFormatted) -- loop with "registerforupdate" once per second EVENT_MANAGER:RegisterForUpdate(self.name, 1000, function() local tRemaining = tonumber(self.tooltipText) - GetTimeStamp() local tFormatted = FormatTimeSeconds(tRemaining, TIME_FORMAT_STYLE_DESCRIPTIVE_SHORT, TIME_FORMAT_PRECISION_SECONDS, TIME_FORMAT_DIRECTION_DESCENDING) ZO_Tooltips_ShowTextTooltip(self, RIGHT, tFormatted) end) end end) AIRG.UI.gridButtons[i][j]:SetHandler("OnMouseExit", function (self) -- unregister the update event or it keeps on displaying EVENT_MANAGER:UnregisterForUpdate(self.name) ZO_Tooltips_HideTextTooltip() end) end -- BUILD THE COLUMN FOOTERS AIRG.UI.columnFooters[i] = WINDOW_MANAGER:CreateControl("AIResearchGridColumnFooterLabel" .. tostring(i), AIResearchGrid, CT_LABEL) AIRG.UI.columnFooters[i]:SetAnchor(TOP, AIRG.UI.columnButtons[i], BOTTOM, 0, 516) AIRG.UI.columnFooters[i]:SetDimensions(36, 24) AIRG.UI.columnFooters[i]:SetFont("ZoFontGame") AIRG.UI.columnFooters[i]:SetHorizontalAlignment(TEXT_ALIGN_CENTER) AIRG.UI.columnFooters[i]:SetVerticalAlignment(TEXT_ALIGN_CENTER) AIRG.UI.columnFooters[i]:SetColor(1, 1, 0.4, 1); -- faded yellow end -- BUILD LABEL FOR COLUMN FOOTER "TRAIT LINE" AIRG.UI.columnFooterTitle = WINDOW_MANAGER:CreateControl("AIResearchGridColumnFooterTitleLabel", AIResearchGrid, CT_LABEL) AIRG.UI.columnFooterTitle:SetAnchor(TOPLEFT, AIResearchGrid, TOPLEFT, 5, 606) AIRG.UI.columnFooterTitle:SetDimensions(180, 24) AIRG.UI.columnFooterTitle:SetFont("ZoFontGame") AIRG.UI.columnFooterTitle:SetHorizontalAlignment(TEXT_ALIGN_RIGHT) AIRG.UI.columnFooterTitle:SetVerticalAlignment(TEXT_ALIGN_CENTER) AIRG.UI.columnFooterTitle:SetColor(1, 1, 0.4, 1); -- faded yellow -- AIRG.UI.columnFooterTitle:SetText(GetString(SI_SMITHING_RESEARCH_LINE_HEADER)) AIRG.UI.columnFooterTitle:SetText(GetString(SI_CRAFTING_COMPONENT_TOOLTIP_TRAITS)) -- BUILD THE MOTIF ICONS ACROSS THE BOTTOM -- Note that for now, we're just setting up 15 icons and stuff is configured manually -- but we can fix it later. It's not like it's going to have an overhead on processing. :) -- It's set-up inside a container frame to make hiding or showing the whole lot simpler. AIRG.UI.motifSection = WINDOW_MANAGER:CreateControl("AIResearchMotifSection", AIResearchGrid, CT_CONTROL) AIRG.UI.motifSection:SetDimensions(AIRG.gridAlignments.grid_base_width, AIRG.gridAlignments.styleGrid.height) AIRG.UI.motifSection:SetAnchor(BOTTOMLEFT, AIResearchGrid, BOTTOMLEFT, 0, 0) AIRG.UI.motifSection:SetHidden(not AIRG.vars.showMotifs) AIResearchGrid:SetHeight(AIRG.vars.showMotifs and AIRG.gridAlignments.grid_base_height + AIRG.gridAlignments.styleGrid.height or AIRG.gridAlignments.grid_base_height) AIRG.UI.motifButtons = {} local currentColumn = 0 local currentRow = 0 for i = 1, AIRG.gridAlignments.styleGrid.num_styles do currentColumn = currentColumn + 1 AIRG.UI.motifButtons[i] = WINDOW_MANAGER:CreateControl("AIResearchGridMotifButton" .. tostring(i), AIRG.UI.motifSection, CT_TEXTURE) AIRG.UI.motifButtons[i]:SetDimensions(AIRG.gridAlignments.styleGrid.icon_width, AIRG.gridAlignments.styleGrid.icon_height) if currentColumn > AIRG.gridAlignments.styleGrid.row_length then currentRow = currentRow + 1 currentColumn = currentColumn - AIRG.gridAlignments.styleGrid.row_length end local yVal = AIRG.gridAlignments.styleGrid.top_align + (AIRG.gridAlignments.styleGrid.icon_box_height * currentRow) local xVal = AIRG.gridAlignments.styleGrid.icon_box_width * currentColumn + AIRG.gridAlignments.styleGrid.left_align AIRG.UI.motifButtons[i]:SetAnchor(TOPLEFT, AIRG.UI.motifSection, TOPLEFT, xVal, yVal) AIRG.UI.motifButtons[i]:SetTexture(AIRG.styleLookupIcons[i] .. "up.dds") AIRG.UI.motifButtons[i]:SetMouseEnabled(true) j = AIRG.styleLookupValue[i] tDesc ,_,_,_,_ = GetSmithingStyleItemInfo( AIRG.styleLookupItem[i] ) AIRG.UI.motifButtons[i].tooltipText = zo_strformat("<<t:1>>\n<<t:2>>", GetString("SI_ITEMSTYLE",j), tDesc) AIRG.UI.motifButtons[i]:SetHandler("OnMouseEnter", function (self) ZO_Tooltips_ShowTextTooltip(self, TOP, self.tooltipText) end) AIRG.UI.motifButtons[i]:SetHandler("OnMouseExit", function (self) ZO_Tooltips_HideTextTooltip() end) end -- BUILD LABEL FOR STYLES AIRG.UI.StyleLabel = WINDOW_MANAGER:CreateControl("AIResearchStylelabel", AIRG.UI.motifSection, CT_LABEL) AIRG.UI.StyleLabel:SetAnchor(TOPLEFT, AIRG.UI.motifSection, TOPLEFT, 5, 14) AIRG.UI.StyleLabel:SetText(GetString(SI_SMITHING_HEADER_STYLE)) AIRG.UI.StyleLabel:SetDimensions(180, 24) AIRG.UI.StyleLabel:SetFont("ZoFontGame") AIRG.UI.StyleLabel:SetHorizontalAlignment(TEXT_ALIGN_RIGHT) end -- AIRG.initUI -- User has clicked on one of the profession buttons -- or we just want to refresh the display with current data function AIRG.OnCraftSelected(_,thisCraft) if (thisCraft == nil) then if (AIRG.curCraft == nil) then return else thisCraft = AIRG.curCraft end end AIRG.UI.WindowSubTitle:SetText(AIRG.craftNames[thisCraft]) local i,j local tType,tDesc,tKnown,tRemain,rowNum,traitCount local maxLines = GetNumSmithingResearchLines(thisCraft) -- the number of columns for this profession AIRG.curCraft = thisCraft for i = 1, AIRG.maxColumns do -- "blank" the grid for j = 1, 18 do AIRG.UI.gridButtons[i][j]:SetColor(1, 1, 1, 0.4) AIRG.UI.gridButtons[i][j]:SetTexture("/esoui/art/buttons/swatchframe_down.dds") AIRG.UI.gridButtons[i][j]:SetMouseEnabled(false) -- effectively disable tooltip for this grid item. end if (i > maxLines) then AIRG.UI.columnButtons[i]:SetHidden(true) AIRG.UI.columnFooters[i]:SetText("") else local name, icon, _, _ = GetSmithingResearchLineInfo(thisCraft, i) -- Get info on that specific item AIRG.UI.columnButtons[i]:SetNormalTexture(icon) AIRG.UI.columnButtons[i]:SetHidden(false) AIRG.UI.columnButtons[i].text = name traitCount = 0 for rowNum,tKnown in pairs(AIRG.vars.data[AIRG.curCharacter][thisCraft][i]) do AIRG.UI.gridButtons[i][rowNum].tooltipText = tKnown if (tKnown == -1) then -- Trait is known AIRG.UI.gridButtons[i][rowNum]:SetColor(0.2, 1, 0.2, 1) -- Green AIRG.UI.gridButtons[i][rowNum]:SetTexture("/esoui/art/loot/loot_finesseitem.dds") traitCount = traitCount + 1 elseif (tKnown > 0) then -- Trait is being researched AIRG.UI.gridButtons[i][rowNum]:SetTexture("ESOUI/art/tutorial/timer_icon.dds") if (tKnown < GetTimeStamp()) then -- This is on another character and the timer has completed. AIRG.UI.gridButtons[i][rowNum]:SetColor(0.2, 1, 0.2, 1) -- Green traitCount = traitCount + 1 else AIRG.UI.gridButtons[i][rowNum]:SetColor(0.5, 0.5, 1, 1) -- Blue AIRG.UI.gridButtons[i][rowNum]:SetMouseEnabled(true) end else -- Trait is NOT known AIRG.UI.gridButtons[i][rowNum]:SetColor(1, 0.2, 0.2, 1) -- Red AIRG.UI.gridButtons[i][rowNum]:SetTexture("ESOUI/art/buttons/decline_up.dds") end end if (traitCount > 0) then AIRG.UI.columnFooters[i]:SetText(traitCount) else AIRG.UI.columnFooters[i]:SetText("") end end end end -- AIRG:OnCraftSelected -- Invoked when the user selected a character from the dropdown box function AIRG.OnCharacterSelect(charName) if (charName == nil) then else AIRG.curCharacter = charName end AIRG.DisplayStyles() AIRG.OnCraftSelected() end -- AIRG.OnCharacterSelect -- Deletes data for the named character from the saved data and removes them from the dropdown box. function AIRG.DeleteCharacter(charName) -- Can't delete the current character if (charName == AIRG.playerName) then d(AIRG.L["DeleteFalse"]) else if (AIRG.vars.data[charName] ~= nil) then AIRG.vars.data[charName] = nil d(AIRG.L["DeleteTrue"] .. charName) end if (AIRG.vars.styles[charName] ~= nil) then AIRG.vars.styles[charName] = nil end end end -- AIRG.DeleteCharacter -- This function cycles through all three professions and populates the data matrix for THIS character. -- This is carried out when the addon loasd to ensure the current character data is up-to-date. -- The "if" logic in this function guesses at which profession should be default to display as the one with most research in. function AIRG.PopulateMatrix() local curCount = 0 local thisCount AIRG.vars.data[AIRG.playerName] = {} -- create a table for this character's matrix thisCount = AIRG.CreateDataMatrix(CRAFTING_TYPE_BLACKSMITHING) if (thisCount > curCount) then AIRG.curCraft = CRAFTING_TYPE_BLACKSMITHING curCount = thisCount end thisCount = AIRG.CreateDataMatrix(CRAFTING_TYPE_CLOTHIER) if (thisCount > curCount) then AIRG.curCraft = CRAFTING_TYPE_CLOTHIER curCount = thisCount end thisCount = AIRG.CreateDataMatrix(CRAFTING_TYPE_WOODWORKING) if (thisCount > curCount) then AIRG.curCraft = CRAFTING_TYPE_WOODWORKING curCount = thisCount end if (AIRG.curCraft == nil) then AIRG.curCraft = CRAFTING_TYPE_BLACKSMITHING end end -- AIRG.PopulateMatrix -- Lookup the style data for the current character and send it to saved vars. function AIRG.PopulateStyleData() AIRG.vars.styles[AIRG.playerName] = {} -- create a table for this character's matrix local i, j for i = 1, AIRG.gridAlignments.styleGrid.num_styles do j = AIRG.styleLookupItem[i] AIRG.vars.styles[AIRG.playerName][i] = IsSmithingStyleKnown(j, 1) --patternIndex set to 1, temporary workaround for changes introduced in Update 4 end end -- AIRG.PopulateStyleData -- Set the icon highlights for the currently selected character function AIRG.DisplayStyles() local i if (AIRG.vars.styles[AIRG.curCharacter] == nil) then for i = 1, 30 do AIRG.UI.motifButtons[i]:SetTexture(AIRG.styleLookupIcons[i] .. "up.dds") AIRG.UI.motifButtons[i]:SetColor(1, 1, 1, 0.7) -- grey end else for i = 1, 30 do if (AIRG.vars.styles[AIRG.curCharacter][i]) then AIRG.UI.motifButtons[i]:SetTexture(AIRG.styleLookupIcons[i] .. "down.dds") AIRG.UI.motifButtons[i]:SetColor(0.7, 1, 0.7, 1) -- Green else AIRG.UI.motifButtons[i]:SetTexture(AIRG.styleLookupIcons[i] .. "up.dds") AIRG.UI.motifButtons[i]:SetColor(1, 1, 1, 0.7) -- grey end end end end -- AIRG.DisplayStyles() -- Look up all the data on this profession and commit to saved variables for this character. -- TO DO: At some point, get clever with storing the timestamp for when research will be complete function AIRG.CreateDataMatrix(thisCraft) local i, j local tType, tKnown, tRemain, rowNum, tTargetStamp local rCount = 0 local maxLines = GetNumSmithingResearchLines(thisCraft) -- the number of columns for this profession AIRG.vars.data[AIRG.playerName][thisCraft] = {} -- create a table for this profession -- Cycle through items for this profession for i = 1, maxLines do AIRG.vars.data[AIRG.playerName][thisCraft][i] = {} -- create a table for this item -- Cycle through the traits for this item for j = 1, 9 do tType,_,tKnown = GetSmithingResearchLineTraitInfo(thisCraft,i,j) _,tRemain = GetSmithingResearchLineTraitTimes(thisCraft,i,j) rowNum = AIRG.gridTraits[tType] if (tKnown) then AIRG.vars.data[AIRG.playerName][thisCraft][i][rowNum] = -1 -- this trait is known rCount = rCount + 1 else if (tRemain) then tTargetStamp = GetTimeStamp() + tRemain AIRG.vars.data[AIRG.playerName][thisCraft][i][rowNum] = tTargetStamp -- this trait is being currently researched -- The value we are setting this to is the timestamp for when the research will be complete. else AIRG.vars.data[AIRG.playerName][thisCraft][i][rowNum] = 0 -- this trait is NOT known end end end end return rCount -- the total number of traits already researched in this profession end -- AIRG.CreateDataMatrix function AIRG.AssignGridTraits() -- Translates the traitType to the correct ROW of the grid AIRG.gridTraits = {} AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_POWERED] = 1 AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_CHARGED] = 2 AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_PRECISE] = 3 AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_INFUSED] = 4 AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_DEFENDING] = 5 AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_TRAINING] = 6 AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_SHARPENED] = 7 AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_WEIGHTED] = 8 AIRG.gridTraits[ITEM_TRAIT_TYPE_WEAPON_NIRNHONED] = 9 AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_STURDY] = 10 AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_IMPENETRABLE] = 11 AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_REINFORCED] = 12 AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_WELL_FITTED] = 13 AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_TRAINING] = 14 AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_INFUSED] = 15 AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_EXPLORATION] = 16 AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_DIVINES] = 17 AIRG.gridTraits[ITEM_TRAIT_TYPE_ARMOR_NIRNHONED] = 18 end -- AIRG.AssignGridTraits function AIRG.AssignStyleLookups() -- Lookup the correct icon for the style AIRG.styleLookupIcons = {} AIRG.styleLookupIcons[1] = "ESOUI/art/charactercreate/charactercreate_altmericon_" AIRG.styleLookupIcons[2] = "ESOUI/art/charactercreate/charactercreate_argonianicon_" AIRG.styleLookupIcons[3] = "ESOUI/art/charactercreate/charactercreate_bosmericon_" AIRG.styleLookupIcons[4] = "ESOUI/art/charactercreate/charactercreate_bretonicon_" AIRG.styleLookupIcons[5] = "ESOUI/art/charactercreate/charactercreate_dunmericon_" AIRG.styleLookupIcons[6] = "ESOUI/art/charactercreate/charactercreate_khajiiticon_" AIRG.styleLookupIcons[7] = "ESOUI/art/charactercreate/charactercreate_nordicon_" AIRG.styleLookupIcons[8] = "ESOUI/art/charactercreate/charactercreate_orcicon_" AIRG.styleLookupIcons[9] = "ESOUI/art/charactercreate/charactercreate_redguardicon_" AIRG.styleLookupIcons[10] = "ESOUI/art/charactercreate/charactercreate_imperialicon_" AIRG.styleLookupIcons[11] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[12] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[13] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[14] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[15] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[16] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[17] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[18] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[19] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[20] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[21] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[22] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[23] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[24] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[25] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[26] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[27] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[28] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[29] = "ESOUI/art/progression/progression_indexicon_weapons_" AIRG.styleLookupIcons[30] = "ESOUI/art/progression/progression_indexicon_weapons_" -- Translate the icon position to the in-game type. Used for text look-up AIRG.styleLookupValue = {} AIRG.styleLookupValue[1] = ITEMSTYLE_RACIAL_HIGH_ELF AIRG.styleLookupValue[2] = ITEMSTYLE_RACIAL_ARGONIAN AIRG.styleLookupValue[3] = ITEMSTYLE_RACIAL_WOOD_ELF AIRG.styleLookupValue[4] = ITEMSTYLE_RACIAL_BRETON AIRG.styleLookupValue[5] = ITEMSTYLE_RACIAL_DARK_ELF AIRG.styleLookupValue[6] = ITEMSTYLE_RACIAL_KHAJIIT AIRG.styleLookupValue[7] = ITEMSTYLE_RACIAL_NORD AIRG.styleLookupValue[8] = ITEMSTYLE_RACIAL_ORC AIRG.styleLookupValue[9] = ITEMSTYLE_RACIAL_REDGUARD AIRG.styleLookupValue[10] = ITEMSTYLE_RACIAL_IMPERIAL AIRG.styleLookupValue[11] = ITEMSTYLE_AREA_ANCIENT_ELF AIRG.styleLookupValue[12] = ITEMSTYLE_AREA_REACH AIRG.styleLookupValue[13] = ITEMSTYLE_ENEMY_PRIMITIVE AIRG.styleLookupValue[14] = ITEMSTYLE_ENEMY_DAEDRIC AIRG.styleLookupValue[15] = ITEMSTYLE_AREA_DWEMER AIRG.styleLookupValue[16] = ITEMSTYLE_GLASS AIRG.styleLookupValue[17] = ITEMSTYLE_AREA_XIVKYN AIRG.styleLookupValue[18] = ITEMSTYLE_AREA_AKAVIRI AIRG.styleLookupValue[19] = ITEMSTYLE_UNDAUNTED AIRG.styleLookupValue[20] = ITEMSTYLE_AREA_ANCIENT_ORC AIRG.styleLookupValue[21] = ITEMSTYLE_DEITY_TRINIMAC AIRG.styleLookupValue[22] = ITEMSTYLE_DEITY_MALACATH AIRG.styleLookupValue[23] = ITEMSTYLE_ORG_OUTLAW AIRG.styleLookupValue[24] = ITEMSTYLE_ALLIANCE_ALDMERI AIRG.styleLookupValue[25] = ITEMSTYLE_ALLIANCE_DAGGERFALL AIRG.styleLookupValue[26] = ITEMSTYLE_ALLIANCE_EBONHEART AIRG.styleLookupValue[27] = ITEMSTYLE_AREA_SOUL_SHRIVEN AIRG.styleLookupValue[28] = ITEMSTYLE_ORG_ABAHS_WATCH AIRG.styleLookupValue[29] = ITEMSTYLE_ORG_THIEVES_GUILD AIRG.styleLookupValue[30] = ITEMSTYLE_ORG_ASSASSINS -- This is a bit of a hack, but only because of the way ESO uses Style Items with different index to styles. AIRG.styleLookupItem = {} AIRG.styleLookupItem[1] = 8 -- Altmer = Adamantite AIRG.styleLookupItem[2] = 7 -- Argonian = Flint AIRG.styleLookupItem[3] = 9 -- Bosmer = Bone AIRG.styleLookupItem[4] = 2 -- Breton = Molybdenum AIRG.styleLookupItem[5] = 5 -- Dunmer = Obsidian AIRG.styleLookupItem[6] = 10 -- Khajit = Moonstone AIRG.styleLookupItem[7] = 6 -- Nord = Corundum AIRG.styleLookupItem[8] = 4 -- Orc = Manganese AIRG.styleLookupItem[9] = 3 -- Redguard = Starmetal AIRG.styleLookupItem[10] = 35 -- Imperial = Nickel AIRG.styleLookupItem[11] = 16 -- Ancient Elf = Palladium AIRG.styleLookupItem[12] = 18 -- Barbarian = Copper AIRG.styleLookupItem[13] = 20 -- Primal = Argentum AIRG.styleLookupItem[14] = 21 -- Daedric = Daedra Heart AIRG.styleLookupItem[15] = 15 -- Dwemer = Dwemer Frame AIRG.styleLookupItem[16] = 29 -- Glass = Malachite AIRG.styleLookupItem[17] = 30 -- Xivkyn = Charcoal of Remorse AIRG.styleLookupItem[18] = 34 -- Akaviri = Gold Scale AIRG.styleLookupItem[19] = 27 -- Mercenary = Laurels AIRG.styleLookupItem[20] = 23 -- Ancient Orc = Casserite AIRG.styleLookupItem[21] = 22 -- Trinimac = Auric Tusk AIRG.styleLookupItem[22] = 14 -- Malacath = Potash AIRG.styleLookupItem[23] = 48 -- Outlaw = Rogue's Soot AIRG.styleLookupItem[24] = 26 -- Aldmeri Dominion = Eagle Feather AIRG.styleLookupItem[25] = 24 -- Daggerfall Covenant = Lion Fang AIRG.styleLookupItem[26] = 25 -- Ebonheart Pact = Dragon Scute AIRG.styleLookupItem[27] = 31 -- Soul Shriven = Azure Plasm AIRG.styleLookupItem[28] = 42 -- Abah's Watch = Polished Shilling AIRG.styleLookupItem[29] = 12 -- Thieves' Guild = Fine Chalk AIRG.styleLookupItem[30] = 47 -- Assassin's League = Tainted Blood end -- AIRG.AssignStyleLookups -- EOF