--[[ Filename: GuildCharNames.lue Author: Sasky Version: 1.1.0 Released under GPLv2. See libraries for their individual licenses ]]-- local LC = LibStub('libChat-1.0') GuildCharInfo = {} --[[ GuildCharInfo:init() @post change events registered @post lookup table initialized ]]-- GuildCharInfo.init = function() local emptyDefault = {} GuildCharInfo.lut = ZO_SavedVars:NewAccountWide('GuildCharacterInfo', 0.9, "cache", emptyDefault) GuildCharInfo.createLUT() GuildCharInfo.player = GetDisplayName() GuildCharInfo.initUI() -- register for guild events EVENT_MANAGER:RegisterForEvent("GuildMemberLeveled", EVENT_GUILD_MEMBER_CHARACTER_LEVEL_CHANGED, GuildCharInfo.guildUpdateEvent) EVENT_MANAGER:RegisterForEvent("GuildMemberLoginout", EVENT_GUILD_MEMBER_PLAYER_STATUS_CHANGED, GuildCharInfo.guildUpdateEvent) EVENT_MANAGER:RegisterForEvent("GuildMemberAdded", EVENT_GUILD_MEMBER_ADDED, GuildCharInfo.guildUpdateEvent) EVENT_MANAGER:UnregisterForEvent("GuildCharacterInfo", EVENT_PLAYER_ACTIVATED, GuildCharInfo.init) LINK_HANDLER:RegisterCallback(LINK_HANDLER.LINK_CLICKED_EVENT, GuildCharInfo.linkHandler) LC:registerName(GuildCharInfo.getFormattedNameLink) --UI init: create close button --From AI research grid GuildCharInfo.uiClose = WINDOW_MANAGER:CreateControl("GCINameBoxCloseButton", GCINameBox, CT_BUTTON) GuildCharInfo.uiClose:SetDimensions(15, 15) GuildCharInfo.uiClose:SetAnchor(TOPRIGHT, GCINameBox, TOPRIGHT, 0 , 0) GuildCharInfo.uiClose:SetState(BSTATE_NORMAL) GuildCharInfo.uiClose:SetMouseOverBlendMode(0) GuildCharInfo.uiClose:SetEnabled(true) GuildCharInfo.uiClose:SetNormalTexture("/esoui/art/buttons/clearslot_down.dds") GuildCharInfo.uiClose:SetMouseOverTexture("/esoui/art/buttons/clearslot_up.dds") GuildCharInfo.uiClose:SetHandler("OnClicked", function(_) GCINameBox:SetHidden(true) end) end --[[ GuildCharInfo:createLUT() @post lookup table initialized ]]-- GuildCharInfo.createLUT = function() local g, guild, acctName, hasChar, charName, lvl, vr, _ for g=1,GetNumGuilds() do guild = GetGuildId(g) for i=1,GetNumGuildMembers(guild) do acctName = GetGuildMemberInfo(guild,i) hasChar, charName, _, _, _, lvl, vr = GetGuildMemberCharacterInfo(guild,i) if hasChar then GuildCharInfo.putToLUT(acctName, charName, lvl, vr, guild, i) end end end end --[[GuildCharInfo:PutToLUT(acctName, charName, charLevel, charVR) @param acctName - name of player account (@foo) @param charName - name of current character. String stripping optional @param charLevel - level of current character @param charVR - veteran rank of current character @post Character added to LUT. If account already exists and charLevel > level in LUT, will replace main character ]]-- GuildCharInfo.putToLUT = function(acctName, charName, charLevel, charVR, guild, index) if charLevel == nil then charLevel = 0 end if charVR == nil then charVR = 0 end charName = charName:gsub("%^.+", "") --Init if first time with this character if GuildCharInfo.lut[acctName] == nil then GuildCharInfo.lut[acctName] = {} GuildCharInfo.lut[acctName].level = 0 -- forces main update end --Always update charName and index GuildCharInfo.lut[acctName].name = charName GuildCharInfo.lut[acctName].guild = guild GuildCharInfo.lut[acctName].index = index --Update main if on higher level char if GuildCharInfo.lut[acctName].level < (charLevel + charVR) then GuildCharInfo.lut[acctName].main = charName GuildCharInfo.lut[acctName].level = charLevel + charVR end --d(acctName ..",".. charName ..",".. charLevel ..",".. charVR) end --[[GuildCharInfo:guildUpdateEvent(eventCode, guildId, acctName) @param eventCode - not used (but needed for callback signature) @param guildId - guild for the event @param acctName - account name that was updated Loops through the guild (guildId) until finds acctName. Updates that entry and exits @post LUT entry for <acctName> updated ]]-- GuildCharInfo.guildUpdateEvent = function(_, guildId, acctName) --Do a full rescan if relevant to current player if GuildCharInfo.player == acctName then GuildCharInfo.createLUT() return end local aName, _ --d(eventCode .. "," .. guildId .. "," .. acctName) for i=1,GetNumGuildMembers(guildId) do aName = GetGuildMemberInfo(guildId,i) if aName == acctName then local hasChar, charName, _, _, _, lvl, vr = GetGuildMemberCharacterInfo(guildId,i) if hasChar then --d("Found update: " .. acctName .. ", " .. charName .. ", " .. lvl .. "+" .. vr) GuildCharInfo.putToLUT(acctName, charName, lvl, vr, guildId, i) end return end end d("No update found for " .. acctName) end --[[ GuildCharInfo:getCharName(acctName) @return current character name for acctName If no entry, will passthrough acctName unaltered ]]-- GuildCharInfo.getCharName = function(acctName) if GuildCharInfo.lut[acctName] ~= nil and GuildCharInfo.lut[acctName].name ~= nil then return GuildCharInfo.lut[acctName].name end return acctName end --[[ GuildCharInfo:getCharName(acctName) @return main character name for acctName If no entry, will passthrough acctName unaltered ]]-- GuildCharInfo.getMainCharName = function(acctName) if GuildCharInfo.lut[acctName] ~= nil and GuildCharInfo.lut[acctName].main ~= nil then return GuildCharInfo.lut[acctName].main end return acctName end --[[ @param acctName - account name or text @param info - info object from receiveMessage @param includeMain - (boolean) whether to show main character name. Will not show if current matches main. Default: true @param includeAcct - (boolean) whether to show the account name. Will not show if name is not in lookup table. Default: false @return name link of format [CurrentCharacter] (Main character) @account ]]-- GuildCharInfo.generateLink = function(acctName) local color, text = GuildCharInfo.cfg.linkColor, GuildCharInfo.cfg.linkText if color == nil or #color ~= 6 then color = "EEEEEE" end if text == nil then text = "[*]" end text = GuildCharInfo.unsanitizeSavedText(text) local data = acctName data = data .. "," .. GuildCharInfo.lut[acctName].guild data = data .. "," .. GuildCharInfo.lut[acctName].index data = data .. ",[]" --Fix for pNames link handling on self local link = "|H" .. color .. ":playerDetail:" .. data .. "|h" .. text .. "|h" return link end --[[ Function for libChat hook @param channel - chat channel code @param acctName - sender of chat message @return formatted name link [Character] (Main) [*] ]]-- GuildCharInfo.getFormattedNameLink = function(channel, acctName, _) local ChanInfoArray = ZO_ChatSystem_GetChannelInfo() local info = ChanInfoArray[channel] local includeMain, includeAcct = GuildCharInfo.cfg.showMain, GuildCharInfo.cfg.showAcct --Short-circuit if not in LUT if GuildCharInfo.lut[acctName] == nil then if info.playerLinkable then return ZO_LinkHandler_CreatePlayerLink(acctName:gsub("%^.*x$","")) else return acctName end end --Parameter defaults if includeMain == nil then includeMain = true end if includeAcct == nil then includeAcct = false end local name, main = GuildCharInfo.lut[acctName].name, GuildCharInfo.lut[acctName].main if main == name then includeMain = false end if info.playerLinkable and acctName ~= GuildCharInfo.player then name = ZO_LinkHandler_CreatePlayerLink(name) end if includeMain then name = name .. " (" .. main .. ")" end --TODO: Make the account name into a link if includeAcct then name = name .. acctName end --Add info tag link name = name .. " " .. GuildCharInfo.generateLink(acctName) return name end --Utility function to kill NIL values local function nn(val) if val == nil then return "" end return val end GuildCharInfo.classLookup = {} GuildCharInfo.classLookup[1] = "dragonknight" GuildCharInfo.classLookup[2] = "sorcerer" GuildCharInfo.classLookup[3] = "nightblade" GuildCharInfo.classLookup[6] = "templar" --[[ Handler function for more info on links (the [*] next to char names) @param linkType - string for what type of link was clicked. we handle playerDetail only @param varargs - string concatenation of args. Format: accountName,guildID,guildIndex @post shows UI box with player info ]]-- GuildCharInfo.linkHandler = function(_, _, _, _, linkType, varargs) if linkType ~= "playerDetail" then return false end local acct, guild, index = SplitString(",", varargs) local _, name, zone, class, _, level, vr = GetGuildMemberCharacterInfo(guild, index) --local main = GuildCharInfo.lut[acct].main level = tonumber(level) if level >= 50 then level = "VR " .. vr end GCINameBoxName:SetText(nn(name):gsub("%^.*x$","")) GCINameBoxLevel:SetText(nn(level)) GCINameBoxClassIcon:SetTexture( "/esoui/art/contacts/social_classicon_" .. nn(GuildCharInfo.classLookup[class]) .. ".dds" ) GCINameBoxZone:SetText(nn(zone)) GCINameBoxAccount:SetText(nn(acct)) --GCINameBoxMain:SetText(nn("(" .. main .. ")")) --Resize box local line1 = GCINameBoxName:GetStringWidth(name) + 25 + 20 --local line2 = GCINameBoxLevel:GetWidth() + GCINameBoxAccount:GetWidth() + 10 --local line3 = GCINameBoxZone:GetWidth() local lineWidth = line1 GCINameBox:SetWidth(lineWidth) GCINameBox:SetHidden(false) return true end local function n0(val) if val == nil then return 0 else return val end end --[[ Change a 6-digit hex string into RGB values @param hex - 6-digit hex string in range 000000 to FFFFFF Note: if not length 6, wil return NIL values @return 3 values: red, green, blue All format decimal of range [0,1] ]]-- GuildCharInfo.hex2rgb = function(hex) --Return nil on invalid input if #hex ~= 6 then return nil, nil, nil end --Convert each two digits to a number local r= GuildCharInfo.hex2dec(string.sub(hex, 1, 2)) local g= GuildCharInfo.hex2dec(string.sub(hex, 3, 4)) local b= GuildCharInfo.hex2dec(string.sub(hex, 5, 6)) return n0(r)/255,n0(g)/255,n0(b)/255 end --[[ Change (r, g, b) into a 6-digit hex format string @param r - red channel intensity. Integer in [0, 255] @param g - green channel intensity. Integer in [0, 255] @param b - blue channel intensity. Integer in [0, 255] @return 6-digit hex string in range 000000 to FFFFFF ]] GuildCharInfo.rgb2hex = function(r, g, b) local str = GuildCharInfo.num2hex2(r) str = str .. GuildCharInfo.num2hex2(g) str = str .. GuildCharInfo.num2hex2(b) return str end GuildCharInfo.num2hex2 = function(d) if d > 1 then d = 1 end if d < 0 then d = 0 end local str = string.format("%X", d*255) if #str == 1 then str = "0" .. str end return str end --Quick hex2dec taking advantage of the fact tonumber recognizes hex input GuildCharInfo.hex2dec = function(dd) dd = "0x" .. dd return tonumber(dd) end GuildCharInfo.sanitizeSavedText = function(txt) txt = txt:gsub("&","&a;") txt = txt:gsub("%[","&o;") txt = txt:gsub("]","&c;") return txt end GuildCharInfo.unsanitizeSavedText = function(txt) txt = txt:gsub("&o;", "[") txt = txt:gsub("&c;", "]") txt = txt:gsub("&a;", "&") return txt end --[[ Init function to create UI configuration menu and managed config variables @post - UI menu created @post - preferences created and saved ]]-- GuildCharInfo.initUI = function() --Defaults local cfgDefault = {} cfgDefault.showMain = true cfgDefault.showAcct = false cfgDefault.showLink = true cfgDefault.linkText = "&o;*&c;]" cfgDefault.linkColor = "EEEEEE" GuildCharInfo.cfg = ZO_SavedVars:NewAccountWide('GuildCharacterInfo', 0.9, "config", cfgDefault) -- --Create menu panel -- local LAM = LibStub("LibAddonMenu-1.0") local pre = "GuildCharInfoUI" GuildCharInfo.panelID = LAM:CreateControlPanel("GuildCharNamesUI", "Guild Character Info") --Name formatting options LAM:AddHeader(GuildCharInfo.panelID, pre.."h1", "Name Format") LAM:AddCheckbox(GuildCharInfo.panelID, pre.."h1c1", "Account Name", "Show the account name (@name) in guild chat after the character name", function() return GuildCharInfo.cfg.showAcct end, function(val) GuildCharInfo.cfg.showAcct = val end, false --No warning ) LAM:AddCheckbox(GuildCharInfo.panelID, pre.."h1c2", "Main Character Name", "Show the name of the highest character in guild chat after current character name", function() return GuildCharInfo.cfg.showMain end, function(val) GuildCharInfo.cfg.showMain = val end, false --No warning ) --Link options LAM:AddHeader(GuildCharInfo.panelID, pre.."h2", "Info Link Format") LAM:AddCheckbox(GuildCharInfo.panelID, pre.."h2c1", "Show Link", "Show the info link after the name", function() return GuildCharInfo.cfg.showLink end, function(val) GuildCharInfo.cfg.showLink = val end, true, "If disabled, there is no way to view the player info card" ) LAM:AddColorPicker(GuildCharInfo.panelID, pre.."h2c2", "Link Color", "Change the color of the text link (default [*]) that shows the info card", function() return GuildCharInfo.hex2rgb(GuildCharInfo.cfg.linkColor) end, function(r,g,b) GuildCharInfo.cfg.linkColor = GuildCharInfo.rgb2hex(r,g,b) end, false -- No warning ) LAM:AddEditBox(GuildCharInfo.panelID, pre.."h2c3", "Link text", "Text shown after character name which on click shows the info box", false, -- Not multiline function() return GuildCharInfo.unsanitizeSavedText(GuildCharInfo.cfg.linkText) end, function(val) GuildCharInfo.cfg.linkText = GuildCharInfo.sanitizeSavedText(val) end, true, "If using pChat, do NOT include a '^' in the link text" ) end EVENT_MANAGER:RegisterForEvent("GuildCharacterInfo", EVENT_PLAYER_ACTIVATED, GuildCharInfo.init)