LeoAltholic.timerQueue = {} LeoAltholic.charList = {} LeoAltholic.lastUpdatedCharList = nil LeoAltholic.myself = nil LeoAltholic.myselfIndex = 0 LeoAltholic.initialized = false LeoAltholic.numUpdates = 0 LeoAltholic.maxTraits = select(3,GetSmithingResearchLineInfo(1,1)) LeoAltholic.jewelryMaxTraits = select(3,GetSmithingResearchLineInfo(7,1)) LeoAltholic.panelList = { "Bio", "Stats", "Skills", "Skills2", "Champion", "Tracked", "Writs", "Inventory", "Research" } LeoAltholic.craftResearch = {CRAFTING_TYPE_BLACKSMITHING,CRAFTING_TYPE_CLOTHIER,CRAFTING_TYPE_WOODWORKING,CRAFTING_TYPE_JEWELRYCRAFTING} local function loadPlayerDataPart(skillType, baseElem) if skillType == nil then return end local numSkillLines = GetNumSkillLines(skillType) for i = 1, numSkillLines do local name, rank, discovered, lineId, advised, unlockText = GetSkillLineInfo(skillType,i) if name == nil then name = i; end if discovered then baseElem[i] = {} local baseElemTable = baseElem[i] local qty = GetNumSkillAbilities(skillType, i) baseElemTable.name = name baseElemTable.id = i baseElemTable.qty = qty baseElemTable.rank = rank baseElemTable.lineId = lineId baseElemTable.list = {} for aj = 1, qty do local name2, icon, earnedRank, passive, ultimate, purchased, progressionIndex = GetSkillAbilityInfo(skillType, i, aj) local currentUpgradeLevel, maxUpgradeLevel = GetSkillAbilityUpgradeInfo(skillType, i, aj) if rank >= earnedRank then local _, _, nextUpgradeEarnedRank = GetSkillAbilityNextUpgradeInfo(skillType, i, aj) local plainName = zo_strformat(SI_ABILITY_NAME, name2) name2 = ZO_Skills_GenerateAbilityName(SI_ABILITY_NAME_AND_UPGRADE_LEVELS, name2, currentUpgradeLevel, maxUpgradeLevel, progressionIndex) baseElemTable.list[aj] = {} local selL = baseElemTable.list[aj] selL.plainName = plainName selL.name = name2 selL.earnedRank = earnedRank or 0 selL.level = currentUpgradeLevel selL.maxLevel = maxUpgradeLevel selL.nextUpgradeEarnedRank = nextUpgradeEarnedRank if passive then selL.passive = passive end if ultimate then selL.ultimate = ultimate end end end end end end function LeoAltholic.GetCraftFromQuest(questName) if not string.find(zo_strformat("<<z:1>>",questName), zo_strformat("<<z:1>>",GetString(LEOALT_WRIT))) then return nil end if string.find(zo_strformat("<<z:1>>",questName), zo_strformat("<<z:1>>",GetString(LEOALT_ALCHEMIST))) then return CRAFTING_TYPE_ALCHEMY end if string.find(zo_strformat("<<z:1>>",questName), zo_strformat("<<z:1>>",GetString(LEOALT_BLACKSMITH))) then return CRAFTING_TYPE_BLACKSMITHING end if string.find(zo_strformat("<<z:1>>",questName), zo_strformat("<<z:1>>",GetString(LEOALT_CLOTHIER))) then return CRAFTING_TYPE_CLOTHIER end if string.find(zo_strformat("<<z:1>>",questName), zo_strformat("<<z:1>>",GetString(LEOALT_ENCHANTER))) then return CRAFTING_TYPE_ENCHANTING end if string.find(zo_strformat("<<z:1>>",questName), zo_strformat("<<z:1>>",GetString(LEOALT_JEWELRY))) then return CRAFTING_TYPE_JEWELRYCRAFTING end if string.find(zo_strformat("<<z:1>>",questName), zo_strformat("<<z:1>>",GetString(LEOALT_PROVISIONER))) then return CRAFTING_TYPE_PROVISIONING end if string.find(zo_strformat("<<z:1>>",questName), zo_strformat("<<z:1>>",GetString(LEOALT_WOODWORKER))) then return CRAFTING_TYPE_WOODWORKING end return nil end local function createQuestEntry(questId) local questName,backgroundText,activeStepText,activeStepType, activeStepTrackerOverrideText, completed, tracked, questLevel,pushed,questType,instanceDisplayType = GetJournalQuestInfo(questId) local repeatType = GetJournalQuestRepeatType(questId) local locationInfo if questType == QUEST_TYPE_GUILD then locationInfo = GetString(SI_QUESTTYPE3) elseif questType == QUEST_TYPE_MAIN_STORY then locationInfo = GetString(SI_QUESTTYPE2) else locationInfo = GetJournalQuestLocationInfo(questId) end local quest = { name = questName, backgroundText = backgroundText, activeStepText = activeStepText, activeStepType = activeStepType, activeStepTrackerOverrideText = activeStepTrackerOverrideText, questLevel = questLevel, questType = questType, instanceDisplayType = instanceDisplayType, location = locationInfo, repeatType = repeatType, isDaily = repeatType == QUEST_REPEAT_DAILY, isCrafting = questType == QUEST_TYPE_CRAFTING } if quest.isCrafting then quest.craft = LeoAltholic.GetCraftFromQuest(quest.name) end return quest end local function initCharsList() if LeoAltholic.savedVariables.CharList == nil then LeoAltholic.savedVariables.CharList = {} end LeoAltholic.CharName = GetUnitName("player") local function getStat(stat) return GetPlayerStat(stat, STAT_BONUS_OPTION_APPLY_BONUS, STAT_SOFT_CAP_OPTION_APPLY_SOFT_CAP) end local numChars = GetNumCharacters() for k, v in pairs(LeoAltholic.savedVariables.CharList) do local deleted = true for i = 1, numChars do local charName = GetCharacterInfo(i) charName = charName:gsub("%^.+", "") if k == charName then deleted = false break end end if deleted then LeoAltholic.savedVariables.CharList[k] = nil end end LeoAltholic.CharNum = 0 local char = LeoAltholic.savedVariables.CharList[LeoAltholic.CharName] or { bio = {}, quests = { actives = {}, tracked = {}, writs = {} } } char.bio.name = LeoAltholic.CharName char.bio.gender = GetUnitGender("player") if char.bio.gender == 1 then char.bio.genderName = GetString(SI_GENDER1) else char.bio.genderName = GetString(SI_GENDER2) end char.bio.level = GetUnitLevel("player") char.bio.effectiveLevel = GetUnitEffectiveLevel("player") char.bio.isChampion = IsUnitChampion("player") char.bio.canChampion = CanUnitGainChampionPoints("player") char.bio.championPoints = GetPlayerChampionPointsEarned("player") char.bio.race = GetUnitRace("player") char.bio.raceId = GetUnitRaceId("player") char.bio.class = GetUnitClass("player") char.bio.classId = GetUnitClassId("player") char.bio.alliance = { id = GetUnitAlliance("player"), name = GetAllianceName(GetUnitAlliance("player")), rank = GetUnitAvARank("player"), points = GetCarriedCurrencyAmount(CURT_ALLIANCE_POINTS) } char.secondsPlayed = GetSecondsPlayed() char.bounty = GetBounty() local riding = {GetRidingStats()} local ridetime = GetTimeUntilCanBeTrained()/1000 or 0 if ridetime > 1 then ridetime = ridetime + GetTimeStamp() end char.attributes = { unspent = GetAttributeUnspentPoints(), health = { points = GetAttributeSpentPoints(ATTRIBUTE_HEALTH), max = getStat(STAT_HEALTH_MAX), recovery = getStat(STAT_HEALTH_REGEN_COMBAT) }, magicka = { points = GetAttributeSpentPoints(ATTRIBUTE_MAGICKA), max = getStat(STAT_MAGICKA_MAX), recovery = getStat(STAT_MAGICKA_REGEN_COMBAT) }, stamina = { points = GetAttributeSpentPoints(ATTRIBUTE_STAMINA), max = getStat(STAT_STAMINA_MAX), recovery = getStat(STAT_STAMINA_REGEN_COMBAT) }, riding = { capacity = riding[1], capacityMax = riding[2], stamina = riding[3], staminaMax = riding[4], speed = riding[5], speedMax = riding[6], time = ridetime }, weapon = { damage = getStat(STAT_WEAPON_POWER), critical = getStat(STAT_CRITICAL_STRIKE), criticalChance = GetCriticalStrikeChance(getStat(STAT_CRITICAL_STRIKE)) }, spell = { damage = getStat(STAT_SPELL_POWER), critical = getStat(STAT_SPELL_CRITICAL), criticalChance = GetCriticalStrikeChance(getStat(STAT_SPELL_CRITICAL)) } } char.attributes.total = char.attributes.unspent + char.attributes.health.points + char.attributes.magicka.points + char.attributes.stamina.points char.resistances = { armor = getStat(STAT_ARMOR_RATING), spell = getStat(STAT_SPELL_RESIST), crit = getStat(STAT_CRITICAL_RESISTANCE), cold = getStat(STAT_DAMAGE_RESIST_COLD), disease = getStat(STAT_DAMAGE_RESIST_DISEASE), drown = getStat(STAT_DAMAGE_RESIST_DROWN), earth = getStat(STAT_DAMAGE_RESIST_EARTH), fire = getStat(STAT_DAMAGE_RESIST_FIRE), generic = getStat(STAT_DAMAGE_RESIST_GENERIC), magic = getStat(STAT_DAMAGE_RESIST_MAGIC), oblivion = getStat(STAT_DAMAGE_RESIST_OBLIVION), physical = getStat(STAT_DAMAGE_RESIST_PHYSICAL), poison = getStat(STAT_DAMAGE_RESIST_POISON), shock = getStat(STAT_DAMAGE_RESIST_SHOCK), start = getStat(STAT_DAMAGE_RESIST_START), mitigation = getStat(STAT_MITIGATION), physical = getStat(STAT_PHYSICAL_RESIST), spell_mitigation = getStat(STAT_SPELL_MITIGATION), miss = getStat(STAT_MISS), parry = getStat(STAT_PARRY), block = getStat(STAT_BLOCK), dodge = getStat(STAT_DODGE) } char.skills = { } char.skills.unspent = GetAvailableSkillPoints() char.skills.skyShards = GetNumSkyShards() local skillType = SKILL_TYPE_ARMOR char.skills.armor = {} local baseElem = char.skills.armor loadPlayerDataPart(skillType,baseElem) -- skillType = SKILL_TYPE_WORLD char.skills.world = {} baseElem = char.skills.world loadPlayerDataPart(skillType,baseElem) -- skillType = SKILL_TYPE_CLASS char.skills.class = {} baseElem = char.skills.class loadPlayerDataPart(skillType,baseElem) -- skillType = SKILL_TYPE_GUILD char.skills.guild = {} baseElem = char.skills.guild loadPlayerDataPart(skillType,baseElem) -- skillType = SKILL_TYPE_RACIAL char.skills.racial = {} baseElem = char.skills.racial loadPlayerDataPart(skillType,baseElem) -- skillType = SKILL_TYPE_WEAPON char.skills.weapon = {} baseElem = char.skills.weapon loadPlayerDataPart(skillType,baseElem) -- skillType = SKILL_TYPE_AVA char.skills.ava = {} baseElem = char.skills.ava loadPlayerDataPart(skillType,baseElem) skillType = SKILL_TYPE_TRADESKILL char.skills.craft = {} baseElem = char.skills.craft loadPlayerDataPart(skillType,baseElem) local function GetBonus(craft) local skillType0, skillId = GetCraftingSkillLineIndices(craft) local _, rank = GetSkillLineInfo(skillType0,skillId) return {rank = rank, max = GetMaxSimultaneousSmithingResearch(craft) or 1} end if char.research == nil then char.research = {} for _,craft in pairs(LeoAltholic.craftResearch) do char.research[craft] = GetBonus(craft) for line = 1, GetNumSmithingResearchLines(craft) do char.research[craft][line] = {} for trait = 1, LeoAltholic.maxTraits do if not char.research[craft][line][trait] then char.research[craft][line][trait] = {} end end end end end if GetDiffBetweenTimeStamps(char.attributes.riding.time - GetTimeStamp()) < 0 then local data = { id = '$M' .. char.bio.name, name = char.bio.name, info = zo_strformat(GetString(LEOALT_MOUNT_FINISHED), char.bio.name), time = char.attributes.riding.time } LeoAltholic.AddToQueue(data) end for _,craft in pairs(LeoAltholic.craftResearch) do for line = 1, GetNumSmithingResearchLines(craft) do local lineName, lineIcon = GetSmithingResearchLineInfo(craft, line) for trait = 1, LeoAltholic.maxTraits do local traitType, _, known = GetSmithingResearchLineTraitInfo(craft, line, trait) if char.bio.name ~= LeoAltholic.CharName then local traitData = char.research[craft][line][trait] or false if type(traitData) == 'number' then local data = { id = '$R' .. char.bio.name..craft..line..trait, charName = char.bio.name, info = zo_strformat( GetString(LEOALT_RESEARCH_FINISHED) .. ': |c00FF00<<C:2>> <<C:3>>|r.', char.bio.name, GetString('SI_ITEMTRAITTYPE',traitType), lineName ), time = traitData } LeoAltholic.AddToQueue(data) end end if known == false then local _,remaining = GetSmithingResearchLineTraitTimes(craft,line,trait) if remaining and remaining > 0 then char.research[craft][line][trait] = remaining + GetTimeStamp() else char.research[craft][line][trait] = false end else char.research[craft][line][trait] = true end end end end char.champion = {} for _, attribute in ipairs({ATTRIBUTE_HEALTH, ATTRIBUTE_MAGICKA, ATTRIBUTE_STAMINA}) do char.champion[attribute] = {} char.champion[attribute].spent = 0 char.champion[attribute].unspent = GetNumUnspentChampionPoints(attribute) char.champion[attribute].disciplines = {} end for i = 1, GetNumChampionDisciplines() do local attribute = GetChampionDisciplineAttribute(i) char.champion[attribute].disciplines[i] = { spent = GetNumPointsSpentInChampionDiscipline(i), skills = {} } char.champion[attribute].spent = char.champion[attribute].spent + char.champion[attribute].disciplines[i].spent for j = 1, GetNumChampionDisciplineSkills(i) do if WillChampionSkillBeUnlocked(i, j) then char.champion[attribute].disciplines[i].skills[j] = true else char.champion[attribute].disciplines[i].skills[j] = GetNumPointsSpentOnChampionSkill(i, j) end end end char.inventory = {} char.inventory.size = GetBagSize(BAG_BACKPACK) char.inventory.used = GetNumBagUsedSlots(BAG_BACKPACK) char.inventory.free = GetNumBagFreeSlots(BAG_BACKPACK) local _, _, soulGemEmpty = GetSoulGemInfo(SOUL_GEM_TYPE_EMPTY, char.bio.level, true) local _, _, soulGemFilled = GetSoulGemInfo(SOUL_GEM_TYPE_FILLED, char.bio.level, true) char.inventory.soulGemEmpty = soulGemEmpty char.inventory.soulGemFilled = soulGemFilled char.inventory.ap = GetAlliancePoints() char.inventory.gold = GetCurrentMoney() char.inventory.telvar = GetCarriedCurrencyAmount(CURT_TELVAR_STONES) char.inventory.writVoucher = GetCarriedCurrencyAmount(CURT_WRIT_VOUCHERS) local bag = SHARED_INVENTORY:GenerateFullSlotData(nil,BAG_WORN,BAG_BACKPACK) char.inventory[BAG_WORN] = {} char.inventory[BAG_BACKPACK] = {} for _, data in pairs(bag) do char.inventory[data.bagId][data.slotIndex] = { link = GetItemLink(data.bagId, data.slotIndex), name = data.name, count = data.stackCount } end if char.stats == nil then char.stats = {} end if char.quests == nil or char.quests.tracked == nil then char.quests = { actives = {}, tracked = {}, writs = {} } else char.quests.actives = {} end if char.quests.writs == nil then char.quests.writs = {} end local n = 0 for i = 1, MAX_JOURNAL_QUESTS do if IsValidQuestIndex(i) then local quest = createQuestEntry(i) table.insert(char.quests.actives, quest) n = n + 1 end end --char.achievements = createCharDataAchievements() LeoAltholic.savedVariables.CharList[LeoAltholic.CharName] = char end local function fixWrits() for charName, char in pairs(LeoAltholic.savedVariables.CharList) do if char.quests == nil then LeoAltholic.savedVariables.CharList[charName].quests = { actives = {}, tracked = {}, writs = {} } end if char.quests.tracked == nil then LeoAltholic.savedVariables.CharList[charName].quests.tracked = {} end if char.quests.writs == nil then LeoAltholic.savedVariables.CharList[charName].quests.writs = {} end for trackedId, trackedQuest in pairs(char.quests.writs) do if trackedQuest.craft == nil then local craft = LeoAltholic.GetCraftFromQuest(trackedQuest.name) if craft ~= nil then LeoAltholic.savedVariables.CharList[charName].quests.writs[trackedId].craft = craft end end end end end function LeoAltholic.TodayReset() local diff = zo_floor(GetDiffBetweenTimeStamps(GetTimeStamp(), 1538200800) / 86400) return 1538200800 + (diff * 86400) end local function parseAchievementLinkId(link) if (link == nil or link == "") then return -1, 0, 0 end local linkType, itemText, achId, achData, achTimestamp = link:match("|H(.-):(.-):(.-):(.-):(.-)|h|h") if (achId == nil or achData == nil or achTimestamp == nil) then return -1, 0, 0 end return achId, tonumber(achData), tonumber(achTimestamp) end local function createCharDataAchievements() local achievements = {} local numTopLevelCategories = GetNumAchievementCategories() local countCategory = 1 for topLevelIndex = 1, numTopLevelCategories do local cateName, numCategories, numCateAchievements, earnedPoints, totalPoints, hidesPoints = GetAchievementCategoryInfo(topLevelIndex) if earnedPoints > 0 then achievements[countCategory] = { id = topLevelIndex, name = cateName, earnedPoints = earnedPoints, totalPoints = totalPoints, subCategory = {} } local countSub = 1 for categoryIndex = 1, numCategories do local subcategoryName, numAchievements, earnedSubSubPoints, totalSubSubPoints, hidesSubSubPoints = GetAchievementSubCategoryInfo(topLevelIndex, categoryIndex) if earnedSubSubPoints > 0 then achievements[countCategory].subCategory[countSub] = { name = subcategoryName, earnedPoints = earnedSubSubPoints, totalPoints = totalSubSubPoints, achievements = {} } earnedPoints = earnedPoints - earnedSubSubPoints totalPoints = totalPoints - totalSubSubPoints local countAchiev = 1 for achievementIndex = 1, numAchievements do local achId = GetAchievementId(topLevelIndex, categoryIndex, achievementIndex) local currentId = GetFirstAchievementInLine(achId) if (currentId == 0) then currentId = achId end while (currentId ~= nil and currentId > 0) do local achLink = GetAchievementLink(currentId) local _, progress, timestamp = parseAchievementLinkId(achLink) if (progress ~= 0 or timestamp ~= 0) then achievements[countCategory].subCategory[countSub].achievements[countAchiev] = { id = currentId, name = GetAchievementNameFromLink(achLink), progress = progress, timestamp = timestamp, completed = IsAchievementComplete(currentId), numCriteria = GetAchievementNumCriteria(currentId), numCriteriaDone = 0 } local numCriteria = achievements[countCategory].subCategory[countSub].achievements[countAchiev].numCriteria local numCriteriaDone = achievements[countCategory].subCategory[countSub].achievements[countAchiev].numCriteriaDone for critIndex = 1, numCriteria do local _, numCompleted, numRequired = GetAchievementCriterion(currentId, critIndex) if numCompleted == numRequired then numCriteriaDone = numCriteriaDone + 1 end end achievements[countCategory].subCategory[countSub].achievements[countAchiev].numCriteriaDone = numCriteriaDone countAchiev = countAchiev + 1 end currentId = GetNextAchievementInLine(currentId) end end countSub = countSub + 1 end end countCategory = countCategory + 1 end end achievements.earnedPoints = GetEarnedAchievementPoints() achievements.totalPoints = GetTotalAchievementPoints() return achievements end local function copy(obj, seen) if type(obj) ~= 'table' then return obj end if seen and seen[obj] then return seen[obj] end local s = seen or {} local res = setmetatable({}, getmetatable(obj)) s[obj] = res for k, v in pairs(obj) do res[copy(k, s)] = copy(v, s) end return res end function LeoAltholic.GetCharacters(forceUpdate) if #LeoAltholic.charList == 0 or (forceUpdate == true and GetTimeStamp() - LeoAltholic.lastUpdatedCharList > 10) then LeoAltholic.charList = {} local i = 1 for k, v in pairs(LeoAltholic.savedVariables.CharList) do if k == nil then return end LeoAltholic.charList[i] = copy(v) i = i + 1 end table.sort(LeoAltholic.charList, function(a, b) return a.bio.name < b.bio.name end) LeoAltholic.lastUpdatedCharList = GetTimeStamp() end return LeoAltholic.charList end function LeoAltholic.ExportCharacters(forceUpdate) LeoAltholic.GetCharacters(forceUpdate) local chars = copy(LeoAltholic.charList) return chars end function LeoAltholic.GetCharByName(name) local chars = LeoAltholic.ExportCharacters() for k, v in pairs(chars) do if v.bio.name == name then return v end end return nil end function LeoAltholic.GetItems(char, bagId) local itemLines = {} local i = 1 for k, v in pairs(char.inventory[bagId]) do if k == nil then return end itemLines[i] = copy(v) i = i + 1 end table.sort(itemLines, function(a, b) return a.name < b.name end) return itemLines end local function formatMessage(message) return LeoAltholic.chatPrefix .. message end function LeoAltholic.log(message) d(formatMessage(message)) end function LeoAltholic.GetMyself() return LeoAltholic.savedVariables.CharList[LeoAltholic.CharName] end local function onResearchCompleted(eventCode, craft, line, trait) if LeoAltholic.initialized == false then local myself = LeoAltholic.GetMyself() myself.research[craft][line][trait] = true end local lineName = GetSmithingResearchLineInfo(craft, line) local traitType = GetSmithingResearchLineTraitInfo(craft, line, trait) local name = GetUnitName("player") local msg = zo_strformat( GetString(LEOALT_RESEARCH_FINISHED) .. ': |c00FF00<<C:2>> <<C:3>>|r.', name, GetString('SI_ITEMTRAITTYPE',traitType), lineName ) if LeoAltholic.savedVariables.settings.completedResearch.screen == true then local messageParams = CENTER_SCREEN_ANNOUNCE:CreateMessageParams(CSA_CATEGORY_SMALL_TEXT, SOUNDS.SMITHING_FINISH_RESEARCH) messageParams:SetText(formatMessage(msg)) CENTER_SCREEN_ANNOUNCE:AddMessageWithParams(messageParams) end if LeoAltholic.savedVariables.settings.completedResearch.chat == true then LeoAltholic.log(msg) end LeoAltholicUI.researchList:RefreshData() end function LeoAltholic.AddToQueue(data) for x,queue in pairs(LeoAltholic.timerQueue) do if queue.id == data.id then return end end table.insert(LeoAltholic.timerQueue, data) end local function processQueue() for x,data in pairs(LeoAltholic.timerQueue) do if GetDiffBetweenTimeStamps(data.time, GetTimeStamp()) <= 0 then if data.charName ~= LeoAltholic.CharName and LeoAltholic.savedVariables.settings.completedResearch.chat == true then LeoAltholic.log(data.info) end if data.charName == LeoAltholic.CharName and LeoAltholic.savedVariables.settings.completedResearch.screen == true then local messageParams = CENTER_SCREEN_ANNOUNCE:CreateMessageParams(CSA_CATEGORY_SMALL_TEXT, SOUNDS.SMITHING_FINISH_RESEARCH) messageParams:SetText(formatMessage(data.info)) CENTER_SCREEN_ANNOUNCE:AddMessageWithParams(messageParams) end table.remove(LeoAltholic.timerQueue, x) end end end local function createMessageQueue() --LeoAltholic.timerQueue = {} for _, char in pairs(LeoAltholic.GetCharacters()) do if char.bio.name ~= LeoAltholic.CharName then if GetDiffBetweenTimeStamps(char.attributes.riding.time - GetTimeStamp()) < 0 then local data = { id = '$M' .. char.bio.name, name = char.bio.name, info = zo_strformat(GetString(LEOALT_MOUNT_FINISHED), char.bio.name), time = char.attributes.riding.time } LeoAltholic.AddToQueue(data) end for _,craft in pairs(LeoAltholic.craftResearch) do for line = 1, GetNumSmithingResearchLines(craft) do local lineName, lineIcon = GetSmithingResearchLineInfo(craft, line) for trait = 1, LeoAltholic.maxTraits do local traitType = GetSmithingResearchLineTraitInfo(craft, line, trait) local traitData = char.research[craft][line][trait] or false if type(traitData) == 'number' then local data = { id = '$R' .. char.bio.name..craft..line..trait, charName = char.bio.name, info = zo_strformat( GetString(LEOALT_RESEARCH_FINISHED) .. ': |c00FF00<<C:2>> <<C:3>>|r.', char.bio.name, GetString('SI_ITEMTRAITTYPE',traitType), lineName ), time = traitData } LeoAltholic.AddToQueue(data) end end end end end end end local function onUpdate() processQueue() LeoAltholic.numUpdates = LeoAltholic.numUpdates + 1 if LeoAltholic.numUpdates >= 1800 then -- 3600 seconds = 1h, forces update every hour LeoAltholic.numUpdates = 1 LeoAltholicUI.researchList:RefreshData() end if LeoAltholic.isHidden() then return end LeoAltholicUI:updateBio() if LeoAltholic.numUpdates >= 30 then -- 60 seconds LeoAltholic.numUpdates = 1 LeoAltholicUI.researchList:RefreshData() --[[ For reference only!! LeoAltholicUI.bioList:RefreshData() LeoAltholicUI.statsList:RefreshData() LeoAltholicUI.championList:RefreshData() LeoAltholicUI.invList:RefreshData() LeoAltholicUI.skillsList:RefreshData() LeoAltholicUI.skills2List:RefreshData() LeoAltholicUI.researchList:RefreshData() LeoAltholicUI.writsList:RefreshData() ]] else LeoAltholicUI:updateResearch() end end local function trackQuest(questId, automatically) local type = GetJournalQuestRepeatType(questId) if type ~= QUEST_REPEAT_DAILY then if automatically ~= true then LeoAltholic.log(GetString(LEOALT_TRACK_ONLY_DAILY)) end return end local lookInto local quest = createQuestEntry(questId) if quest.isCrafting then lookInto = LeoAltholic.savedVariables.CharList[LeoAltholic.CharName].quests.writs else lookInto = LeoAltholic.savedVariables.CharList[LeoAltholic.CharName].quests.tracked end for _,trackedQuest in pairs(lookInto) do if (trackedQuest.name == quest.name) then if automatically ~= true then LeoAltholic.log(zo_strformat(GetString(LEOALT_QUEST_ALREADY_TRACKED), quest.name)) end return end end quest.lastDone = nil table.insert(lookInto, quest) LeoAltholic.log(GetString(LEOALT_TRACKING) .. " " .. quest.name .. "...") if quest.isCrafting then LeoAltholicUI.writsList:RefreshData() end end local function onQuestAdded(eventCode, journalIndex, questName, objectiveName) local quest = createQuestEntry(journalIndex) if quest.isDaily == false then return end if LeoAltholic.savedVariables.settings.tracked.allDaily == true or (quest.questType == QUEST_TYPE_CRAFTING and LeoAltholic.savedVariables.settings.tracked.dailyWrits == true) then trackQuest(journalIndex, true) end end local function onQuestComplete(eventCode, questName, level, previousExperience, currentExperience, rank, previousPoints, currentPoints) for i,trackedQuest in pairs(LeoAltholic.savedVariables.CharList[LeoAltholic.CharName].quests.writs) do if (trackedQuest.name == questName) then LeoAltholic.savedVariables.CharList[LeoAltholic.CharName].quests.writs[i].lastDone = GetTimeStamp() LeoAltholic.log(zo_strformat(GetString(LEOALT_QUEST_DONE_TODAY), questName)) LeoAltholicUI.writsList:RefreshData() return end end for i,trackedQuest in pairs(LeoAltholic.savedVariables.CharList[LeoAltholic.CharName].quests.tracked) do if (trackedQuest.name == questName) then LeoAltholic.savedVariables.CharList[LeoAltholic.CharName].quests.tracked[i].lastDone = GetTimeStamp() LeoAltholic.log(zo_strformat(GetString(LEOALT_QUEST_DONE_TODAY), questName)) return end end end local function initializeVars() local oldVariables = ZO_SavedVars:NewAccountWide("LeoAltholicSavedVariables", 2) LeoAltholic.savedVariables = ZO_SavedVars:NewAccountWide("LeoAltholicSavedVariables", 2, nil, nil, GetWorldName()) if oldVariables ~= nil and oldVariables.CharList ~= nil then local varCopy = copy(oldVariables) LeoAltholic.savedVariables.activeTab = varCopy.activeTab LeoAltholic.savedVariables.CharList = varCopy.CharList LeoAltholic.savedVariables.position = varCopy.position LeoAltholicSavedVariables["Default"] = nil end if not LeoAltholic.savedVariables.settings or LeoAltholic.savedVariables.settings == nil then LeoAltholic.savedVariables.settings = { tracked = { dailyWrits = false, allDaily = false }, completedResearch = { chat = true, screen = true } } end end local function initialize() local LibFeedback = LibStub:GetLibrary("LibFeedback") local showButton, feedbackWindow = LibFeedback:initializeFeedbackWindow(LeoAltholic, LeoAltholic.name,LeoAltholicWindow, "@LeandroSilva", {TOPRIGHT, LeoAltholicWindow, 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.") LeoAltholic.feedback = feedbackWindow LeoAltholic.RestorePosition() initCharsList() fixWrits() LeoAltholicUI.InitPanels() createMessageQueue() local keybindStripDescriptor = { alignment = KEYBIND_STRIP_ALIGN_LEFT, { name = "Track with " .. LeoAltholic.displayName, keybind = "LEOALTHOLIC_TRACK_QUEST", enabled = function() return true end, visible = function() return true end, order = 100, callback = function() trackQuest(QUEST_JOURNAL_MANAGER:GetFocusedQuestIndex()) end, } } QUEST_JOURNAL_SCENE:RegisterCallback("StateChange", function(oldState, newState) if(newState == SCENE_SHOWING) then local type = GetJournalQuestRepeatType(QUEST_JOURNAL_MANAGER:GetFocusedQuestIndex()) if type == QUEST_REPEAT_DAILY then KEYBIND_STRIP:AddKeybindButtonGroup(keybindStripDescriptor) else KEYBIND_STRIP:RemoveKeybindButtonGroup(keybindStripDescriptor) end elseif(newState == SCENE_HIDDEN) then KEYBIND_STRIP:RemoveKeybindButtonGroup(keybindStripDescriptor) end end) QUEST_JOURNAL_KEYBOARD:RegisterCallback("QuestSelected", function(questId) local type = GetJournalQuestRepeatType(questId) if type == QUEST_REPEAT_DAILY then KEYBIND_STRIP:AddKeybindButtonGroup(keybindStripDescriptor) else KEYBIND_STRIP:RemoveKeybindButtonGroup(keybindStripDescriptor) end end) LeoAltholic.settings = LeoAltholic_Settings:New() LeoAltholic.settings:CreatePanel() LeoAltholic.initialized = true CALLBACK_MANAGER:FireCallbacks("LeoAltholicInitialized") end local orig_ZO_QuestJournalNavigationEntry_OnMouseUp = ZO_QuestJournalNavigationEntry_OnMouseUp function ZO_QuestJournalNavigationEntry_OnMouseUp(label, button, upInside) orig_ZO_QuestJournalNavigationEntry_OnMouseUp(label, button, upInside) if button == MOUSE_BUTTON_INDEX_RIGHT and upInside then local questIndex = label.node.data.questIndex if questIndex and GetJournalQuestRepeatType(questIndex) == QUEST_REPEAT_DAILY then AddMenuItem("Track with " .. LeoAltholic.displayName, function() trackQuest(questIndex) end) ShowMenu(label) end end end local function onNewMovementInUIMode(eventCode) if not LeoAltholicWindow:IsHidden() then LeoAltholic.CloseUI() end end local function onChampionPerksSceneStateChange(oldState,newState) if newState == SCENE_SHOWING then if not LeoAltholicWindow:IsHidden() then LeoAltholic.CloseUI() end end end local function onPlayerDeactivated(event, addonName) EVENT_MANAGER:UnregisterForEvent(LeoAltholic.Name, EVENT_PLAYER_DEACTIVATED) initCharsList() end local function onAddOnLoaded(event, addonName) if addonName ~= LeoAltholic.name then return end EVENT_MANAGER:UnregisterForEvent(LeoAltholic.name, EVENT_ADD_ON_LOADED) SCENE_MANAGER:RegisterTopLevel(LeoAltholicWindow, false) if GetDisplayName() == "@LeandroSilva" then SLASH_COMMANDS["/rr"] = function(cmd) ReloadUI() end end SLASH_COMMANDS["/leoalt"] = function(cmd) LeoAltholic:ShowUI() end initializeVars() EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_SMITHING_TRAIT_RESEARCH_COMPLETED, onResearchCompleted) initialize() EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_PLAYER_DEACTIVATED, onPlayerDeactivated) EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_QUEST_COMPLETE, onQuestComplete) EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_QUEST_ADDED, onQuestAdded) EVENT_MANAGER:RegisterForUpdate(LeoAltholic.name, 2000, onUpdate) EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_NEW_MOVEMENT_IN_UI_MODE, onNewMovementInUIMode) CHAMPION_PERKS_SCENE:RegisterCallback('StateChange', onChampionPerksSceneStateChange) LeoAltholic.log("started.") end EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_ADD_ON_LOADED, onAddOnLoaded)