Skip to content

Instantly share code, notes, and snippets.

@merlight
Last active August 29, 2015 14:05
Show Gist options
  • Save merlight/164703bab3100b3ed98b to your computer and use it in GitHub Desktop.
Save merlight/164703bab3100b3ed98b to your computer and use it in GitHub Desktop.
local HarvensTraitAndStyle = {}
local g_savedVars = {}
local UnknowableTraitTypes = {
[ITEM_TRAIT_TYPE_NONE] = "none",
[ITEM_TRAIT_TYPE_WEAPON_INTRICATE] = "weapon",
[ITEM_TRAIT_TYPE_WEAPON_ORNATE] = "weapon",
[ITEM_TRAIT_TYPE_ARMOR_INTRICATE] = "armor",
[ITEM_TRAIT_TYPE_ARMOR_ORNATE] = "armor",
[ITEM_TRAIT_TYPE_JEWELRY_HEALTHY] = "jewelry",
[ITEM_TRAIT_TYPE_JEWELRY_ARCANE] = "jewelry",
[ITEM_TRAIT_TYPE_JEWELRY_ROBUST] = "jewelry",
[ITEM_TRAIT_TYPE_JEWELRY_ORNATE] = "jewelry",
}
local STR_KNOWN_TRAIT = zo_strformat(SI_ITEM_FORMAT_STR_KNOWN_ITEM_TYPE, GetString(SI_SMITHING_HEADER_TRAIT))
local STR_RESEARCH_IN_PROGRESS = zo_strformat("<<1>>", GetString(SI_SMITHING_RESEARCH_IN_PROGRESS))
local STR_RESEARCHABLE = zo_strformat("<<1>>", GetString(SI_SMITHING_RESEARCH_RESEARCHABLE))
--local functions
local function addStyleHeaderLine(tooltip, styleIndex)
local style = zo_strformat("<<1>>", GetString("SI_ITEMSTYLE", styleIndex))
local color = ZO_TOOLTIP_DEFAULT_COLOR
if g_savedVars.colorizeStyle then
if styleIndex >= ITEMSTYLE_RACIAL_BRETON and styleIndex <= ITEMSTYLE_RACIAL_KHAJIIT then
color = GetItemQualityColor(ITEM_QUALITY_ARCANE)
elseif styleIndex == ITEMSTYLE_RACIAL_IMPERIAL or styleIndex == ITEMSTYLE_AREA_DWEMER then
color = GetItemQualityColor(ITEM_QUALITY_LEGENDARY)
else
color = GetItemQualityColor(ITEM_QUALITY_ARTIFACT)
end
end
tooltip:AddHeaderLine(style, "ZoFontWinT2", 2, TOOLTIP_HEADER_SIDE_LEFT, color:UnpackRGB())
end
local function addTraitHeaderLine(tooltip, researchInfo, countBank, countPack)
local color = ZO_TOOLTIP_DEFAULT_COLOR
local text = ""
if g_savedVars.colorizeTrait then
if researchInfo == STR_RESEARCHABLE then
if countBank + countPack > 1 then
color = STAT_DIMINISHING_RETURNS_COLOR
else
color = STAT_LOWER_COLOR
end
elseif researchInfo == STR_RESEARCH_IN_PROGRESS then
color = STAT_DIMINISHING_RETURNS_COLOR
end
end
if g_savedVars.duplicateItems and researchInfo == STR_RESEARCHABLE then
if countBank > 0 then
text = text .. ("|u2:2::%d|u"):format(countBank)
text = text .. "|t24:24:esoui/art/icons/servicemappins/servicepin_bank.dds:inheritColor|t"
text = text .. "|u4:0::|u " -- padding
end
if countPack > 0 then
text = text .. ("|u2:0::%d|u"):format(countPack)
text = text .. "|t24:24:EsoUI/Art/Crafting/crafting_provisioner_inventorycolumn_icon.dds:inheritColor|t"
text = text .. "|u0:0::|u " -- padding
end
end
text = text .. "(" .. researchInfo .. ")"
tooltip:AddHeaderLine(text, "ZoFontWinT2", 2, TOOLTIP_HEADER_SIDE_RIGHT, color:UnpackRGB())
return color, text
end
-- optionally appends research info to localized trait name
-- returns function that will restore the original string
local function hackTraitName(traitType, appendColor, appendString)
if g_savedVars.appendResearchToTraitName and appendColor and appendString then
local stringId = _G["SI_ITEMTRAITTYPE" .. traitType]
local orgString = EsoStrings[stringId]
EsoStrings[stringId] = ("%s |c%s(%s)|r"):format(orgString, appendColor:ToHex(), appendString)
return function() EsoStrings[stringId] = orgString end
else
return function() end
end
end
local function hookMethod(obj, name, hook)
local orgFunc = obj[name]
local function hookFunc(...)
return hook(orgFunc, ...)
end
obj[name] = hookFunc
end
--exposable functions
function HarvensTraitAndStyle:GetSameTraitCount(bagId, armorType, weaponType, equipType, trait)
local count = 0
for slotIndex = 0, GetBagSize(bagId) - 1 do
local itemType = GetItemType(bagId, slotIndex)
if itemType == ITEMTYPE_ARMOR or itemType == ITEMTYPE_WEAPON then
if armorType == GetItemArmorType(bagId, slotIndex) and weaponType == GetItemWeaponType(bagId, slotIndex) and GetItemTrait(bagId, slotIndex) == trait then
local _,_,_,_,_, otherEquipType, otherStyle = GetItemInfo(bagId, slotIndex)
if otherStyle ~= ITEMSTYLE_NONE and otherEquipType == equipType then
count = count + 1
end
end
end
end
return count
end
function HarvensTraitAndStyle:GetItemResearchInfo(bagId, slotIndex)
local itemType = GetItemType(bagId, slotIndex)
if not self.tradeskillForItemType[itemType] then
return nil
end
local traitType = GetItemTrait(bagId, slotIndex)
if UnknowableTraitTypes[traitType] then
return nil
end
for i,tradeskill in ipairs(self.tradeskillForItemType[itemType]) do
local numResearchLines = GetNumSmithingResearchLines(tradeskill)
for j=1,numResearchLines do
local name, _, numTraits = GetSmithingResearchLineInfo(tradeskill, j)
for k=1,numTraits do
local can = CanItemBeSmithingTraitResearched(bagId, slotIndex, tradeskill, j, k)
if can then
local _, remaining = GetSmithingResearchLineTraitTimes(tradeskill, j, k)
if remaining then
return STR_RESEARCH_IN_PROGRESS
end
return STR_RESEARCHABLE
end
end
end
end
return STR_KNOWN_TRAIT
end
function HarvensTraitAndStyle:GetItemLinkResearchInfo(link)
local itemType = GetItemLinkItemType(link)
if itemType ~= ITEMTYPE_ARMOR and itemType ~= ITEMTYPE_WEAPON then
return nil
end
local traitType = GetItemLinkTraitInfo(link)
if traitType == ITEM_TRAIT_TYPE_NONE then
return nil
end
local equipType = GetItemLinkEquipType(link)
if itemType == ITEMTYPE_ARMOR then
local armorType = GetItemLinkArmorType(link)
local resLines = self.armorTypeAndEquipTypeToResearchLineIndex[armorType]
if not resLines then
return nil
end
local resIndex = resLines[equipType]
if not resIndex or resIndex == 0 then
return nil
end
local tradeSkill = self.tradeskillForArmorType[armorType]
if not tradeSkill or tradeSkill == 0 then
return nil
end
return self.traitTable[tradeSkill][resIndex][traitType]
else
local weaponType = GetItemLinkWeaponType(link)
local tradeSkill = self.tradeskillForWeaponType[weaponType]
if not tradeSkill or tradeSkill == 0 then
return nil
end
local resIndex = self.weaponTypeToResearchLineIndex[weaponType]
if not resIndex or resIndex == 0 then
return nil
end
return self.traitTable[tradeSkill][resIndex][traitType]
end
return nil
end
function HarvensTraitAndStyle:AddStyleFromBagNoHack(tooltip, bagId, slotIndex)
local equipType, itemStyle = select(6, GetItemInfo(bagId, slotIndex))
if itemStyle ~= ITEMSTYLE_NONE then
addStyleHeaderLine(tooltip, itemStyle)
end
local traitType = GetItemTrait(bagId, slotIndex)
local researchColor = nil
local researchInfo = self:GetItemResearchInfo(bagId, slotIndex)
if researchInfo then
local armorType = GetItemArmorType(bagId, slotIndex)
local weaponType = GetItemWeaponType(bagId, slotIndex)
local countBank = self:GetSameTraitCount(BAG_BANK, armorType, weaponType, equipType, traitType)
local countPack = self:GetSameTraitCount(BAG_BACKPACK, armorType, weaponType, equipType, traitType)
researchColor = addTraitHeaderLine(tooltip, researchInfo, countBank, countPack)
end
return traitType, researchColor, researchInfo
end
function HarvensTraitAndStyle:AddStyleFromBag(tooltip, bagId, slotIndex)
return hackTraitName(self:AddStyleFromBagNoHack(tooltip, bagId, slotIndex))
end
function HarvensTraitAndStyle:AddStyleFromLink(tooltip, link)
local itemStyle = GetItemLinkItemStyle(link)
if itemStyle ~= ITEMSTYLE_NONE then
addStyleHeaderLine(tooltip, itemStyle)
end
local traitType = GetItemLinkTraitInfo(link)
local researchColor = nil
local researchInfo = self:GetItemLinkResearchInfo(link)
if researchInfo then
local armorType = GetItemLinkArmorType(link)
local weaponType = GetItemLinkWeaponType(link)
local equipType = GetItemLinkEquipType(link)
local countBank = self:GetSameTraitCount(BAG_BANK, armorType, weaponType, equipType, traitType)
local countPack = self:GetSameTraitCount(BAG_BACKPACK, armorType, weaponType, equipType, traitType)
researchColor = addTraitHeaderLine(tooltip, researchInfo, countBank, countPack)
end
return hackTraitName(traitType, researchColor, researchInfo)
end
--hooks
local function HarvensTraitAndStyle_SetAttachedMailItem(orgFunc, tooltip, mailId, attachmentIndex, ...)
local link = GetAttachedItemLink(mailId, attachmentIndex)
local unhackTraitName = HarvensTraitAndStyle:AddStyleFromLink(tooltip, link)
orgFunc(tooltip, mailId, attachmentIndex, ...)
unhackTraitName()
end
local function HarvensTraitAndStyle_SetBagItem(orgFunc, tooltip, bagId, slotIndex, ...)
local unhackTraitName = HarvensTraitAndStyle:AddStyleFromBag(tooltip, bagId, slotIndex)
orgFunc(tooltip, bagId, slotIndex, ...)
unhackTraitName()
end
local function HarvensTraitAndStyle_SetBuybackItem(orgFunc, tooltip, entryIndex, ...)
local link = GetBuybackItemLink(entryIndex)
local unhackTraitName = HarvensTraitAndStyle:AddStyleFromLink(tooltip, link)
orgFunc(tooltip, entryIndex, ...)
unhackTraitName()
end
local function HarvensTraitAndStyle_SetLink(orgFunc, tooltip, link,...)
local unhackTraitName = HarvensTraitAndStyle:AddStyleFromLink(tooltip, link)
orgFunc(tooltip, link, ...)
unhackTraitName()
end
local function HarvensTraitAndStyle_SetLootItem(orgFunc, tooltip, lootId)
local link = GetLootItemLink(lootId)
local unhackTraitName = HarvensTraitAndStyle:AddStyleFromLink(tooltip, link)
orgFunc(tooltip, lootId)
unhackTraitName()
end
local function HarvensTraitAndStyle_SetPendingSmithingItem(orgFunc, tooltip, ...)
local link = GetSmithingPatternResultLink(...)
local unhackTraitName = HarvensTraitAndStyle:AddStyleFromLink(tooltip, link)
orgFunc(tooltip, ...)
unhackTraitName()
end
local function HarvensTraitAndStyle_SetSmithingImprovementResult(orgFunc, tooltip, ...)
local unhackTraitName = HarvensTraitAndStyle:AddStyleFromBag(tooltip, ...)
orgFunc(tooltip, ...)
unhackTraitName()
end
local function HarvensTraitAndStyle_SetTradingHouseItem(orgFunc, tooltip, index)
local link = GetTradingHouseSearchResultItemLink(index)
local unhackTraitName = HarvensTraitAndStyle:AddStyleFromLink(tooltip, link)
orgFunc(tooltip, index)
unhackTraitName()
end
local function HarvensTraitAndStyle_SetTradingHouseListing(orgFunc, tooltip, index)
local link = GetTradingHouseListingItemLink(index)
local unhackTraitName = HarvensTraitAndStyle:AddStyleFromLink(tooltip, link)
orgFunc(tooltip, index)
unhackTraitName()
end
local function HarvensTraitAndStyle_SetWornItem(orgFunc, tooltip, equipSlot, ...)
local unhackTraitName = HarvensTraitAndStyle:AddStyleFromBag(tooltip, BAG_WORN, equipSlot)
orgFunc(tooltip, equipSlot, ...)
unhackTraitName()
end
local function HarvensTraitAndStyle_CTTOnAddGameData(tooltip, gameDataType, equipSlot, ...)
if gameDataType == TOOLTIP_GAME_DATA_EQUIPPED_INFO then
-- NoHack because trait name in comparative tooltip is filled somewhere else
HarvensTraitAndStyle:AddStyleFromBagNoHack(tooltip, BAG_WORN, equipSlot)
end
end
function HarvensTraitAndStyle:InitHooks()
hookMethod(ItemTooltip, "SetAttachedMailItem", HarvensTraitAndStyle_SetAttachedMailItem)
hookMethod(ItemTooltip, "SetBagItem", HarvensTraitAndStyle_SetBagItem)
hookMethod(ItemTooltip, "SetBuybackItem", HarvensTraitAndStyle_SetBuybackItem)
hookMethod(PopupTooltip, "SetLink", HarvensTraitAndStyle_SetLink)
hookMethod(ItemTooltip, "SetLootItem", HarvensTraitAndStyle_SetLootItem)
hookMethod(ZO_SmithingTopLevelCreationPanelResultTooltip, "SetPendingSmithingItem", HarvensTraitAndStyle_SetPendingSmithingItem)
hookMethod(ZO_SmithingTopLevelImprovementPanelResultTooltip, "SetSmithingImprovementResult", HarvensTraitAndStyle_SetSmithingImprovementResult)
hookMethod(ItemTooltip, "SetTradingHouseItem", HarvensTraitAndStyle_SetTradingHouseItem)
hookMethod(ItemTooltip, "SetTradingHouseListing", HarvensTraitAndStyle_SetTradingHouseListing)
hookMethod(ItemTooltip, "SetWornItem", HarvensTraitAndStyle_SetWornItem)
ZO_PreHookHandler(ComparativeTooltip1, "OnAddGameData", HarvensTraitAndStyle_CTTOnAddGameData)
ZO_PreHookHandler(ComparativeTooltip2, "OnAddGameData", HarvensTraitAndStyle_CTTOnAddGameData)
self.tradeskillForItemType = {
[ITEMTYPE_ARMOR] = {
CRAFTING_TYPE_BLACKSMITHING,
CRAFTING_TYPE_CLOTHIER,
CRAFTING_TYPE_WOODWORKING,
},
[ITEMTYPE_WEAPON] = {
CRAFTING_TYPE_BLACKSMITHING,
CRAFTING_TYPE_WOODWORKING,
}
}
self.tradeskillForArmorType = {
[ARMORTYPE_LIGHT] = CRAFTING_TYPE_CLOTHIER,
[ARMORTYPE_MEDIUM] = CRAFTING_TYPE_CLOTHIER,
[ARMORTYPE_HEAVY] = CRAFTING_TYPE_BLACKSMITHING
}
self.tradeskillForWeaponType = {
[WEAPONTYPE_AXE] = CRAFTING_TYPE_BLACKSMITHING,
[WEAPONTYPE_HAMMER] = CRAFTING_TYPE_BLACKSMITHING,
[WEAPONTYPE_SWORD] = CRAFTING_TYPE_BLACKSMITHING,
[WEAPONTYPE_TWO_HANDED_SWORD] = CRAFTING_TYPE_BLACKSMITHING,
[WEAPONTYPE_TWO_HANDED_AXE] = CRAFTING_TYPE_BLACKSMITHING,
[WEAPONTYPE_TWO_HANDED_HAMMER] = CRAFTING_TYPE_BLACKSMITHING,
[WEAPONTYPE_PROP] = CRAFTING_TYPE_INVALID, --what's that?
[WEAPONTYPE_BOW] = CRAFTING_TYPE_WOODWORKING,
[WEAPONTYPE_HEALING_STAFF] = CRAFTING_TYPE_WOODWORKING,
[WEAPONTYPE_RUNE] = CRAFTING_TYPE_INVALID,
[WEAPONTYPE_DAGGER] = CRAFTING_TYPE_BLACKSMITHING,
[WEAPONTYPE_FIRE_STAFF] = CRAFTING_TYPE_WOODWORKING,
[WEAPONTYPE_FROST_STAFF] = CRAFTING_TYPE_WOODWORKING,
[WEAPONTYPE_SHIELD] = CRAFTING_TYPE_WOODWORKING,
[WEAPONTYPE_LIGHTNING_STAFF] = CRAFTING_TYPE_WOODWORKING,
}
self.armorTypeAndEquipTypeToResearchLineIndex = {
[ARMORTYPE_HEAVY] = {
[EQUIP_TYPE_HEAD] = 11,
[EQUIP_TYPE_CHEST] = 8,
[EQUIP_TYPE_SHOULDERS] = 13,
[EQUIP_TYPE_WAIST] = 14,
[EQUIP_TYPE_LEGS] = 12,
[EQUIP_TYPE_FEET] = 9,
[EQUIP_TYPE_HAND] = 10,
},
[ARMORTYPE_LIGHT] = {
[EQUIP_TYPE_HEAD] = 4,
[EQUIP_TYPE_CHEST] = 1,
[EQUIP_TYPE_SHOULDERS] = 6,
[EQUIP_TYPE_WAIST] = 7,
[EQUIP_TYPE_LEGS] = 5,
[EQUIP_TYPE_FEET] = 2,
[EQUIP_TYPE_HAND] = 3,
},
[ARMORTYPE_MEDIUM] = {
[EQUIP_TYPE_HEAD] = 11,
[EQUIP_TYPE_CHEST] = 8,
[EQUIP_TYPE_SHOULDERS] = 13,
[EQUIP_TYPE_WAIST] = 14,
[EQUIP_TYPE_LEGS] = 12,
[EQUIP_TYPE_FEET] = 9,
[EQUIP_TYPE_HAND] = 10,
},
}
self.weaponTypeToResearchLineIndex = {
[WEAPONTYPE_AXE] = 1,
[WEAPONTYPE_BOW] = 1,
[WEAPONTYPE_DAGGER] = 7,
[WEAPONTYPE_FIRE_STAFF] = 2,
[WEAPONTYPE_FROST_STAFF] = 3,
[WEAPONTYPE_HAMMER] = 2,
[WEAPONTYPE_HEALING_STAFF] = 5,
[WEAPONTYPE_LIGHTNING_STAFF] = 4,
[WEAPONTYPE_PROP] = 0,
[WEAPONTYPE_RUNE] = 0,
[WEAPONTYPE_SHIELD] = 6,
[WEAPONTYPE_SWORD] = 3,
[WEAPONTYPE_TWO_HANDED_AXE] = 4,
[WEAPONTYPE_TWO_HANDED_HAMMER] = 5,
[WEAPONTYPE_TWO_HANDED_SWORD] = 6,
}
self.traitTable = {
[CRAFTING_TYPE_BLACKSMITHING] = {},
[CRAFTING_TYPE_WOODWORKING] = {},
[CRAFTING_TYPE_CLOTHIER] = {},
}
for k,v in pairs(self.traitTable) do
local nLines = GetNumSmithingResearchLines(k)
for i=1, nLines do
local name, _, nTraits = GetSmithingResearchLineInfo(k, i)
self.traitTable[k][i] = {}
for j=1, nTraits do
local traitType, _, known = GetSmithingResearchLineTraitInfo(k, i, j)
local _, remaining = GetSmithingResearchLineTraitTimes(k, i, j)
if remaining then
self.traitTable[k][i][traitType] = STR_RESEARCH_IN_PROGRESS
elseif known then
self.traitTable[k][i][traitType] = STR_KNOWN_TRAIT
else
self.traitTable[k][i][traitType] = STR_RESEARCHABLE
end
end
end
end
end
--settings
function HarvensTraitAndStyle:InitSettings()
local LibHarvensAddonSettings = LibStub("LibHarvensAddonSettings-1.0")
if not LibHarvensAddonSettings then return end
local settings = LibHarvensAddonSettings:AddAddon("Harven's Trait and Style")
if not settings then return end
settings:AddSetting{
type = LibHarvensAddonSettings.ST_CHECKBOX,
label = "Colorize style name",
tooltip = "Make style the color of the corresponding Motif book (common blue, rare purple)",
getFunction = function() return g_savedVars.colorizeStyle end,
setFunction = function(value) g_savedVars.colorizeStyle = value end,
}
settings:AddSetting{
type = LibHarvensAddonSettings.ST_CHECKBOX,
label = "Colorize trait knowledge",
tooltip = "Make 'Researchable' red and 'Researching...' orange",
getFunction = function() return g_savedVars.colorizeTrait end,
setFunction = function(value) g_savedVars.colorizeTrait = value end,
}
settings:AddSetting{
type = LibHarvensAddonSettings.ST_CHECKBOX,
label = "Show duplicate items info",
tooltip = "Adds information how many items of the same researchable trait you have",
getFunction = function() return g_savedVars.duplicateItems end,
setFunction = function(value) g_savedVars.duplicateItems = value end,
}
settings:AddSetting{
type = LibHarvensAddonSettings.ST_CHECKBOX,
label = "Append trait knowledge to trait name",
tooltip = "This feature is experimental, and may need to be disabled or removed if something goes wrong",
getFunction = function() return g_savedVars.appendResearchToTraitName end,
setFunction = function(value) g_savedVars.appendResearchToTraitName = value end,
}
end
--event handlers
local function HarvensTraitAndStyle_OnResearchCompleted(eventType, craftingSkillType, researchLineIndex, traitIndex)
if HarvensTraitAndStyle.traitTable[craftingSkillType] and HarvensTraitAndStyle.traitTable[craftingSkillType][researchLineIndex] then
local traitType = GetSmithingResearchLineTraitInfo(craftingSkillType, researchLineIndex, traitIndex)
HarvensTraitAndStyle.traitTable[craftingSkillType][researchLineIndex][traitType] = STR_KNOWN_TRAIT
end
end
local function HarvensTraitAndStyle_OnResearchStarted(eventType, craftingSkillType, researchLineIndex, traitIndex)
if HarvensTraitAndStyle.traitTable[craftingSkillType] and HarvensTraitAndStyle.traitTable[craftingSkillType][researchLineIndex] then
local traitType = GetSmithingResearchLineTraitInfo(craftingSkillType, researchLineIndex, traitIndex)
HarvensTraitAndStyle.traitTable[craftingSkillType][researchLineIndex][traitType] = STR_RESEARCH_IN_PROGRESS
end
end
local function HarvensTraitAndStyle_OnLoaded(eventType, addonName)
if addonName ~= "HarvensTraitAndStyle" then return end
if HarvensTraitAndStyle_SavedVariables then
g_savedVars = HarvensTraitAndStyle_SavedVariables
else
HarvensTraitAndStyle_SavedVariables = g_savedVars
end
HarvensTraitAndStyle:InitHooks()
HarvensTraitAndStyle:InitSettings()
EVENT_MANAGER:RegisterForEvent("HarvensTraitAndStyleResearchCompleted", EVENT_SMITHING_TRAIT_RESEARCH_COMPLETED, HarvensTraitAndStyle_OnResearchCompleted)
EVENT_MANAGER:RegisterForEvent("HarvensTraitAndStyleResearchStarted", EVENT_SMITHING_TRAIT_RESEARCH_STARTED, HarvensTraitAndStyle_OnResearchStarted)
end
EVENT_MANAGER:RegisterForEvent("HarvensTraitAndStyleOnLoaded", EVENT_ADD_ON_LOADED, HarvensTraitAndStyle_OnLoaded)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment