local AddOnName = ... local _G = _G local LibStub = LibStub local PA = LibStub('AceAddon-3.0'):NewAddon('ProjectAzilroka', 'AceEvent-3.0', 'AceTimer-3.0') _G.ProjectAzilroka = PA local select = select local pairs = pairs local sort = sort local tinsert = tinsert local print = print local format = format local strsplit = strsplit local GetAddOnMetadata = GetAddOnMetadata local GetAddOnEnableState = GetAddOnEnableState local UnitName = UnitName local UnitClass = UnitClass local GetRealmName = GetRealmName local UIParent = UIParent local BNGetFriendInfo = BNGetFriendInfo local BNGetGameAccountInfo = BNGetGameAccountInfo -- Ace Libraries PA.AC = LibStub('AceConfig-3.0') PA.GUI = LibStub('AceGUI-3.0') PA.ACR = LibStub('AceConfigRegistry-3.0') PA.ACD = LibStub('AceConfigDialog-3.0') PA.ACL = LibStub('AceLocale-3.0'):GetLocale(AddOnName, false) PA.ADB = LibStub('AceDB-3.0') -- Extra Libraries PA.LSM = LibStub('LibSharedMedia-3.0') PA.LDB = LibStub('LibDataBroker-1.1') PA.LCG = LibStub("LibCustomGlow-1.0") PA.LAB = LibStub('LibActionButton-1.0') PA.ACH = LibStub('LibAceConfigHelper') -- External Libraries PA.Masque = LibStub("Masque", true) PA.LCD = LibStub("LibClassicDurations", true) if PA.LCD then PA.LCD:Register(AddOnName) -- Register LibClassicDurations end -- WoW Data PA.MyClass = select(2, UnitClass('player')) PA.MyName = UnitName('player') PA.MyRace = select(2, UnitRace("player")) PA.MyRealm = GetRealmName() PA.Locale = GetLocale() PA.Noop = function() end PA.TexCoords = {.08, .92, .08, .92} if _G.ElvUI then PA.TexCoords = {0, 1, 0, 1} local modifier = 0.04 * _G.ElvUI[1].db.general.cropIcon for i, v in ipairs(PA.TexCoords) do if i % 2 == 0 then PA.TexCoords[i] = v - modifier else PA.TexCoords[i] = v + modifier end end end PA.UIScale = UIParent:GetScale() PA.MyFaction = UnitFactionGroup('player') PA.Classic = WOW_PROJECT_ID == WOW_PROJECT_CLASSIC PA.Retail = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE -- Pixel Perfect PA.ScreenWidth, PA.ScreenHeight = GetPhysicalScreenSize() PA.Multiple = 1 PA.Solid = PA.LSM:Fetch('background', 'Solid') -- Project Data function PA:IsAddOnEnabled(addon, character) if (type(character) == 'boolean' and character == true) then character = nil end return GetAddOnEnableState(character, addon) == 2 end function PA:IsAddOnPartiallyEnabled(addon, character) if (type(character) == 'boolean' and character == true) then character = nil end return GetAddOnEnableState(character, addon) == 1 end PA.Title = GetAddOnMetadata('ProjectAzilroka', 'Title') PA.Version = GetAddOnMetadata('ProjectAzilroka', 'Version') PA.Authors = GetAddOnMetadata('ProjectAzilroka', 'Author'):gsub(', ', ' ') PA.AllPoints = { CENTER = 'CENTER', BOTTOM = 'BOTTOM', TOP = 'TOP', LEFT = 'LEFT', RIGHT = 'RIGHT', BOTTOMLEFT = 'BOTTOMLEFT', BOTTOMRIGHT = 'BOTTOMRIGHT', TOPLEFT = 'TOPLEFT', TOPRIGHT = 'TOPRIGHT' } PA.ElvUI = PA:IsAddOnEnabled('ElvUI', PA.MyName) PA.SLE = PA:IsAddOnEnabled('ElvUI_SLE', PA.MyName) PA.NUI = PA:IsAddOnEnabled('ElvUI_NihilistUI', PA.MyName) PA.Tukui = PA:IsAddOnEnabled('Tukui', PA.MyName) PA.AzilUI = PA:IsAddOnEnabled('AzilUI', PA.MyName) PA.AddOnSkins = PA:IsAddOnEnabled('AddOnSkins', PA.MyName) -- Setup oUF for pbuf local function GetoUF() local key = PA.ElvUI and "ElvUI" or PA.Tukui and "Tukui" if not key then return end return _G[_G.GetAddOnMetadata(key, 'X-oUF')] end PA.oUF = GetoUF() PA.Classes = {} for k, v in pairs(LOCALIZED_CLASS_NAMES_MALE) do PA.Classes[v] = k end for k, v in pairs(LOCALIZED_CLASS_NAMES_FEMALE) do PA.Classes[v] = k end function PA:ClassColorCode(class) local color = PA:GetClassColor(PA.Classes[class]) return format('FF%02x%02x%02x', color.r * 255, color.g * 255, color.b * 255) end function PA:GetClassColor(class) return _G.CUSTOM_CLASS_COLORS and _G.CUSTOM_CLASS_COLORS[class] or _G.RAID_CLASS_COLORS[class] or { r = 1, g = 1, b = 1 } end local Color = PA:GetClassColor(PA.MyClass) PA.ClassColor = { Color.r, Color.g, Color.b } PA.ScanTooltip = CreateFrame('GameTooltip', 'PAScanTooltip', _G.UIParent, 'GameTooltipTemplate') PA.ScanTooltip:SetOwner(_G.UIParent, "ANCHOR_NONE") PA.PetBattleFrameHider = CreateFrame('Frame', 'PA_PetBattleFrameHider', UIParent, 'SecureHandlerStateTemplate') PA.PetBattleFrameHider:SetAllPoints() PA.PetBattleFrameHider:SetFrameStrata('LOW') RegisterStateDriver(PA.PetBattleFrameHider, 'visibility', '[petbattle] hide; show') function PA:GetUIScale() local effectiveScale = _G.UIParent:GetEffectiveScale() local magic = effectiveScale local scale = max(.64, min(1.15, magic)) if strlen(scale) > 6 then scale = tonumber(strsub(scale, 0, 6)) end return magic/scale end function PA:GetClassName(class) return PA.Classes[class] end function PA:Color(name) local color = '|cFF16C3F2%s|r' return (color):format(name) end function PA:Print(...) print(PA:Color(PA.Title..':'), ...) end function PA:ShortValue(value) if (value >= 1e6) then return gsub(format("%.1fm", value / 1e6), "%.?0+([km])$", "%1") elseif (value >= 1e3 or value <= -1e3) then return gsub(format("%.1fk", value / 1e3), "%.?0+([km])$", "%1") else return value end end function PA:RGBToHex(r, g, b, header, ending) r = r <= 1 and r >= 0 and r or 1 g = g <= 1 and g >= 0 and g or 1 b = b <= 1 and b >= 0 and b or 1 return format('%s%02x%02x%02x%s', header or '|cff', r*255, g*255, b*255, ending or '') end function PA:HexToRGB(hex) local a, r, g, b = strmatch(hex, '^|?c?(%x%x)(%x%x)(%x%x)(%x?%x?)|?r?$') if not a then return 0, 0, 0, 0 end if b == '' then r, g, b, a = a, r, g, 'ff' end return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), tonumber(a, 16) end function PA:ConflictAddOn(AddOns) for AddOn in pairs(AddOns) do if PA:IsAddOnEnabled(AddOn, PA.MyName) then return true end end return false end function PA:CountTable(T) local n = 0 for _ in pairs(T) do n = n + 1 end return n end function PA:PairsByKeys(t, f) local a = {} for n in pairs(t) do tinsert(a, n) end sort(a, f) local i = 0 local iter = function() i = i + 1 if a[i] == nil then return nil else return a[i], t[a[i]] end end return iter end function PA:AddKeysToTable(current, tbl) if type(current) ~= 'table' then return end for key, value in pairs(tbl) do if current[key] == nil then current[key] = value end end end function PA:SetTemplate(frame) if PA.AddOnSkins then _G.AddOnSkins[1]:SetTemplate(frame) else if not frame.SetBackdrop then _G.Mixin(frame, _G.BackdropTemplateMixin) end if frame.SetTemplate then frame:SetTemplate('Transparent', true) else frame:SetBackdrop({ bgFile = PA.Solid, edgeFile = PA.Solid, tile = false, tileSize = 0, edgeSize = 1, insets = { left = 0, right = 0, top = 0, bottom = 0 } }) end frame:SetBackdropColor(.08, .08, .08, .8) frame:SetBackdropBorderColor(0.2, 0.2, 0.2, 0) end end function PA:CreateBackdrop(frame) if PA.AddOnSkins then _G.AddOnSkins[1]:CreateBackdrop(frame) else frame.Backdrop = CreateFrame('Frame', nil, frame) frame.Backdrop:SetFrameLevel(frame:GetFrameLevel() - 1) frame.Backdrop:SetOutside(frame) PA:SetTemplate(frame.Backdrop) end end function PA:CreateShadow(frame) if PA.AddOnSkins then _G.AddOnSkins[1]:CreateShadow(frame) elseif frame.CreateShadow then frame:CreateShadow() if not PA.SLE and not PA.NUI then PA.ES:RegisterFrameShadows(frame) elseif PA.SLE or PA.NUI then _G.EnhancedShadows:RegisterShadow(frame.shadow) end end end function PA:SetInside(obj, anchor, xOffset, yOffset, anchor2) xOffset = xOffset or 1 yOffset = yOffset or 1 anchor = anchor or obj:GetParent() assert(anchor) if obj:GetPoint() then obj:ClearAllPoints() end obj:SetPoint('TOPLEFT', anchor, 'TOPLEFT', xOffset, -yOffset) obj:SetPoint('BOTTOMRIGHT', anchor2 or anchor, 'BOTTOMRIGHT', -xOffset, yOffset) end function PA:SetOutside(obj, anchor, xOffset, yOffset, anchor2) xOffset = xOffset or 1 yOffset = yOffset or 1 anchor = anchor or obj:GetParent() assert(anchor) if obj:GetPoint() then obj:ClearAllPoints() end obj:SetPoint('TOPLEFT', anchor, 'TOPLEFT', -xOffset, yOffset) obj:SetPoint('BOTTOMRIGHT', anchor2 or anchor, 'BOTTOMRIGHT', xOffset, -yOffset) end PA.ClassicServerNameByID = { [4703] = 'Amnennar', [4715] = 'Anathema', [4716] = 'Arcanite Reaper', [4742] = 'Ashbringer', [4387] = 'Ashkandi', [4372] = 'Atiesh', [4669] = 'Arugal', [4441] = 'Auberdine', [4376] = 'Azuresong', [4728] = 'Benediction', [4398] = 'Bigglesworth', [4397] = 'Blaumeux', [4746] = 'Bloodfang', [4648] = 'Bloodsail Buccaneers', [4386] = 'Deviate Delight', [4751] = 'Dragonfang', [4756] = "Dragon's Call", [4755] = 'Dreadmist', [4731] = 'Earthfury', [4749] = 'Earthshaker', [4440] = 'Everlook', [4408] = 'Faerlina', [4396] = 'Fairbanks', [4739] = 'Felstriker', [4744] = 'Finkle', [4467] = 'Firemaw', [4706] = 'Flamelash', [4702] = 'Gandling', [4476] = 'Gehennas', [4465] = 'Golemagg', [4647] = 'Grobbulus', [4732] = 'Heartseeker', [4763] = 'Heartstriker', [4406] = 'Herod', [4678] = 'Hydraxian Waterlords', [4698] = 'Incendius', [4758] = 'Judgement', [4700] = 'Kirtonos', [4699] = 'Kromcrush', [4399] = 'Kurinnaxx', [4442] = 'Lakeshire', [4801] = 'Loatheb', [4463] = 'Lucifron', [4813] = 'Mandokir', [4384] = 'Mankrik', [4454] = 'Mirage Raceway', [4701] = 'Mograine', [4373] = 'Myzrael', [4456] = 'Nethergarde Keep', [4729] = 'Netherwind', [4741] = 'Noggenfogger', [4374] = 'Old Blanchy', [4385] = 'Pagle', [4466] = 'Patchwerk', [4453] = 'Pyrewood Village', [4695] = 'Rattlegore', [4455] = 'Razorfen', [4478] = 'Razorgore', [4667] = 'Remulos', [4475] = 'Shazzrah', [4410] = 'Skeram', [4743] = 'Skullflame', [4696] = 'Smolderweb', [4409] = 'Stalagg', [4705] = 'Stonespine', [4726] = 'Sulfuras', [4464] = 'Sulfuron', [4737] = "Sul'thraze", [4757] = 'Ten Storms', [4407] = 'Thalnos', [4714] = 'Thunderfury', [4745] = 'Transcendence', [4477] = 'Venoxis', [4388] = 'Westfall', [4395] = 'Whitemane', [4727] = 'Windseeker', [4670] = 'Yojamba', [4676] = 'Zandalar Tribe', [4452] = 'Хроми', [4704] = 'Змейталак', [4754] = 'Рок-Делар', [4766] = 'Вестник Рока', [4474] = 'Пламегор', } local accountInfo = { gameAccountInfo = {} } function PA:GetBattleNetInfo(friendIndex) if PA.Classic then local bnetIDAccount, accountName, battleTag, isBattleTag, _, bnetIDGameAccount, _, isOnline, lastOnline, isBnetAFK, isBnetDND, messageText, noteText, _, messageTime, _, isReferAFriend, canSummonFriend, isFavorite = BNGetFriendInfo(friendIndex) if not bnetIDGameAccount then return end local hasFocus, characterName, client, realmName, realmID, faction, race, class, guild, zoneName, level, gameText, broadcastText, broadcastTime, _, toonID, _, isGameAFK, isGameBusy, guid, wowProjectID, mobile = BNGetGameAccountInfo(bnetIDGameAccount) accountInfo.bnetAccountID = bnetIDAccount accountInfo.accountName = accountName accountInfo.battleTag = battleTag accountInfo.isBattleTagFriend = isBattleTag accountInfo.isDND = isBnetDND accountInfo.isAFK = isBnetAFK accountInfo.isFriend = true accountInfo.isFavorite = isFavorite accountInfo.note = noteText accountInfo.rafLinkType = 0 accountInfo.appearOffline = false accountInfo.customMessage = messageText accountInfo.lastOnlineTime = lastOnline accountInfo.customMessageTime = messageTime accountInfo.gameAccountInfo.clientProgram = client or "App" accountInfo.gameAccountInfo.richPresence = gameText ~= '' and gameText or PA.ACL["Mobile"] accountInfo.gameAccountInfo.gameAccountID = bnetIDGameAccount accountInfo.gameAccountInfo.isOnline = isOnline accountInfo.gameAccountInfo.isGameAFK = isGameAFK accountInfo.gameAccountInfo.isGameBusy = isGameBusy accountInfo.gameAccountInfo.isWowMobile = mobile accountInfo.gameAccountInfo.hasFocus = hasFocus accountInfo.gameAccountInfo.canSummon = canSummonFriend if wowProjectID == _G.WOW_PROJECT_MAINLINE then zoneName, realmName = strsplit("-", gameText) end if client == _G.BNET_CLIENT_WOW then accountInfo.gameAccountInfo.characterName = characterName accountInfo.gameAccountInfo.factionName = faction ~= '' and faction or nil accountInfo.gameAccountInfo.playerGuid = guid accountInfo.gameAccountInfo.wowProjectID = wowProjectID accountInfo.gameAccountInfo.realmID = realmID accountInfo.gameAccountInfo.realmDisplayName = realmName accountInfo.gameAccountInfo.realmName = realmName accountInfo.gameAccountInfo.areaName = zoneName accountInfo.gameAccountInfo.className = class accountInfo.gameAccountInfo.characterLevel = level accountInfo.gameAccountInfo.raceName = race else accountInfo.gameAccountInfo.characterName = nil accountInfo.gameAccountInfo.factionName = nil accountInfo.gameAccountInfo.playerGuid = nil accountInfo.gameAccountInfo.wowProjectID = nil accountInfo.gameAccountInfo.realmID = nil accountInfo.gameAccountInfo.realmDisplayName = nil accountInfo.gameAccountInfo.realmName = nil accountInfo.gameAccountInfo.areaName = nil accountInfo.gameAccountInfo.className = nil accountInfo.gameAccountInfo.characterLevel = nil accountInfo.gameAccountInfo.raceName = nil end return accountInfo else accountInfo = _G.C_BattleNet.GetFriendAccountInfo(friendIndex) if accountInfo and accountInfo.gameAccountInfo.wowProjectID == _G.WOW_PROJECT_CLASSIC then accountInfo.gameAccountInfo.realmDisplayName = PA.ClassicServerNameByID[accountInfo.gameAccountInfo.realmID] or accountInfo.gameAccountInfo.realmID end return accountInfo end end StaticPopupDialogs["PROJECTAZILROKA"] = { text = PA.ACL["A setting you have changed will change an option for this character only. This setting that you have changed will be uneffected by changing user profiles. Changing this setting requires that you reload your User Interface."], button1 = ACCEPT, button2 = CANCEL, OnAccept = ReloadUI, timeout = 0, whileDead = 1, hideOnEscape = false, } StaticPopupDialogs["PROJECTAZILROKA_RL"] = { text = PA.ACL["This setting requires that you reload your User Interface."], button1 = ACCEPT, button2 = CANCEL, OnAccept = ReloadUI, timeout = 0, whileDead = 1, hideOnEscape = false, } PA.Defaults = { profile = { Cooldown = { Enable = true, threshold = 3, hideBlizzard = false, useIndicatorColor = false, expiringColor = { r = 1, g = 0, b = 0 }, secondsColor = { r = 1, g = 1, b = 0 }, minutesColor = { r = 1, g = 1, b = 1 }, hoursColor = { r = 0.4, g = 1, b = 1 }, daysColor = { r = 0.4, g = 0.4, b = 1 }, expireIndicator = { r = 1, g = 1, b = 1 }, secondsIndicator = { r = 1, g = 1, b = 1 }, minutesIndicator = { r = 1, g = 1, b = 1 }, hoursIndicator = { r = 1, g = 1, b = 1 }, daysIndicator = { r = 1, g = 1, b = 1 }, hhmmColorIndicator = { r = 1, g = 1, b = 1 }, mmssColorIndicator = { r = 1, g = 1, b = 1 }, checkSeconds = false, hhmmColor = { r = 0.43, g = 0.43, b = 0.43 }, mmssColor = { r = 0.56, g = 0.56, b = 0.56 }, hhmmThreshold = -1, mmssThreshold = -1, fonts = { enable = false, font = 'PT Sans Narrow', fontOutline = 'OUTLINE', fontSize = 18, }, } } } PA.Options = PA.ACH:Group(PA:Color(PA.Title), nil, 6) function PA:GetOptions() PA.AceOptionsPanel.Options.args.ProjectAzilroka = PA.Options end function PA:BuildProfile() PA.data = PA.ADB:New('ProjectAzilrokaDB', PA.Defaults, true) PA.data.RegisterCallback(PA, 'OnProfileChanged', 'SetupProfile') PA.data.RegisterCallback(PA, 'OnProfileCopied', 'SetupProfile') PA.Options.args.profiles = LibStub('AceDBOptions-3.0'):GetOptionsTable(PA.data) PA.Options.args.profiles.order = -2 PA.db = PA.data.profile end function PA:SetupProfile() PA.db = PA.data.profile for _, module in PA:IterateModules() do if module.UpdateSettings then module:UpdateSettings() end end end function PA:CallModuleFunction(module, func) local pass, err = pcall(func, module) if not pass and PA.Debug then error(err) end end function PA:PLAYER_LOGIN() PA.Multiple = PA:GetUIScale() PA.AS = _G.AddOnSkins and _G.AddOnSkins[1] PA.EP = LibStub('LibElvUIPlugin-1.0', true) PA.AceOptionsPanel = PA.ElvUI and _G.ElvUI[1] or PA.EC PA.Options.childGroups = PA.EC and 'tab' or 'tree' for _, module in PA:IterateModules() do if module.BuildProfile then PA:CallModuleFunction(module, module.BuildProfile) end end PA:BuildProfile() if PA.EP then PA.EP:RegisterPlugin('ProjectAzilroka', PA.GetOptions) end PA:UpdateCooldownSettings('all') for _, module in PA:IterateModules() do if module.GetOptions then PA:CallModuleFunction(module, module.GetOptions) end if module.Initialize then PA:CallModuleFunction(module, module.Initialize) end end end PA:RegisterEvent('PLAYER_LOGIN')