diff --git a/CHANGELOG.html b/CHANGELOG.html index 53ee497..a4265a5 100644 --- a/CHANGELOG.html +++ b/CHANGELOG.html @@ -1,3 +1,27 @@ +
LARGE REWRITE FOR WRATH
+SETTINGS WILL BE RESET
++
New Features
++
Regressions
+
Bug Fixes
diff --git a/Config.lua b/Config.lua index 8e2b472..ec7373e 100644 --- a/Config.lua +++ b/Config.lua @@ -1,29 +1,48 @@ - local ADDON_NAME, Data = ... +local Addon = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME) +local L = LibStub("AceLocale-3.0"):GetLocale(ADDON_NAME) -local buildMajor = tonumber(GetBuildInfo():match"^(%d+)%.") -if buildMajor == 2 then - Data.WOW_VERSION = "BCC" -elseif buildMajor == 1 then - Data.WOW_VERSION = "Classic" -end - -function Data:IsBCC() - return Data.WOW_VERSION == "BCC" -end -function Data:IsClassic() - return Data.WOW_VERSION == "Classic" -end +local strGmatch = string.gmatch +local strGsub = string.gsub +local strByte = string.byte +local tinsert = table.insert +local tblRemove = table.remove +local tblConcat = table.concat +local mathMin = math.min +local mathMax = math.max -local function rgb(r, g, b) - return {r, g, b} -end +-- these are optional table which may be defined in /LocaleExtra +-- they are run when relevant settings are reset or initialized +local localeDefaultOverrideMethods = { + SetDefaultRewordByLocale = {"reword" , "defaultRewordLocaleOverrides"}, + SetDefaultModByLocale = {"mod" , "defaultModLocaleOverrides"}, + SetDefaultPrecisionByLocale = {"precision", "defaultPrecisionLocaleOverrides"}, +} +for method, data in pairs(localeDefaultOverrideMethods) do + local field, overrides = unpack(data, 1, 2) + Addon[method] = function(self, stat) + if stat then + if Addon[overrides][stat] then + Addon.SetOption(self, Addon[overrides][stat], field, stat) + end + else + for stat, val in pairs(Addon[overrides]) do + Addon.SetOption(self, val, field, stat) + end + end + end +end +function Addon:OverrideAllLocaleDefaults() + for method in pairs(localeDefaultOverrideMethods) do + Addon[method](self) + end +end -- ██████╗ ██████╗ ███╗ ██╗███████╗██╗ ██████╗ @@ -34,164 +53,193 @@ end -- ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝ - -Data.CHAT_COMMAND = "zt" - --- Fastest weapon speed -Data.WEAPON_SPEED_MIN = 1.2 - --- Slowest weapon speed -Data.WEAPON_SPEED_MAX = 4.0 - --- How spread out options are in interface options -Data.OPTIONS_DIVIDER_HEIGHT = 3 - -local COLORS = { - WHITE = rgb(255, 255, 255), - ORANGE = rgb(255, 127, 32), - GREEN = rgb( 0, 255, 0), - BLUE = rgb( 0, 0, 255), - - ARCANE = rgb(255, 127, 255), - FIRE = rgb(255, 128, 0), - NATURE = rgb( 76, 255, 76), - FROST = rgb(127, 255, 255), - SHADOW = rgb(127, 127, 255), - HOLY = rgb(255, 229, 127), - - HONEYSUCKLE = rgb(237, 252, 132), - LIGHT_YELLOW_GREEN = rgb(204, 253, 127), - REEF = rgb(201, 255, 162), - PALE_LIGHT_GREEN = rgb(177, 252, 153), - FOAM_GREEN = rgb(144, 253, 169), - PARIS_GREEN = rgb( 80, 200, 120), - LEMON_LIME = rgb(191, 254, 40), - - YELLOW = rgb(255, 255, 0), - SANDY_YELLOW = rgb(253, 238, 115), - - CITRON = rgb(158, 169, 31), - BRASS = rgb(181, 166, 66), - - TUMBLEWEED = rgb(222, 166, 129), - ATOMIC_TANGERINE = rgb(255, 153, 102), - PUMPKIN_ORANGE = rgb(248, 114, 23), - - SUNSET_ORANGE = rgb(253, 94, 83), - ROSSO_CORSA = rgb(212, 0, 0), - - PINK_SHERBET = rgb(247, 143, 167), - BLUSH_PINK = rgb(230, 169, 236), - LIGHT_FUSCHIA_PINK = rgb(249, 132, 239), - PURPLE_PIZZAZZ = rgb(255, 80, 218), - BRIGHT_NEON_PINK = rgb(244, 51, 255), - - LILAC = rgb(206, 162, 253), - PURPLE_MIMOSA = rgb(158, 123, 255), - HELIOTROPE_PURPLE = rgb(212, 98, 255), - NEON_PURPLE = rgb(188, 19, 254), - - LIGHT_AQUA = rgb(140, 255, 219), - LIGHT_CYAN = rgb(172, 255, 252), - FRENCH_PASS = rgb(189, 237, 253), - BABY_BLUE = rgb(162, 207, 254), - JORDY_BLUE = rgb(138, 185, 241), - DENIM_BLUE = rgb(121, 186, 236), - CRYSTAL_BLUE = rgb( 92, 179, 255), +local icons = { + "|TInterface\\Buttons\\UI-AttributeButton-Encourage-Up:0|t", + "|TInterface\\Buttons\\UI-GroupLoot-Coin-Up:0|t", + "|TInterface\\Buttons\\UI-GroupLoot-DE-Up:0|t", + "|TInterface\\Buttons\\UI-GroupLoot-Dice-Up:0|t", + + "|TInterface\\Buttons\\UI-PlusButton-Up:0|t", + "|TInterface\\Buttons\\UI-PlusButton-Disabled:0|t", + "|TInterface\\Buttons\\UI-CheckBox-Check:0|t", + "|TInterface\\Buttons\\UI-CheckBox-Check-Disabled:0|t", + -- "|TInterface\\Buttons\\UI-SliderBar-Button-Vertical:0|t", + + -- "|TInterface\\COMMON\\FavoritesIcon:0|t", + -- "|TInterface\\COMMON\\friendship-archivistscodex:0|t", + -- "|TInterface\\COMMON\\friendship-FistHuman:0|t", + -- "|TInterface\\COMMON\\friendship-FistOrc:0|t", + "|TInterface\\COMMON\\friendship-heart:0|t", + "|TInterface\\COMMON\\friendship-manaorb:0|t", + -- "|TInterface\\COMMON\\help-i:0|t", + -- "|TInterface\\COMMON\\Indicator-Gray:0|t", + -- "|TInterface\\COMMON\\Indicator-Green:0|t", + -- "|TInterface\\COMMON\\Indicator-Yellow:0|t", + -- "|TInterface\\COMMON\\Indicator-Red:0|t", + "|TInterface\\COMMON\\RingBorder:0|t", + + "|TInterface\\CURSOR\\Attack:0|t", + -- "|TInterface\\CURSOR\\Missions:0|t", + "|TInterface\\CURSOR\\Cast:0|t", + "|TInterface\\CURSOR\\Point:0|t", + "|TInterface\\CURSOR\\Crosshairs:0|t", + + "|TInterface\\FriendsFrame\\InformationIcon:0|t", + -- "|TInterface\\FriendsFrame\\StatusIcon-Away:0|t", + -- "|TInterface\\FriendsFrame\\StatusIcon-DnD:0|t", + "|TInterface\\FriendsFrame\\StatusIcon-Offline:0|t", + "|TInterface\\FriendsFrame\\StatusIcon-Online:0|t", + + "|TInterface\\HELPFRAME\\HotIssueIcon:0|t", + -- "|TInterface\\HELPFRAME\\HelpIcon-HotIssues:0|t", + -- "|TInterface\\HELPFRAME\\HelpIcon-Suggestion:0|t", + -- "|TInterface\\HELPFRAME\\ReportLagIcon-Spells:0|t", + + "|TInterface\\MINIMAP\\Dungeon:0|t", + "|TInterface\\MINIMAP\\Raid:0|t", + "|TInterface\\MINIMAP\\TempleofKotmogu_ball_cyan:0|t", + "|TInterface\\MINIMAP\\TempleofKotmogu_ball_green:0|t", + "|TInterface\\MINIMAP\\TempleofKotmogu_ball_orange:0|t", + "|TInterface\\MINIMAP\\TempleofKotmogu_ball_purple:0|t", + "|TInterface\\MINIMAP\\Vehicle-AllianceMagePortal:0|t", + "|TInterface\\MINIMAP\\Vehicle-HordeMagePortal:0|t", + + "|TInterface\\MONEYFRAME\\Arrow-Left-Down:0|t", + -- "|TInterface\\MONEYFRAME\\Arrow-Left-Up:0|t", + "|TInterface\\MONEYFRAME\\Arrow-Right-Down:0|t", + -- "|TInterface\\MONEYFRAME\\Arrow-Right-Up:0|t", + + "|TInterface\\Transmogrify\\transmog-tooltip-arrow:0|t", + + "|TInterface\\Tooltips\\ReforgeGreenArrow:0|t", + + "|TInterface\\OPTIONSFRAME\\VoiceChat-Play:0|t", + "|TInterface\\OPTIONSFRAME\\VoiceChat-Record:0|t", + + "|TInterface\\RAIDFRAME\\ReadyCheck-Ready:0|t", + + "|TInterface\\TARGETINGFRAME\\UI-RaidTargetingIcon_1:0|t", + "|TInterface\\TARGETINGFRAME\\UI-RaidTargetingIcon_2:0|t", + "|TInterface\\TARGETINGFRAME\\UI-RaidTargetingIcon_3:0|t", + "|TInterface\\TARGETINGFRAME\\UI-RaidTargetingIcon_4:0|t", + "|TInterface\\TARGETINGFRAME\\UI-RaidTargetingIcon_5:0|t", + "|TInterface\\TARGETINGFRAME\\UI-RaidTargetingIcon_6:0|t", + "|TInterface\\TARGETINGFRAME\\UI-RaidTargetingIcon_7:0|t", + "|TInterface\\TARGETINGFRAME\\UI-RaidTargetingIcon_8:0|t", } +local iconsDropdown = Addon:Map(icons, nil, function(v) return v end) -function Data:MakeDefaultOptions() - return { - profile = { - SIMPLIFY = true, - REORDER = true, - RECOLOR = true, - - RECOLOR_USABLE = true, - - SHOW_SPEEDBAR = true, - - -- Bar width. Longer is more accurate but can cause a wider tooltip - SPEEDBAR_SIZE = 10, - - -- Number of significant decimal places on weapon speeds - SPEED_ACCURACY = 1, - - COLORS = { - TRAINABLE = COLORS.ORANGE, - WEAP_DAMAGE = COLORS.TUMBLEWEED, - SPEED = COLORS.WHITE, - ENCHANT = COLORS.GREEN, - SKILL = COLORS.GREEN, - - ARMOR = COLORS.YELLOW, - - STAMINA = COLORS.PALE_LIGHT_GREEN, - STRENGTH = COLORS.TUMBLEWEED, - AGILITY = COLORS.SANDY_YELLOW, - INTELLECT = COLORS.JORDY_BLUE, - SPIRIT = COLORS.LIGHT_AQUA, - - ARCANE_RESIST = COLORS.ARCANE, - FIRE_RESIST = COLORS.FIRE, - NATURE_RESIST = COLORS.NATURE, - FROST_RESIST = COLORS.FROST, - SHADOW_RESIST = COLORS.SHADOW, - HOLY_RESIST = COLORS.HOLY, + +function Addon:MakeDefaultOptions() + local fakeAddon = { + db = { + profile = { - ARCANE_DAMAGE = COLORS.ARCANE, - FIRE_DAMAGE = COLORS.FIRE, - NATURE_DAMAGE = COLORS.NATURE, - FROST_DAMAGE = COLORS.FROST, - SHADOW_DAMAGE = COLORS.SHADOW, - HOLY_DAMAGE = COLORS.HOLY, + enabled = true, + invertMode = "none", + modKeys = { + ["*"] = true, + }, - DEFENSE = COLORS.PALE_LIGHT_GREEN, - RESILIENCE = COLORS.HONEYSUCKLE, - DODGE = COLORS.HONEYSUCKLE, - PARRY = COLORS.PARIS_GREEN, - BLOCK_RATING = COLORS.LEMON_LIME, - BLOCK_VALUE = COLORS.LEMON_LIME, - RESIST_ALL = COLORS.PALE_LIGHT_GREEN, + allow = { -- only applies to stats + reorder = true, + reword = true, + recolor = true, + }, - ATTACK_POW = COLORS.TUMBLEWEED, - R_ATTACK_POW = COLORS.TUMBLEWEED, - PHYS_HIT = COLORS.SANDY_YELLOW, - PHYS_CRIT = COLORS.ATOMIC_TANGERINE, - PHYS_HASTE = COLORS.CITRON, - PHYS_PEN = COLORS.PUMPKIN_ORANGE, - EXPERTISE = COLORS.TUMBLEWEED, + order = { + wrath = tblConcat(self.statList.wrath , ","), + tbc = tblConcat(self.statList.tbc , ","), + classic = tblConcat(self.statList.classic, ","), + }, + hide = { + ["*"] = false, + uselessRaces = true, + }, + doReword = { + ["*"] = true, + Enchant = false, + Equip = false, + Use = false, + ChanceOnHit = false, + }, + reword = { + ["*"] = "", + }, + mod = { + ["*"] = 1, + }, + precision = { + ["*"] = 0, + Speed = 1, + }, + doRecolor = { + ["*"] = true, + }, + color = (function() local colors = {["*"] = "00ff00"} for stat, StatInfo in pairs(self.statsInfo) do colors[stat] = StatInfo.color end return colors end)(), - MAGICAL = COLORS.LIGHT_FUSCHIA_PINK, - MAGIC_HIT = COLORS.PURPLE_PIZZAZZ, - MAGIC_CRIT = COLORS.PURPLE_MIMOSA, - MAGIC_HASTE = COLORS.LILAC, - MAGIC_PEN = COLORS.HELIOTROPE_PURPLE, + damage = { + ["*"] = true, + showVariance = false, + ["variancePrefix"] = "+-", + }, + dps = { + ["*"] = true, + }, + speedBar = { + min = 1.2, + max = 4, + size = 15, + fillChar = "I", + blankChar = " ", + speedPrefix = false, + }, + trimSpace = { + ["*"] = true, + }, + doIcon = { + ["*"] = false, + Enchant = true, + }, + icon = { + Enchant = "|TInterface\\Buttons\\UI-GroupLoot-DE-Up:0|t", + Equip = "|TInterface\\Tooltips\\ReforgeGreenArrow:0|t", + Use = "|TInterface\\CURSOR\\Cast:0|t", + ChanceOnHit = "|TInterface\\Buttons\\UI-GroupLoot-Dice-Up:0|t", + }, + iconSpace = { + ["*"] = true, + }, - HEALING = COLORS.LIGHT_CYAN, - HEALTH = COLORS.PALE_LIGHT_GREEN, - MANA = COLORS.JORDY_BLUE, - }, - - RECOLOR_STAT = { - ["**"] = true, + pad = { + before = { + ["*"] = true, + BaseStat = false, + }, + after = { + ["*"] = true, + }, + }, + padLastLine = true, + combineStats = true, - WEAP_DAMAGE = false, - SPEED = false, - ENCHANT = false, - SKILL = false, - }, - Debug = { - enabled = true, - menu = false, + cache = { + ["*"] = true, + }, - showLabels = false, - ctrlSupprseeion = false, + -- TODO: config options for blizzard fixes? + fixAuctionFrame = true, + fixInspectFrame = true, + fixMailFrame = true, + fixOptionsMenu = false, }, }, } + Addon.OverrideAllLocaleDefaults(fakeAddon) + return fakeAddon.db end + -- ███████╗███╗ ██╗██████╗ ██████╗ ██████╗ ███╗ ██╗███████╗██╗ ██████╗ -- ██╔════╝████╗ ██║██╔══██╗ ██╔════╝██╔═══██╗████╗ ██║██╔════╝██║██╔════╝ -- █████╗ ██╔██╗ ██║██║ ██║ ██║ ██║ ██║██╔██╗ ██║█████╗ ██║██║ ███╗ @@ -203,520 +251,883 @@ end -function Data:Round(num, decimalPlaces) - local mult = 10^(tonumber(decimalPlaces) or 0) - return math.floor(tonumber(num) * mult + 0.5) / mult -end - - - -function Data:IsSameColor(color1, color2) - for k, v in pairs(color1) do - if color2[k] ~= v then - return false - end - end - return true -end - -function Data:IsSameColorFuzzy(color1, color2, fuzziness) - fuzziness = fuzziness or 0.02 * 255 - for k, v in pairs(color1) do - if math.abs(color2[k] - v) > fuzziness then - return false - end - end - return true -end - - - - -Data.CLASS = select(2, UnitClass"player") - -Data.WEAPON_SPEED_DIF = Data.WEAPON_SPEED_MAX - Data.WEAPON_SPEED_MIN - -Data.COLOR_CODE = "|c%x%x%x%x%x%x%x%x" -Data.COLOR_CODE_RESET = "|r" - -Data.GRAY = rgb(127, 127, 127) -Data.RED = rgb(255, 32, 32) -Data.GREEN = rgb( 0, 255, 0) - - - -local ELEMENTS_ENGLISH = { - "Arcane", - "Fire", - "Nature", - "Frost", - "Shadow", - "Holy", -} -local ELEMENT_KEYS = {} -for i, element in ipairs(ELEMENTS_ENGLISH) do - ELEMENT_KEYS[i] = element:upper() -end -local ELEMENTS = { - STRING_SCHOOL_ARCANE, - STRING_SCHOOL_FIRE, - STRING_SCHOOL_NATURE, - STRING_SCHOOL_FROST, - STRING_SCHOOL_SHADOW, - STRING_SCHOOL_HOLY, -} -local ELEMENT_PATTERNS = {} -for i, element in ipairs(ELEMENTS) do - local elementPattern = "" - for char in element:gmatch"." do - if char:match"%u" then - elementPattern = ("%s[%s%s]"):format(elementPattern, char, char:lower()) - elseif char:match"%p" then - elementPattern = elementPattern .. "%" .. char - else - elementPattern = elementPattern .. char - end - end - ELEMENT_PATTERNS[i] = elementPattern -end - -function Data:GetElements() - return ELEMENTS -end -function Data:GetElement(i) - return self:GetElements()[i] -end -function Data:GetElementPattern(i) - return ELEMENT_PATTERNS[i] -end -function Data:GetElementEnglish(i) - return ELEMENTS_ENGLISH[i] -end -function Data:GetElementKey(i) - return ELEMENT_KEYS[i] -end - - - -function Data:OnInitialize(L) - - local LEFT_TYPES = {} - for _, globalString in ipairs{ - "INVTYPE_WEAPON", - "INVTYPE_WEAPONOFFHAND", - "INVTYPE_SHIELD", - "INVTYPE_RANGED", - "INVTYPE_2HWEAPON", - "INVTYPE_HOLDABLE", - "INVTYPE_WEAPONMAINHAND", - "INVTYPE_RELIC", - "INVTYPE_THROWN", - - "INVTYPE_HEAD", - -- "INVTYPE_NECK", - -- "INVTYPE_BODY", - "INVTYPE_CHEST", - "INVTYPE_LEGS", - "INVTYPE_FEET", - "INVTYPE_WRIST", - "INVTYPE_HAND", - -- "INVTYPE_FINGER", - -- "INVTYPE_CLOAK", - -- "INVTYPE_TABARD", - "INVTYPE_ROBE", - "INVTYPE_SHOULDER", - -- "INVTYPE_TRINKET", - "INVTYPE_WAIST", - -- "INVTYPE_AMMO", - } do - LEFT_TYPES[globalString] = _G[globalString] - end - - - local ITEM_TYPES = { - [WEAPON] = 2, - [ARMOR] = 4, - } - - local SUBTYPES_DATA = { - [WEAPON] = { - [1] = {subType = "Two-Handed Axes" , text = L["Axe"]}, - [0] = {subType = "One-Handed Axes" , text = L["Axe"]}, - [8] = {subType = "Two-Handed Swords", text = L["Sword"]}, - [7] = {subType = "One-Handed Swords", text = L["Sword"]}, - [5] = {subType = "Two-Handed Maces" , text = L["Mace"]}, - [4] = {subType = "One-Handed Maces" , text = L["Mace"]}, - [6] = {subType = "Polearms" , text = L["Polearm"]}, - [10] = {subType = "Staves" , text = L["Staff"]}, - [15] = {subType = "Daggers" , text = L["Dagger"]}, - [13] = {subType = "Fist Weapons" , text = L["Fist Weapon"]}, - - [2] = {subType = "Bows" , text = L["Bow"]}, - [18] = {subType = "Crossbows" , text = L["Crossbow"]}, - [3] = {subType = "Guns" , text = L["Gun"]}, - [16] = {subType = "Thrown" , text = L["Thrown"]}, - [19] = {subType = "Wands" , text = L["Wand"]}, - }, - - [ARMOR] = { - -- [0] = {subType = "Miscellaneous", text = L["Miscellaneous"]}, - -- [1] = {subType = "Cloth" , text = L["Cloth"]}, - [2] = {subType = "Leather" , text = L["Leather"]}, - [3] = {subType = "Mail" , text = L["Mail"]}, - [4] = {subType = "Plate" , text = L["Plate"]}, - [6] = {subType = "Shields" , text = L["Shield"]}, - [7] = {subType = "Librams" , text = L["Libram"]}, - [8] = {subType = "Idols" , text = L["Idol"]}, - [9] = {subType = "Totems" , text = L["Totem"]}, - }, - } - - local SUBTYPES_LOCALE_MAP = {} - local ITEM_SUBTYPES = {} - for _, key in ipairs{WEAPON, ARMOR} do - SUBTYPES_LOCALE_MAP[key] = {} - ITEM_SUBTYPES[key] = {} - for i, data in pairs(SUBTYPES_DATA[key]) do - SUBTYPES_LOCALE_MAP[key][data.subType] = GetItemSubClassInfo(ITEM_TYPES[key], i) - ITEM_SUBTYPES[key][GetItemSubClassInfo(ITEM_TYPES[key], i)] = data.text - end - end - - - - local USABLE_WEAPONS = { - DRUID = {"Two-Handed Maces", "One-Handed Maces", "Staves", "Daggers", "Fist Weapons"}, - HUNTER = {"Two-Handed Axes", "One-Handed Axes", "Two-Handed Swords", "One-Handed Swords", "Polearms", "Staves", "Daggers", "Fist Weapons", "Bows", "Crossbows", "Guns", "Thrown"}, - MAGE = {"One-Handed Swords", "Staves", "Daggers", "Wands"}, - PALADIN = {"Two-Handed Axes", "One-Handed Axes", "Two-Handed Swords", "One-Handed Swords", "Two-Handed Maces", "One-Handed Maces", "Polearms"}, - PRIEST = {"One-Handed Maces", "Staves", "Daggers", "Wands"}, - ROGUE = {"One-Handed Swords", "One-Handed Maces", "Daggers", "Fist Weapons", "Bows", "Crossbows", "Guns", "Thrown"}, - SHAMAN = {"Two-Handed Axes", "One-Handed Axes", "Two-Handed Maces", "One-Handed Maces", "Staves", "Daggers", "Fist Weapons"}, - WARLOCK = {"One-Handed Swords", "Staves", "Daggers", "Wands"}, - WARRIOR = {"Two-Handed Axes", "One-Handed Axes", "Two-Handed Swords", "One-Handed Swords", "Two-Handed Maces", "One-Handed Maces", "Polearms", "Staves", "Daggers", "Fist Weapons", "Bows", "Crossbows", "Guns", "Thrown"}, - } - local USABLE_ARMORS = { - DRUID = {"Leather", "Idols"}, - HUNTER = {"Leather", "Mail"}, - MAGE = {}, - PALADIN = {"Leather", "Mail", "Plate", "Shields", "Librams"}, - PRIEST = {}, - ROGUE = {"Leather"}, - SHAMAN = {"Leather", "Mail", "Shields", "Totems"}, - WARLOCK = {}, - WARRIOR = {"Leather", "Mail", "Plate", "Shields"}, - } - local UNUSABLE_INVTYPES = { - DRUID = {INVTYPE_WEAPONOFFHAND = true}, - HUNTER = {}, - MAGE = {INVTYPE_WEAPONOFFHAND = true}, - PALADIN = {INVTYPE_WEAPONOFFHAND = true}, - PRIEST = {INVTYPE_WEAPONOFFHAND = true}, - ROGUE = {}, - SHAMAN = {INVTYPE_WEAPONOFFHAND = true}, - WARLOCK = {INVTYPE_WEAPONOFFHAND = true}, - WARRIOR = {}, - } - local USABLE_EQUIPMENT = {} - for class, weapons in pairs(USABLE_WEAPONS) do - USABLE_EQUIPMENT[class] = {} - USABLE_EQUIPMENT[class][WEAPON] = {} - for _, weapon in ipairs(weapons) do - USABLE_EQUIPMENT[class][WEAPON][SUBTYPES_LOCALE_MAP[WEAPON][weapon]] = true - end - end - for class, armors in pairs(USABLE_ARMORS) do - USABLE_EQUIPMENT[class][ARMOR] = {} - for _, armor in ipairs(armors) do - USABLE_EQUIPMENT[class][ARMOR][SUBTYPES_LOCALE_MAP[ARMOR][armor]] = true - end - end - - - - function Data:IsUsable(itemType, itemSubType, invType) - return USABLE_EQUIPMENT[self.CLASS][itemType] and USABLE_EQUIPMENT[self.CLASS][itemType][itemSubType] and not UNUSABLE_INVTYPES[self.CLASS][invType] and true or false - end - - function Data:GetRedText(itemType, itemSubType, invType) - return ITEM_SUBTYPES[itemType] and ITEM_SUBTYPES[itemType][itemSubType] or nil, invType == "INVTYPE_WEAPONOFFHAND" and not UNUSABLE_INVTYPES[invType] and LEFT_TYPES["INVTYPE_WEAPONOFFHAND"] or nil - end - -end - - - -function Data:FontifyColor(color) - return color[1]/255, color[2]/255, color[3]/255, 1 -end -function Data:DefontifyColor(r, g, b) - return {r*255, g*255, b*255} -end -local function GetOptionTableHelpers(Options, Addon) - local defaultInc = 1000 - local order = 1000 +function Addon:InitOptionTableHelpers() + self.GUI = {} + local GUI = self.GUI - local GUI = {} + local defaultInc = 1000 + local defaultOrder = 1000 + local order = defaultOrder function GUI:GetOrder() return order end function GUI:SetOrder(newOrder) order = newOrder + return self + end + function GUI:ResetOrder() + order = defaultOrder + return self end function GUI:Order(inc) self:SetOrder(self:GetOrder() + (inc or defaultInc)) return self:GetOrder() end - function GUI:CreateEntry(keys, name, desc, widgetType, disabled, order) + function GUI:CreateEntry(opts, keys, name, desc, widgetType, disabled, order) if type(keys) ~= "table" then keys = {keys} end - local key = widgetType .. "_" .. (table.concat(keys, ".") or "") - Options.args[key] = {name = name, desc = desc, type = widgetType, order = order or self:Order(), disabled = disabled} - Options.args[key].set = function(info, val) Addon:SetOption(val, unpack(keys)) end - Options.args[key].get = function(info) return Addon:GetOption(unpack(keys)) end - return Options.args[key] + local key = widgetType .. "_" .. (tblConcat(keys, ".") or "") + opts.args[key] = {name = name, desc = desc, type = widgetType, order = order or self:Order(), disabled = disabled} + opts.args[key].set = function(info, val) Addon:SetOption(val, unpack(keys)) end + opts.args[key].get = function(info) return Addon:GetOption(unpack(keys)) end + return opts.args[key] end - function GUI:CreateHeader(name) - local option = self:CreateEntry(self:Order(), name, nil, "header", nil, self:Order(0)) + function GUI:CreateHeader(opts, name) + local option = self:CreateEntry(opts, self:Order(), name, nil, "header", nil, self:Order(0)) end - function GUI:CreateDescription(desc, fontSize) - local option = self:CreateEntry(self:Order(), desc, nil, "description", nil, self:Order(0)) + function GUI:CreateDescription(opts, desc, fontSize) + local option = self:CreateEntry(opts, self:Order(), desc, nil, "description", nil, self:Order(0)) option.fontSize = fontSize or "large" + return option end - function GUI:CreateDivider(count) - for i = 1, count or 3 do - self:CreateDescription("", "small") + function GUI:CreateDivider(opts, count, fontSize) + for i = 1, count or 1 do + self:CreateDescription(opts, " ", fontSize or "small") end end - function GUI:CreateNewline() - return self:CreateDivider(1) + function GUI:CreateNewline(opts) + return self:CreateDivider(opts, 1) + end + + function GUI:CreateToggle(opts, keys, name, desc, disabled) + local option = self:CreateEntry(opts, keys, name, desc, "toggle", disabled) + return option + end + + function GUI:CreateSelect(opts, keys, name, desc, values, sorting, disabled) + local option = self:CreateEntry(opts, keys, name, desc, "select", disabled) + option.values = values + option.sorting = sorting + option.style = "dropdown" + return option end - function GUI:CreateToggle(keys, name, desc, disabled) - local option = self:CreateEntry(keys, name, desc, "toggle", disabled) + function GUI:CreateMultiSelect(opts, keys, name, desc, values, disabled) + local option = self:CreateEntry(opts, keys, name, desc, "multiselect", disabled) + option.values = values return option end - function GUI:CreateRange(keys, name, desc, min, max, step, disabled) - local option = self:CreateEntry(keys, name, desc, "range", disabled) + function GUI:CreateRange(opts, keys, name, desc, min, max, step, disabled) + local option = self:CreateEntry(opts, keys, name, desc, "range", disabled) option.min = min option.max = max option.step = step return option end - function GUI:CreateInput(keys, name, desc, multiline, disabled) - local option = self:CreateEntry(keys, name, desc, "input", disabled) + function GUI:CreateInput(opts, keys, name, desc, multiline, disabled) + local option = self:CreateEntry(opts, keys, name, desc, "input", disabled) option.multiline = multiline return option end - function GUI:CreateColor(keys, name, desc, disabled) - local option = self:CreateEntry(keys, name, desc, "color", disabled) - option.set = function(info, r, g, b) Addon:SetOption(Data:DefontifyColor(r, g, b), unpack(keys)) end - option.get = function(info) return Data:FontifyColor(Addon:GetOption(unpack(keys))) end + function GUI:CreateColor(opts, keys, name, desc, disabled) + local option = self:CreateEntry(opts, keys, name, desc, "color", disabled) + option.set = function(info, r, g, b) Addon:SetOption(Addon:ConvertColorFromBlizzard(r, g, b), unpack(keys)) end + option.get = function(info) return Addon:ConvertColorToBlizzard(Addon:GetOption(unpack(keys))) end return option end - function GUI:CreateExecute(key, name, desc, func, disabled) - local option = self:CreateEntry(key, name, desc, "execute", disabled) + function GUI:CreateExecute(opts, key, name, desc, func, disabled) + local option = self:CreateEntry(opts, key, name, desc, "execute", disabled) option.func = func return option end - return GUI + function GUI:CreateGroup(opts, key, name, groupType, disabled) + key = "group_" .. key + opts.args[key] = {name = name, type = "group", childGroups = groupType, args = {}, order = self:Order(), disabled = disabled} + return opts.args[key] + end + + function GUI:CreateGroupTop(name, groupType, disabled) + return {name = name, type = "group", childGroups = groupType, args = {}, order = self:Order(), disabled = disabled} + end end -function Data:MakeOptionsTable(title, Addon, L) - local Options = { - name = title, - type = "group", - args = {} - } - local GUI = GetOptionTableHelpers(Options, Addon) - - - GUI:CreateToggle("SIMPLIFY", L["Reword tooltips"], L["REWORD TOOLTIPS DESCRIPTION"]) - GUI:CreateNewline() - GUI:CreateToggle("REORDER", L["Reorder stats"], L["REORDER STATS DESCRIPTION"]) - GUI:CreateNewline() - GUI:CreateToggle("RECOLOR", L["Recolor stats"], L["RECOLOR STATS DESCRIPTION"]) + +function Addon:ChangeOrder(from, to) + tinsert(self.statList[self.expac], to, tblRemove(self.statList[self.expac], from)) + self:SetOption(tblConcat(self.statList[self.expac], ","), "order", self.expac) + self:RegenerateStatOrder() +end +function Addon:ResetOrder() + self:ResetOption("order", self.expac) + self:RegenerateStatOrder() +end +function Addon:ResetReword(stat) + self:ResetOption("reword", stat) + self:SetDefaultRewordByLocale(stat) +end +function Addon:ResetMod(stat) + self:ResetOption("mod", stat) + self:SetDefaultModByLocale(stat) +end +function Addon:ResetPrecision(stat) + self:ResetOption("precision", stat) + self:SetDefaultPrecisionByLocale(stat) +end + +local function CreateCombineStatsOption(opts) + Addon.GUI:CreateToggle(opts, {"combineStats"}, L["Group Secondary Stats with Base Stats"]).width = 2 +end + + +-- ZeraTooltip options +function Addon:MakeOptionsTable() + local title = ADDON_NAME + self:CreateOptionsCategory(nil, function() + local GUI = self.GUI:ResetOrder() + local opts = GUI:CreateGroupTop(title, "tab") + do + local enabled = self:GetOption"enabled" + local invertMode = self:GetOption"invertMode" + + local group = GUI:CreateGroup(opts, 1, self.L["Enable"], "tab") + local opts = group + + GUI:CreateToggle(opts, {"enabled"}, self.L["Enabled"]) + GUI:CreateDivider(opts, 2) + + local text = enabled and self.L["Disable"] or self.L["Enable"] + GUI:CreateSelect(opts, {"invertMode"}, text, desc, {none = self.L["never"], any = self.L["any"], all = self.L["all"]}, {"none", "any", "all"}).width = 0.7 + GUI:CreateNewline(opts) + + local disabled = invertMode == "none" + GUI:CreateToggle(opts, {"modKeys", "shift"}, self.L["SHIFT key"], nil, disabled).width = 0.8 + GUI:CreateToggle(opts, {"modKeys", "ctrl"} , self.L["CTRL key"] , nil, disabled).width = 0.8 + GUI:CreateToggle(opts, {"modKeys", "alt"} , self.L["ALT key"] , nil, disabled).width = 0.8 + end + do + local group = GUI:CreateGroup(opts, 2, self.L["Features"], "tab") + local opts = group + + GUI:CreateToggle(opts, {"allow", "reorder"}, L["Reorder"]) + GUI:CreateNewline(opts) + GUI:CreateToggle(opts, {"allow", "reword"} , self.L["Rename"]) + GUI:CreateNewline(opts) + GUI:CreateToggle(opts, {"allow", "recolor"}, L["Recolor"]) + end - return Options + return opts + end) end +-- Stat options +local function GetDefaultStatText(number, stat) + local StatInfo = Addon.statsInfo[stat] + return Addon:MakeColorCode(StatInfo.tooltipColor, StatInfo:GetDefaultForm(number)) +end - -function Data:MakeSpeedbarOptionsTable(title, Addon, L) - local Options = { - name = title, - type = "group", - args = {} - } - local GUI = GetOptionTableHelpers(Options, Addon) +local function GetFormattedStatText(number, stat) + local StatInfo = Addon.statsInfo[stat] + local hidden = Addon:GetOption("hide", stat) + local text = StatInfo:GetDefaultForm(number) + if Addon:GetOption("allow", "reword") and Addon:GetOption("doReword", stat) then + text = StatInfo:ConvertToNormalForm(text) + text = strGsub(StatInfo:Reword(text, text), "%+(%-)", "%1") + end + local color = StatInfo.tooltipColor + if hidden then + color = Addon.COLORS.GRAY + elseif Addon:GetOption("allow", "recolor") and Addon:GetOption("doRecolor", stat) then + color = Addon:GetOption("color", stat) + end + return (hidden and "|T132320:0|t " or "") .. Addon:MakeColorCode(color, text) +end +local function GetFormattedText(stat, originalColor, defaultText, formattedText) + local changed + if formattedText ~= defaultText then + changed = true + end + local color = Addon:GetOption("color", stat) + if Addon:GetOption("hide", stat) then + formattedText = "|T132320:0|t " .. Addon:MakeColorCode(Addon.COLORS.GRAY, formattedText) + changed = true + elseif Addon:GetOption("allow", "recolor") and Addon:GetOption("doRecolor", stat) and color ~= originalColor then + formattedText = Addon:MakeColorCode(color, formattedText) + changed = true + else + formattedText = Addon:MakeColorCode(originalColor, formattedText) + end + return Addon:MakeColorCode(originalColor, defaultText), formattedText, changed +end +local function CreateTitle(opts, defaultText, formattedText, changed, gapHeight) + local self = Addon + local GUI = self.GUI + + GUI:CreateDescription(opts, self.L["Default"], "small") + GUI:CreateDescription(opts, defaultText) + GUI:CreateDivider(opts, 1) + if changed then + GUI:CreateDescription(opts, self.L["Current"], "small") + GUI:CreateDescription(opts, formattedText) + else + GUI:CreateDescription(opts, " ", "small") + GUI:CreateDescription(opts, " ") + end + GUI:CreateDivider(opts, gapHeight or 2) +end +local function CreateReset(opts, option, func) + local self = Addon + local GUI = self.GUI + + GUI:CreateExecute(opts, option, self.L["Reset"], nil, func or function() self:ResetOption(unpack(option)) end).width = 0.6 +end +local function CreateColor(opts, stat, toggleWidth, colorWidth) + local self = Addon + local GUI = self.GUI + + local disabled = not Addon:GetOption("allow", "recolor") + GUI:CreateToggle(opts, {"doRecolor", stat}, self.L["Color"], nil, disabled).width = toggleWidth or 0.5 + GUI:CreateColor(opts, {"color", stat}, self.L["Color"], nil, disabled or not Addon:GetOption("doRecolor", stat)).width = colorWidth + CreateReset(opts, {"color", stat}) + GUI:CreateDivider(opts, 1) +end +local function CreateHide(opts, stat, width) + local self = Addon + local GUI = self.GUI + + GUI:CreateToggle(opts, {"hide", stat}, self.L["Hide"]).width = width or 0.6 + CreateReset(opts, {"hide", stat}) +end +local sampleNumber = 10 +local function CreateStatOption(opts, i, stat) + local self = Addon + local GUI = self.GUI + + local defaultText = GetDefaultStatText(sampleNumber, stat) + local formattedText = GetFormattedStatText(sampleNumber, stat) + + local group = GUI:CreateGroup(opts, stat, formattedText) + local opts = group + + CreateTitle(opts, defaultText, formattedText, defaultText ~= formattedText, 1) + + -- Test + local option = GUI:CreateRange(opts, {"sampleNumber"}, L["Test"], nil, -1000000, 1000000, 1) + option.softMin = 0 + option.softMax = 100 + option.set = function(info, val) sampleNumber = val end + option.get = function(info) return sampleNumber end + GUI:CreateDivider(opts, 1) - GUI:CreateToggle("SHOW_SPEEDBAR", L["Show Speedbar"], L["SHOW SPEEDBAR DESCRIPTION"]) - GUI:CreateNewline() + -- Move Up/Down + local disabled = not Addon:GetOption("allow", "reorder") + local option = GUI:CreateExecute(opts, {"order", stat, "up"}, self.L["Move Up"], nil, function() self:ChangeOrder(i, i-1) end, disabled or i == 1) + local option = GUI:CreateExecute(opts, {"order", stat, "wayUp"}, self.L["Move to Top"], nil, function() self:ChangeOrder(i, 1) end, disabled or i == 1) + GUI:CreateNewline(opts) + local option = GUI:CreateExecute(opts, {"order", stat, "down"}, self.L["Move Down"], nil, function() self:ChangeOrder(i, i+1) end, disabled or i == #self.statList[self.expac]) + local option = GUI:CreateExecute(opts, {"order", stat, "wayDown"}, self.L["Move to Bottom"], nil, function() self:ChangeOrder(i, #self.statList[self.expac]) end, disabled or i == #self.statList[self.expac]) + GUI:CreateDivider(opts, 2) - GUI:CreateRange("SPEEDBAR_SIZE", L["Speedbar width"], L["SPEEDBAR SIZE DESCRIPTION"], 5, 25, 1) - GUI:CreateExecute("SPEEDBAR_SIZE Reset", L["Reset"], nil, function() Addon:ResetOption"SPEEDBAR_SIZE" end) + CreateColor(opts, stat, 0.6) - GUI:CreateNewline() + -- Reword + local disabled = not Addon:GetOption("allow", "reword") + GUI:CreateToggle(opts, {"doReword", stat}, self.L["Rename"], nil, disabled).width = 0.6 + local disabled = disabled or not self:GetOption("doReword", stat) + local option = GUI:CreateInput(opts, {"reword", stat}, self.L["Custom"], nil, nil, disabled) + option.set = function(info, val) self:SetOption(self:CoverSpecialCharacters(val), "reword", stat) end + option.get = function(info) return Addon:UncoverSpecialCharacters(self:GetOption("reword", stat)) end + CreateReset(opts, {"reword", stat}, function() self:ResetReword(stat) end) + GUI:CreateDivider(opts, 1) - GUI:CreateRange("SPEED_ACCURACY", L["Speed accuracy"], L["SPEED ACCURACY DESCRIPTION"], 1, 5, 1) - GUI:CreateExecute("SPEED_ACCURACY Reset", L["Reset"], nil, function() Addon:ResetOption"SPEED_ACCURACY" end) + -- Mod + local option = GUI:CreateRange(opts, {"mod", stat}, L["Modifier"], nil, 0, 1000, nil, disabled) + option.width = 1.6 + option.softMax = 12 + option.bigStep = 0.1 + option.isPercent = true + CreateReset(opts, {"mod", stat}, function() self:ResetMod(stat) end) + GUI:CreateRange(opts, {"precision", stat}, L["Precision"], nil, 0, 5, 1, disabled).width = 1.6 + CreateReset(opts, {"precision", stat}, function() self:ResetPrecision(stat) end) + GUI:CreateDivider(opts, 1) + CreateHide(opts, stat, 1.6) +end +function Addon:MakeStatsOptionsTable() + local title = self.L["Stats"] + self:CreateOptionsCategory(title, function() + + local GUI = self.GUI:ResetOrder() + local opts = GUI:CreateGroupTop(title) + + CreateCombineStatsOption(opts) + + if Addon:GetOption("allow", "reorder") then + for i, stat in ipairs(self.statList[self.expac]) do + CreateStatOption(opts, i, stat) + end + else + for stat in strGmatch(self:GetDefaultOption("order", self.expac), "[^,]+") do + CreateStatOption(opts, nil, stat) + end + end - return Options + return opts + end) end -function Data:MakeColorsOptionsTable(title, Addon, L) - local Options = { - name = title, - type = "group", - args = {} - } - local GUI = GetOptionTableHelpers(Options, Addon) +local sampleDamage = 20 +local sampleVariance = 0.5 +local sampleSpeed = 2.6 +-- Misc options +function Addon:MakeExtraStatsOptionsTable() + local title = self.L["Other Options"] + self:CreateOptionsCategory(title, function() + + local GUI = self.GUI:ResetOrder() + local opts = GUI:CreateGroupTop(title) + + -- Trainable + do + local stat = "Trainable" + + local defaultText = self.L["Weapon"] + local _, name = GetFormattedText(stat, self.COLORS.RED, L["Trainable Equipment"], L["Trainable Equipment"]) + local defaultText, formattedText, changed = GetFormattedText(stat, self.COLORS.RED, defaultText, defaultText) + + local group = GUI:CreateGroup(opts, stat, name) + local opts = group + + CreateTitle(opts, defaultText, formattedText, changed) + + -- Color + CreateColor(opts, stat, nil, 0.5) + end + + GUI:CreateGroup(opts, "afterTrainable" , " ").disabled = true + -- Weapon Damage + do + local stat = "Damage" + + local defaultText = format(DAMAGE_TEMPLATE, sampleDamage * (1-sampleVariance), sampleDamage * (1+sampleVariance)) + local defaultText, formattedText, changed = GetFormattedText(stat, self.COLORS.WHITE, defaultText, self:ModifyWeaponDamage(defaultText, sampleDamage, 1)) + + local group = GUI:CreateGroup(opts, stat, formattedText) + local opts = group + + CreateTitle(opts, defaultText, formattedText, changed) + + -- Test + local option = GUI:CreateRange(opts, {"sampleDamage"}, L["Test"], nil, 0, 1000000, 0.5) + option.softMax = 1000 + option.bigStep = 10 + option.set = function(info, val) sampleDamage = val end + option.get = function(info) return sampleDamage end + local option = GUI:CreateRange(opts, {"sampleVariance"}, L["Test"], nil, 0, 1, 0.1) + option.isPercent = true + option.set = function(info, val) sampleVariance = val end + option.get = function(info) return sampleVariance end + GUI:CreateDivider(opts, 1) + + -- Color + CreateColor(opts, stat) + + -- Reword + local disabled = not self:GetOption("allow", "reword") + GUI:CreateToggle(opts, {"damage", "showMinMax"} , L["Show Minimum and Maximum"], nil, disabled or not self:GetOption("damage", "showAverage")).width = 1.5 + CreateReset(opts, {"damage", "showMinMax"}) + GUI:CreateNewline(opts) + GUI:CreateToggle(opts, {"damage", "showAverage"} , L["Show Average"], nil, disabled or not self:GetOption("damage", "showMinMax")).width = 1.5 + CreateReset(opts, {"damage", "showAverage"}) + GUI:CreateNewline(opts) + GUI:CreateToggle(opts, {"damage", "showVariance"}, L["Show Variance"], nil, disabled).width = 1.5 + CreateReset(opts, {"damage", "showVariance"}) + GUI:CreateNewline(opts) + GUI:CreateInput(opts, {"damage", "variancePrefix"} , L["Variance Prefix"], nil, nil, disabled).width = 1.5 + CreateReset(opts, {"damage", "variancePrefix"}) + GUI:CreateDivider(opts, 1) + + CreateHide(opts, stat, 1.5) + end - local function CreateColorOption(key, name, desc) - GUI:CreateToggle({"RECOLOR_STAT", key}, name, desc) - GUI:CreateColor({"COLORS", key}, L["Color"], nil, function() return not not not Addon:GetOption("RECOLOR_STAT", key) end) - GUI:CreateExecute(key .. " Reset", L["Reset"], nil, function() Addon:ResetOption("RECOLOR_STAT", key) Addon:ResetOption("COLORS", key) end) - GUI:CreateNewline() + local speedString = strGsub(format("%.2f", sampleSpeed), "%.", DECIMAL_SEPERATOR) + local speedStringFull = SPEED .. " " .. speedString + -- Weapon Speed + do + local stat = "Speed" + + local defaultSpeedString = speedString + local defaultText = speedStringFull + local formattedTextOriginal = self:ModifyWeaponSpeed(defaultText, sampleSpeed, defaultSpeedString) + local defaultText, formattedText, changed = GetFormattedText(stat, self.COLORS.WHITE, defaultText, formattedTextOriginal) + local disabled + if self:GetOption("hide", "Damage") then + formattedText = "|T132320:0|t " .. formattedTextOriginal + changed = true + disabled = true + end + + local group = GUI:CreateGroup(opts, stat, " " .. (formattedText)) + group.disabled = disabled + local opts = group + + CreateTitle(opts, defaultText, formattedText, changed) + + -- Test + local option = GUI:CreateRange(opts, {"sampleSpeed"}, L["Test"], nil, self:GetDefaultOption("speedBar", "min"), self:GetDefaultOption("speedBar", "max"), 0.1) + option.set = function(info, val) sampleSpeed = val end + option.get = function(info) return sampleSpeed end + GUI:CreateDivider(opts, 1) + + -- Color + CreateColor(opts, stat, 0.6) + + -- Reword + local disabled = not self:GetOption("allow", "reword") + GUI:CreateToggle(opts, {"doReword", stat}, L["Prefix"], nil, disabled).width = 0.6 + local option = GUI:CreateInput(opts, {"reword", stat}, self.L["Rename"], nil, nil, disabled or not self:GetOption("doReword", stat)) + option.set = function(info, val) self:SetOption(self:CoverSpecialCharacters(val), "reword", stat) end + option.get = function(info) return Addon:UncoverSpecialCharacters(self:GetOption("reword", stat)) end + CreateReset(opts, {"reword", stat}, function() self:ResetReword(stat) end) + GUI:CreateDivider(opts, 1) + + GUI:CreateRange(opts, {"precision", stat}, L["Precision"], nil, 0, 5, 1, disabled).width = 1.6 + CreateReset(opts, {"precision", stat}, function() self:ResetOption("precision", stat) end) + GUI:CreateDivider(opts, 1) + + CreateHide(opts, stat, 1.6) end + GUI:CreateGroup(opts, "afterSpeed" , " ", nil, true) - GUI:CreateExecute("ResetColors", L["Reset Color Options"], nil, function() - Addon:ResetOption("RECOLOR_USABLE") - for _, option in ipairs{"RECOLOR_STAT", "COLORS"} do - for color in pairs(Addon:GetOption(option)) do - Addon:ResetOption(option, color) + -- Weapon dps + local sampleDPS = strGsub(format("%.1f", sampleDamage / sampleSpeed), "%.", DECIMAL_SEPERATOR) + do + local stat = "DamagePerSecond" + + local defaultText = format(DPS_TEMPLATE, sampleDPS) + local formattedText = Addon:ModifyWeaponDamagePerSecond(defaultText) + -- if self:GetOption("dps", "removeBrackets") then + -- formattedText = self:ChainGsub(formattedText, {"^%(", "%)$", ""}) + -- end + local defaultText, formattedText, changed = GetFormattedText(stat, self.COLORS.WHITE, defaultText, formattedText) + + if self:GetOption("dps", "removeBrackets") then + -- defaultText = self:ChainGsub(defaultText , {"^%(", "%)$", ""}) + formattedText = self:ChainGsub(formattedText, {"^%(", "%)$", ""}) + if defaultText ~= formattedText then + changed = true end end - end) + + local group = GUI:CreateGroup(opts, stat, formattedText) + local opts = group + + CreateTitle(opts, defaultText, formattedText, changed) + + -- Color + CreateColor(opts, stat, 0.6) + + -- Reword + local disabled = not self:GetOption("allow", "reword") + GUI:CreateToggle(opts, {"doReword", stat}, self.L["Rename"], nil, disabled).width = 0.6 + local option = GUI:CreateInput(opts, {"reword", stat}, self.L["Rename"], nil, nil, disabled or not self:GetOption("doReword", stat)) + option.set = function(info, val) self:SetOption(self:CoverSpecialCharacters(val), "reword", stat) end + option.get = function(info) return Addon:UncoverSpecialCharacters(self:GetOption("reword", stat)) end + CreateReset(opts, {"reword", stat}, function() self:ResetReword(stat) end) + GUI:CreateNewline(opts) + GUI:CreateToggle(opts, {"dps", "removeBrackets"}, L["Remove Brackets"], nil, disabled).width = 1.6 + CreateReset(opts, {"dps", "removeBrackets"}) + GUI:CreateDivider(opts, 1) + + CreateHide(opts, stat, 1.6) + end + + -- Weapon Speedbar + do + local stat = "Speedbar" + + local defaultSpeed = sampleSpeed + local defaultText = self:ModifyWeaponSpeedbar(defaultSpeed, speedString, speedStringFull) or "" + local formattedTextOriginal = defaultText == "" and L["Speed Bar"] or defaultText + local defaultText, formattedText, changed = GetFormattedText(stat, self.COLORS.WHITE, formattedTextOriginal, formattedTextOriginal) + local name, disabled + if self:GetOption("hide", "DamagePerSecond") then + name = "|T132320:0|t " .. self:MakeColorCode(self.COLORS.GRAY, defaultText == "" and L["Speed Bar"] or formattedText) + disabled = true + end + + local group = GUI:CreateGroup(opts, stat, " " .. (name or formattedText)) + group.disabled = disabled + local opts = group + + GUI:CreateDescription(opts, tostring(defaultSpeed), "small") + GUI:CreateDescription(opts, formattedText) + GUI:CreateDivider(opts, 1) + + -- Test + local option = GUI:CreateRange(opts, {"sampleSpeed"}, L["Test"], nil, self:GetDefaultOption("speedBar", "min"), self:GetDefaultOption("speedBar", "max"), 0.1) + option.set = function(info, val) sampleSpeed = val end + option.get = function(info) return sampleSpeed end + GUI:CreateDivider(opts, 1) + + -- Color + CreateColor(opts, stat, nil, 0.5) + + -- Reword + local disabled = not self:GetOption("allow", "reword") + GUI:CreateToggle(opts, {"speedBar", "speedPrefix"}, L["Show Speed"], nil, disabled) + CreateReset(opts, {"speedBar", "speedPrefix"}) + GUI:CreateNewline(opts) + local option = GUI:CreateInput(opts, {"speedBar", "fillChar"} , L["Fill Character"], nil, nil, disabled) + CreateReset(opts, {"speedBar", "fillChar"}) + GUI:CreateNewline(opts) + local option = GUI:CreateInput(opts, {"speedBar", "blankChar"}, L["Blank Character"], nil, nil, disabled) + CreateReset(opts, {"speedBar", "blankChar"}) + GUI:CreateDivider(opts, 1) + + + local option = GUI:CreateRange(opts, {"speedBar", "min"}, self.L["Minimum"], nil, self:GetDefaultOption("speedBar", "min"), self:GetDefaultOption("speedBar", "max"), 0.1, disabled) + option.set = function(info, val) self:SetOption(val, "speedBar", "min") self:SetOption(mathMax(val, self:GetOption("speedBar", "max")), "speedBar", "max") end + local option = GUI:CreateRange(opts, {"speedBar", "max"}, self.L["Maximum"], nil, self:GetDefaultOption("speedBar", "min"), self:GetDefaultOption("speedBar", "max"), 0.1, disabled) + option.set = function(info, val) self:SetOption(val, "speedBar", "max") self:SetOption(mathMin(val, self:GetOption("speedBar", "min")), "speedBar", "min") end + GUI:CreateNewline(opts) + GUI:CreateRange(opts, {"speedBar", "size"}, self.L["Frame Width"], nil, 0, 30, 1, disabled) + CreateReset(opts, {"speedBar", "size"}, func) + GUI:CreateDivider(opts, 1) + + CreateHide(opts, stat, 1) + end + + GUI:CreateGroup(opts, "afterSpeedbar" , " ", nil, true) + + -- Enchant + do + local stat = "Enchant" + + local defaultText = ENSCRIBE + local defaultText, formattedText, changed = GetFormattedText(stat, self.COLORS.GREEN, defaultText, self:ModifyEnchantment(defaultText)) + + local group = GUI:CreateGroup(opts, stat, formattedText) + local opts = group + + CreateTitle(opts, defaultText, formattedText, changed) + + -- Color + CreateColor(opts, stat, 0.6) + + -- Reword + local disabled = not self:GetOption("allow", "reword") + GUI:CreateToggle(opts, {"doReword", stat}, self.L["Rename"], nil, disabled).width = 0.6 + local option = GUI:CreateInput(opts, {"reword", stat}, self.L["Rename"], nil, nil, disabled or not self:GetOption("doReword", stat)) + option.set = function(info, val) self:SetOption(self:CoverSpecialCharacters(val), "reword", stat) end + option.get = function(info) return Addon:UncoverSpecialCharacters(self:GetOption("reword", stat)) end + CreateReset(opts, {"reword", stat}, function() self:ResetReword(stat) end) + GUI:CreateDivider(opts, 1) + + -- Icon + local disabled = not self:GetOption("allow", "reword") + GUI:CreateToggle(opts, {"doIcon", stat}, self.L["Icon"], nil, disabled).width = 0.6 + GUI:CreateSelect(opts, {"icon", stat}, self.L["Choose an Icon:"], desc, iconsDropdown, icons, disabled) + CreateReset(opts, {"icon", stat}, function() self:ResetOption("icon", stat) end) + GUI:CreateDivider(opts, 1) + + -- Icon Space + local disabled = disabled or not self:GetOption("doIcon", stat) + GUI:CreateToggle(opts, {"iconSpace", stat}, L["Icon Space"], nil, disabled).width = 1.6 + CreateReset(opts, {"iconSpace", stat}, function() self:ResetOption("iconSpace", stat) end) + GUI:CreateDivider(opts, 1) + + CreateHide(opts, stat, 1.6) + end + + GUI:CreateGroup(opts, "afterEnchant" , " ", nil, true) + + -- Races + do + local stat = "RequiredRaces" + + local defaultText = format(ITEM_RACES_ALLOWED, Addon.MY_RACE_NAME) + local formattedText = defaultText + local changed + if self:GetOption("hide", stat) then + formattedText = "|T132320:0|t " .. self:MakeColorCode(self.COLORS.GRAY, formattedText) + changed = true + else + formattedText = self:MakeColorCode(self.COLORS.WHITE, formattedText) + end + + local sampleText = self.uselessRaceStrings[1] + if self:GetOption("hide", stat) or self:GetOption("hide", "uselessRaces") then + sampleText = "|T132320:0|t " .. self:MakeColorCode(self.COLORS.GRAY, sampleText) + else + self:MakeColorCode(self.COLORS.WHITE, sampleText) + end + + local group = GUI:CreateGroup(opts, stat, formattedText) + local opts = group + + CreateTitle(opts, defaultText, formattedText, changed) + GUI:CreateDescription(opts, L["Test"], "small") + GUI:CreateDescription(opts, sampleText) + GUI:CreateDivider(opts, 2) + + -- Reword + GUI:CreateToggle(opts, {"hide", "uselessRaces"}, L["Hide Pointless Lines"]).width = 1 + CreateReset(opts, {"hide", "uselessRaces"}) + GUI:CreateDivider(opts, 1) + + CreateHide(opts, stat, 1) + end + + GUI:CreateGroup(opts, "afterRaces" , " ", nil, true) + + -- Prefixes + for _, data in ipairs{ + {"Equip", ITEM_SPELL_TRIGGER_ONEQUIP}, + {"Use", ITEM_SPELL_TRIGGER_ONUSE}, + -- {"ChanceOnHit", ITEM_SPELL_TRIGGER_ONPROC}, + } do + local stat = data[1] + local prefix = data[2] + + local defaultText = format("%s %s", prefix, format(ITEM_RESIST_ALL, strByte"+", sampleNumber)) + local defaultText, formattedText, changed = GetFormattedText(stat, self.COLORS.GREEN, defaultText, self:ModifyPrefix(defaultText, prefix)) + + local group = GUI:CreateGroup(opts, stat, formattedText) + local opts = group + + CreateTitle(opts, defaultText, formattedText, changed) + + -- Color + CreateColor(opts, stat, 0.6) + + -- Reword + local disabled = not self:GetOption("allow", "reword") + GUI:CreateToggle(opts, {"doReword", stat}, self.L["Rename"], nil, disabled).width = 0.6 + local option = GUI:CreateInput(opts, {"reword", stat}, self.L["Rename"], nil, nil, disabled or not self:GetOption("doReword", stat)) + option.set = function(info, val) self:SetOption(self:CoverSpecialCharacters(val), "reword", stat) end + option.get = function(info) return Addon:UncoverSpecialCharacters(self:GetOption("reword", stat)) end + CreateReset(opts, {"reword", stat}, function() self:ResetReword(stat) end) + GUI:CreateDivider(opts, 1) + + -- Trim Space + local disabled = disabled or not self:GetOption("doReword", stat) + GUI:CreateToggle(opts, {"trimSpace", stat}, L["Remove Space"], nil, disabled).width = 1.6 + CreateReset(opts, {"trimSpace", stat}, function() self:ResetOption("trimSpace", stat) end) + GUI:CreateDivider(opts, 1) + + -- Icon + local disabled = not self:GetOption("allow", "reword") + GUI:CreateToggle(opts, {"doIcon", stat}, self.L["Icon"], nil, disabled).width = 0.6 + GUI:CreateSelect(opts, {"icon", stat}, self.L["Choose an Icon:"], desc, iconsDropdown, icons, disabled) + CreateReset(opts, {"icon", stat}, function() self:ResetOption("icon", stat) end) + GUI:CreateDivider(opts, 1) + + -- Icon Space + local disabled = disabled or not self:GetOption("doIcon", stat) + GUI:CreateToggle(opts, {"iconSpace", stat}, L["Icon Space"], nil, disabled).width = 1.6 + CreateReset(opts, {"iconSpace", stat}, function() self:ResetOption("iconSpace", stat) end) + GUI:CreateDivider(opts, 1) + + CreateHide(opts, stat, 1.6) + end + + GUI:CreateGroup(opts, "afterPrefixes" , " ", nil, true) + + -- Socket Hint + do + local stat = "SocketHint" + + local defaultText = ITEM_SOCKETABLE + local defaultText, formattedText, changed = GetFormattedText(stat, self.COLORS.GREEN, defaultText, self:RewordSocketHint(defaultText)) + + local group = GUI:CreateGroup(opts, stat, formattedText) + local opts = group + + CreateTitle(opts, defaultText, formattedText, changed) + + -- Color + CreateColor(opts, stat, 0.6) + + -- Reword + local disabled = not self:GetOption("allow", "reword") + GUI:CreateToggle(opts, {"doReword", stat}, self.L["Rename"], nil, disabled).width = 0.6 + local option = GUI:CreateInput(opts, {"reword", stat}, self.L["Rename"], nil, nil, not self:GetOption("doReword", stat)) + option.set = function(info, val) self:SetOption(self:CoverSpecialCharacters(val), "reword", stat) end + option.get = function(info) return Addon:UncoverSpecialCharacters(self:GetOption("reword", stat)) end + CreateReset(opts, {"reword", stat}, function() self:ResetReword(stat) end) + GUI:CreateDivider(opts, 1) + + CreateHide(opts, stat, 1.6) + end + + GUI:CreateGroup(opts, "afterSocketHint" , " ", nil, true) + + -- Misc locale rewording + do + local stat = "Miscellaneous" + local name = Addon:MakeColorCode(self.COLORS.WHITE, self.L["Miscellaneous"]) + + local group = GUI:CreateGroup(opts, stat, name) + local opts = group + + -- Reword + local disabled = not self:GetOption("allow", "reword") + GUI:CreateToggle(opts, {"doReword", stat}, self.L["Rename"], nil, disabled).width = 0.6 + CreateReset(opts, {"doReword", stat}) + end - GUI:CreateDivider() - - GUI:CreateDescription("Miscellaneous") - GUI:CreateToggle("RECOLOR_USABLE", L["Recolor Usable Effects"], L["Recolor Usable Effects DESCRIPTION"]) - - GUI:CreateNewline() - CreateColorOption("TRAINABLE" , L["Trainable Equipment"], L["Trainable Equipment DESCRIPTION"]) - CreateColorOption("WEAP_DAMAGE", L["Weapon Damage"] , L["Weapon Damage DESCRIPTION"]) - CreateColorOption("SPEED" , L["Weapon Speed"] , L["Weapon Speed DESCRIPTION"]) - CreateColorOption("ENCHANT" , L["Enchantment"] , L["Enchantment DESCRIPTION"]) - CreateColorOption("SKILL" , L["Skill"] , L["Skill DESCRIPTION"]) - - GUI:CreateDivider() - - GUI:CreateDescription("Base Stats") - CreateColorOption("ARMOR" , L["Armor"]) - CreateColorOption("STAMINA" , L["Stamina"]) - CreateColorOption("STRENGTH" , L["Strength"]) - CreateColorOption("AGILITY" , L["Agility"]) - CreateColorOption("INTELLECT", L["Intellect"]) - CreateColorOption("SPIRIT" , L["Spirit"]) - - GUI:CreateDivider() - - GUI:CreateDescription("Elemental Resistances") - CreateColorOption("ARCANE_RESIST", L["Arcane Resist"]) - CreateColorOption("FIRE_RESIST" , L["Fire Resist"]) - CreateColorOption("NATURE_RESIST", L["Nature Resist"]) - CreateColorOption("FROST_RESIST" , L["Frost Resist"]) - CreateColorOption("SHADOW_RESIST", L["Shadow Resist"]) - CreateColorOption("HOLY_RESIST" , L["Holy Resist"]) - CreateColorOption("RESIST_ALL" , L["Resist All"]) - - GUI:CreateDivider() - - GUI:CreateDescription("Elemental Damage") - CreateColorOption("ARCANE_DAMAGE", L["Arcane Damage"]) - CreateColorOption("FIRE_DAMAGE" , L["Fire Damage"]) - CreateColorOption("NATURE_DAMAGE", L["Nature Damage"]) - CreateColorOption("FROST_DAMAGE" , L["Frost Damage"]) - CreateColorOption("SHADOW_DAMAGE", L["Shadow Damage"]) - CreateColorOption("HOLY_DAMAGE" , L["Holy Damage"]) - - GUI:CreateDivider() - - GUI:CreateDescription("Defensive") - CreateColorOption("DEFENSE", L["Defense"]) - if Data:IsBCC() then - CreateColorOption("RESILIENCE", L["Resilience"]) - end - CreateColorOption("DODGE" , L["Dodge"]) - CreateColorOption("PARRY" , L["Parry"]) - CreateColorOption("BLOCK_RATING", L["Block Rating"]) - CreateColorOption("BLOCK_VALUE" , L["Block Value"]) - - GUI:CreateDivider() - - GUI:CreateDescription("Physical") - CreateColorOption("ATTACK_POW" , L["Attack Power"]) - CreateColorOption("R_ATTACK_POW", L["Ranged Attack Power"]) - CreateColorOption("PHYS_HIT" , L["Physical Hit"]) - CreateColorOption("PHYS_CRIT" , L["Physical Crit"]) - if Data:IsBCC() then - CreateColorOption("PHYS_HASTE", L["Physical Haste"]) - CreateColorOption("PHYS_PEN" , L["Armor Pen"]) - CreateColorOption("EXPERTISE" , L["Expertise"]) - end - - GUI:CreateDivider() - - GUI:CreateDescription("Magical") - CreateColorOption("MAGICAL", L["Spell Damage"]) - CreateColorOption("MAGIC_HIT" , L["Spell Hit"]) - CreateColorOption("MAGIC_CRIT" , L["Spell Crit"]) - if Data:IsBCC() then - CreateColorOption("MAGIC_HASTE", L["Spell Haste"]) - CreateColorOption("MAGIC_PEN" , L["Spell Pen"]) - end - - GUI:CreateDivider() - - GUI:CreateDescription("Healing") - CreateColorOption("HEALING", L["Healing"]) - CreateColorOption("HEALTH" , L["Health"]) - CreateColorOption("MANA" , L["Mana"]) - - return Options + return opts + end) end -function Data:MakeDebugOptionsTable(title, Addon, L) - local Options = { - name = title, - type = "group", - args = {} - } - local GUI = GetOptionTableHelpers(Options, Addon) +-- Padding options +local function CreateGroupGap(opts, name, disabled) + if disabled then return end + local self = Addon + local GUI = self.GUI + + GUI:CreateGroup(opts, name, " ", nil, true) +end +local function CreatePaddingOption(opts, name, beforeStat, afterStat, sample, disabled) + local self = Addon + local GUI = self.GUI + + local group = GUI:CreateGroup(opts, name, name, nil, disabled) + local opts = group + + if beforeStat then + GUI:CreateToggle(opts, beforeStat, L["Space Above"], nil, disabled) + else -- only happens at the end + return GUI:CreateToggle(opts, afterStat, L["Space Below"], nil, disabled) + end + + GUI:CreateNewline(opts) + if sample then + GUI:CreateDescription(opts, sample) + else + GUI:CreateDescription(opts, " ") + end - GUI:CreateToggle({"Debug", "enabled"} , "Enabled") - GUI:CreateNewline() - GUI:CreateToggle({"Debug", "showLabels"} , "Show Labels") - GUI:CreateNewline() - GUI:CreateToggle({"Debug", "ctrlSuppression"}, "CTRL Suppression") + if afterStat then + GUI:CreateNewline(opts) + GUI:CreateToggle(opts, afterStat, L["Space Below"], nil, disabled) + end +end +local function CreateStandardPaddingMenu(opts, name, beforeStat, afterStat, sample, disabled, paddedAfterPrevious) + local self = Addon - return Options + if beforeStat and self:GetOption(unpack(beforeStat)) and not paddedAfterPrevious then CreateGroupGap(opts, "before" .. name) end + CreatePaddingOption(opts, name, beforeStat, afterStat, sample) + paddedAfterPrevious = self:GetOption(unpack(afterStat)) + if paddedAfterPrevious then CreateGroupGap(opts, "after" .. name) end + return paddedAfterPrevious +end +function Addon:MakePaddingOptionsTable() + local title = L["Spacing"] + self:CreateOptionsCategory(title, function() + + local GUI = self.GUI:ResetOrder() + local opts = GUI:CreateGroupTop(title) + + CreateCombineStatsOption(opts) + Addon.GUI:CreateToggle(opts, {"pad", "before", "BonusEffect"}, L["Space Above Bonus Effects"]).width = 2 + + local paddedAfterPrevious = false + local combineStats = self:GetOption"combineStats" + + -- base stats + local name, beforeStat, afterStat, sample = self.L["Base Stats"], {"pad", "before", "BaseStat"}, {"pad", "after", "BaseStat"}, format(ITEM_MOD_STAMINA, strByte"+", 10) + if beforeStat and self:GetOption(unpack(beforeStat)) and not paddedAfterPrevious then CreateGroupGap(opts, "before" .. name) end + CreatePaddingOption(opts, name, beforeStat, afterStat, sample) + if combineStats then + -- secondary stats + local name, beforeStat, afterStat, sample = L["Secondary Stats"], {"pad", "before", "SecondaryStat"}, {"pad", "after", "SecondaryStat"}, ITEM_SPELL_TRIGGER_ONEQUIP .. " " .. format(ITEM_MOD_MANA_REGENERATION, "10") + CreatePaddingOption(opts, name, beforeStat, afterStat, sample, true) + end + paddedAfterPrevious = self:GetOption(unpack(afterStat)) + if paddedAfterPrevious then CreateGroupGap(opts, "after" .. name) end + + -- enchant + local name, beforeStat, afterStat, sample = self.L["Enchant"], {"pad", "before", "Enchant"}, {"pad", "after", "Enchant"}, format(ENCHANTED_TOOLTIP_LINE, ENSCRIBE) + paddedAfterPrevious = CreateStandardPaddingMenu(opts, name, beforeStat, afterStat, sample, true, paddedAfterPrevious) + + -- sockets + local name, beforeStat, afterStat, sample = L["Sockets"], {"pad", "before", "Socket"}, {"pad", "after", "SocketBonus"} + paddedAfterPrevious = CreateStandardPaddingMenu(opts, name, beforeStat, afterStat, sample, true, paddedAfterPrevious) + + if not combineStats then + -- secondary stats + local name, beforeStat, afterStat, sample = L["Secondary Stats"], {"pad", "before", "SecondaryStat"}, {"pad", "after", "SecondaryStat"}, ITEM_SPELL_TRIGGER_ONEQUIP .. " " .. format(ITEM_MOD_MANA_REGENERATION, "10") + paddedAfterPrevious = CreateStandardPaddingMenu(opts, name, beforeStat, afterStat, sample, true, paddedAfterPrevious) + end + + -- set list + local name, beforeStat, afterStat, sample = L["Set List"], {"pad", "before", "SetName"}, {"pad", "after", "SetPiece"} + paddedAfterPrevious = CreateStandardPaddingMenu(opts, name, beforeStat, afterStat, sample, true, paddedAfterPrevious) + + -- set bonus + local name, beforeStat, afterStat, sample = L["Set List"], {"pad", "before", "SetBonus"}, {"pad", "after", "SetBonus"}, format(ITEM_SET_BONUS, format(ITEM_MOD_MANA_REGENERATION, "10")) + paddedAfterPrevious = CreateStandardPaddingMenu(opts, name, beforeStat, afterStat, sample, true, paddedAfterPrevious) + + -- end + local name, beforeStat, afterStat, sample = self.L["End"], nil, {"padLastLine"} + paddedAfterPrevious = CreateStandardPaddingMenu(opts, name, beforeStat, afterStat, sample, true, paddedAfterPrevious) + + + GUI:CreateGroup(opts, "-", "------------------", nil, true) + + return opts + end) end - - - +-- Reset Options +function Addon:MakeResetOptionsTable() + local title = self.L["Reset"] + self:CreateOptionsCategory(title, function() + + local GUI = self.GUI:ResetOrder() + local opts = GUI:CreateGroupTop(title) + + GUI:CreateDivider(opts, 2) + + for _, v in ipairs{ + {self.L["All"] , function() self:ResetProfile() end}, + {L["Order"] , function() self:ResetOrder() end}, + {self.L["Color"] , function() self:ResetOption"color" end}, + {self.L["Rename"] , function() self:ResetReword() end}, + {L["Mod"] , function() self:ResetMod() end}, + {L["Precision"] , function() self:ResetPrecision() end}, + {self.L["Hide"] , function() self:ResetOption"hide" end}, + {L["Spacing"] , function() self:ResetOption"pad" end}, + } do + local cat, func = unpack(v, 1, 2) + GUI:CreateDescription(opts, cat) + CreateReset(opts, {cat}, func) + GUI:CreateNewline(opts) + end + + return opts + end) +end diff --git a/Init.lua b/Init.lua new file mode 100644 index 0000000..7b41cf7 --- /dev/null +++ b/Init.lua @@ -0,0 +1,736 @@ + + +local ADDON_NAME, Data = ... + + + + +local Addon = LibStub("AceAddon-3.0"):NewAddon(ADDON_NAME, "AceConsole-3.0", "AceEvent-3.0", "AceHook-3.0") +Addon.onSetHandlers = {} + +-- Curseforge automatic packaging will comment this out +-- https://support.curseforge.com/en/support/solutions/articles/9000197281-automatic-packaging +--@debug@ + Addon.debug = true + + -- GAME_LOCALE = "enUS" -- AceLocale override + + -- TOOLTIP_UPDATE_TIME = 10000 + + -- DECIMAL_SEPERATOR = "," +--@end-debug@ +function Addon:Debug(...) + if self.debug then + self:Print(...) + end +end +function Addon:Debugf(...) + if self.debug then + self:Printf(...) + end +end + + +Addon.AceConfig = LibStub"AceConfig-3.0" +Addon.AceConfig = LibStub"AceConfig-3.0" +Addon.AceConfigDialog = LibStub"AceConfigDialog-3.0" +Addon.AceConfigRegistry = LibStub"AceConfigRegistry-3.0" +Addon.AceDB = LibStub"AceDB-3.0" +Addon.AceDBOptions = LibStub"AceDBOptions-3.0" + +Addon.TipHooker = LibStub"LibTipHooker-1.1-ZeraTooltip" +Addon.TipHooker2 = LibStub"LibTipHooker-1.0-ZeraTooltip" +Addon.SemVer = LibStub"SemVer" + + + +local buildMajor = tonumber(GetBuildInfo():match"^(%d+)%.") +if buildMajor >= 9 then + Addon.expac = "retail" +elseif buildMajor >= 3 then + Addon.expac = "wrath" +elseif buildMajor == 2 then + Addon.expac = "tbc" +elseif buildMajor == 1 then + Addon.expac = "classic" +end +Addon.isRetail = Addon.expac == "retail" +Addon.isWrath = Addon.expac == "wrath" +Addon.isTBC = Addon.expac == "tbc" +Addon.isClassic = Addon.expac == "classic" + + + + +local strLower = string.lower +local strFind = string.find +local strMatch = string.match +local strSub = string.sub +local strGsub = string.gsub +local strGmatch = string.gmatch +local strByte = string.byte + +local mathMin = math.min +local mathMax = math.max +local mathFloor = math.floor + +local tinsert = table.insert +local tblRemove = table.remove +local tblConcat = table.concat + + +local function strRemove(text, ...) + for _, pattern in ipairs{...} do + text = strGsub(text, pattern, "") + end + return text +end + +function Addon:StripText(text) + return strRemove(text, "|c%x%x%x%x%x%x%x%x", "|r", "^ +", " +$") +end + +function Addon:ChainGsub(text, ...) + for _, patterns in ipairs{...} do + local newText = tblRemove(patterns) + for _, oldText in ipairs(patterns) do + text = strGsub(text, oldText, newText) + end + end + return text +end + +local reversedPatternsCache = {} +function Addon:ReversePattern(text) + if not reversedPatternsCache[text] then + reversedPatternsCache[text] = "^" .. self:ChainGsub(text, {"%%%d%$", "%%"}, {"[+-]", "%%%1"}, {"[%(%)%.]", "%%%0"}, {"%%c", "([+-])"}, {"%%d", "(%%d+)"}, {"%%s", "(.*)"}, {"|4[^:]-:[^:]-:[^:]-;", ".-"}, {"|4[^:]-:[^:]-;", ".-"}) .. "$" + end + return reversedPatternsCache[text] +end + + +function Addon:CoverSpecialCharacters(text) + -- TODO: handle UI escape sequences here? or bypass and handle elsewhere? + -- return self:ChainGsub(text, {"|3%-%d+%(%%s%)", "%%s"}, {"%p", "%%%0"}) + return self:ChainGsub(text, {"%p", "%%%0"}) +end +function Addon:UncoverSpecialCharacters(text) + return (strGsub(text, "%%(.)", "%1")) +end + + + + + + + + + + + + + + + + + + +local L = setmetatable({}, { + __index = function(self, key) + rawset(self, key, key) + if Addon.debug then + geterrorhandler()(ADDON_NAME..": Missing entry for '"..tostring(key).."'") + end + return key + end +}) +Addon.L = L + +L["Enable"] = ENABLE +L["Disable"] = DISABLE +L["Enabled"] = VIDEO_OPTIONS_ENABLED +-- L["Disabled"] = ADDON_DISABLED + +L["never"] = strLower(CALENDAR_REPEAT_NEVER) +L["any"] = strLower(SPELL_TARGET_TYPE1_DESC) +L["all"] = strLower(SPELL_TARGET_TYPE12_DESC) + +L["SHIFT key"] = SHIFT_KEY +L["CTRL key"] = CTRL_KEY +L["ALT key"] = ALT_KEY + +L["Features"] = FEATURES_LABEL + +L["Stats"] = PET_BATTLE_STATS_LABEL + +L["Default"] = DEFAULT +L["Current"] = REFORGE_CURRENT + +L["Move Up"] = TRACKER_SORT_MANUAL_UP +L["Move Down"] = TRACKER_SORT_MANUAL_DOWN +L["Move to Top"] = TRACKER_SORT_MANUAL_TOP +L["Move to Bottom"] = TRACKER_SORT_MANUAL_BOTTOM + +L["Color"] = COLOR +L["Reset"] = RESET +L["Custom"] = CUSTOM +L["Rename"] = PET_RENAME +L["Hide"] = HIDE + +L["Base Stats"] = PLAYERSTAT_BASE_STATS +L["Enchant"] = ENSCRIBE +L["End"] = KEY_END + +L["Other Options"] = UNIT_FRAME_DROPDOWN_SUBSECTION_TITLE_OTHER +L["Weapon"] = WEAPON +-- L["Weapon Damage"] = DAMAGE_TOOLTIP +-- L["Damage Per Second"] = ITEM_MOD_DAMAGE_PER_SECOND_SHORT +L["Miscellaneous"] = MISCELLANEOUS +-- missing? +-- L["Test"] = TEST_BUILD +L["Minimum"] = MINIMUM +L["Maximum"] = MAXIMUM +L["Frame Width"] = COMPACT_UNIT_FRAME_PROFILE_FRAMEWIDTH +L["Icon"] = EMBLEM_SYMBOL +L["Choose an Icon:"] = MACRO_POPUP_CHOOSE_ICON + +L["All"] = ALL + +L["ERROR"] = ERROR_CAPS + + + +Addon.prefixStats = { + [ITEM_SPELL_TRIGGER_ONEQUIP] = "Equip", + [ITEM_SPELL_TRIGGER_ONUSE] = "Use", + [ITEM_SPELL_TRIGGER_ONPROC] = "ChanceOnHit", +} + + + + + +function Addon:Round(num, nearest) + nearest = nearest or 1; + local lower = mathFloor(num / nearest) * nearest; + local upper = lower + nearest; + return (upper - num < num - lower) and upper or lower; +end + +function Addon:Clamp(min, num, max) + assert(type(min) == "number", "Can't clamp. min is " .. type(min)) + assert(type(max) == "number", "Can't clamp. max is " .. type(max)) + assert(min <= max, format("Can't clamp. min (%d) > max (%d)", min, max)) + return mathMin(mathMax(num, min), max) +end + + +function Addon:GetHexFromColor(r, g, b) + return format("%.2x%.2x%.2x", r, g, b) +end +function Addon:ConvertColorFromBlizzard(r, g, b) + return self:GetHexFromColor(Addon:Round(r*255, 1), Addon:Round(g*255, 1), Addon:Round(b*255, 1)) +end +function Addon:GetTextColorAsHex(frame) + return self:ConvertColorFromBlizzard(frame:GetTextColor()) +end + +function Addon:ConvertColorToBlizzard(hex) + return tonumber(strSub(hex, 1, 2), 16) / 255, tonumber(strSub(hex, 3, 4), 16) / 255, tonumber(strSub(hex, 5, 6), 16) / 255, 1 +end +function Addon:SetTextColorFromHex(frame, hex) + frame:SetTextColor(self:ConvertColorToBlizzard(hex)) +end + +function Addon:MakeColorCode(hex, text) + return format("|cff%s%s%s", hex, text or "", text and "|r" or "") +end + + +function Addon:Map(t, ValMap, KeyMap) + if type(KeyMap) == "table" then + local keyTbl = KeyMap + KeyMap = function(v, k, self) return keyTbl[k] end + end + if type(ValMap) == "table" then + local valTbl = KeyMap + ValMap = function(v, k, self) return valTbl[k] end + end + local new = {} + for k, v in next, t, nil do + local key, val = k, v + if KeyMap then + key = KeyMap(v, k, t) + end + if ValMap then + val = ValMap(v, k, t) + end + if key then + new[key] = val + end + end + local meta = getmetatable(t) + if meta then + setmetatable(new, meta) + end + return new +end + +function Addon:MakeLookupTable(t, val, keepOrigVals) + local ValFunc + if val ~= nil then + if type(val) == "function" then + ValFunc = val + else + ValFunc = function() return val end + end + end + local new = {} + for k, v in next, t, nil do + if ValFunc then + new[v] = ValFunc(v, k, t) + else + new[v] = k + end + if keepOrigVals and new[k] == nil then + new[k] = v + end + end + return new +end + + + +Addon.statList = { + classic = {}, + tbc = {}, + wrath = {}, +} +Addon.statsInfo = setmetatable({}, {__index = function() return {} end}) +Addon.statOrder = {} + + +Addon.defaultRewordLocaleOverrides = {} +Addon.defaultModLocaleOverrides = {} +Addon.defaultPrecisionLocaleOverrides = {} +Addon.localeExtras = {} + +function Addon:AddDefaultRewordByLocale(stat, val) + Addon.defaultRewordLocaleOverrides[stat] = val +end +function Addon:AddDefaultModByLocale(stat, val) + Addon.defaultModLocaleOverrides[stat] = val +end +function Addon:AddDefaultPrecisionByLocale(stat, val) + Addon.defaultPrecisionLocaleOverrides[stat] = val +end + +function Addon:AddExtraStatCapture(stat, ...) + if not Addon.localeExtras[stat] then + Addon.localeExtras[stat] = {} + end + for i, rule in ipairs{...} do + table.insert(Addon.localeExtras[stat], rule) + end +end + +local replacementKeys = {} +function Addon:AddExtraReplacement(label, ...) + if not replacementKeys[label] then + table.insert(Addon.localeExtras, {label = label}) + replacementKeys[label] = #Addon.localeExtras + end + for i, rule in ipairs{...} do + table.insert(Addon.localeExtras[replacementKeys[label]], rule) + end +end + + + +do + Addon.MY_RACE_NAME = UnitRace"player" + + -- Races: Human, Orc, Dwarf, Night Elf, Undead, Tauren, Gnome, Troll, Blood Elf, Draenei + local raceIDs = {} + raceIDs.classic = {1, 2, 3, 4, 5, 6, 7, 8} + raceIDs.tbc = {1, 2, 3, 4, 5, 6, 7, 8, 10, 11} + raceIDs.wrath = raceIDs.tbc + + Addon.raceNames = {} + + local allRaces = {} + local factionRaces = {Alliance = {}, Horde = {}} + + for _, raceID in ipairs(raceIDs[Addon.expac]) do + local raceName = C_CreatureInfo.GetRaceInfo(raceID).raceName + local factionTag = C_CreatureInfo.GetFactionInfo(raceID).groupTag + Addon.raceNames[raceID] = raceName + + tinsert(allRaces, raceName) + tinsert(factionRaces[factionTag], raceName) + end + Addon.uselessRaceStrings = {} + local sample = format(ITEM_RACES_ALLOWED, tblConcat(allRaces, ", ")) + Addon.uselessRaceStrings[1] = sample -- used as an example in config + Addon.uselessRaceStrings[sample] = true + Addon.uselessRaceStrings[format(ITEM_RACES_ALLOWED, tblConcat(factionRaces.Alliance, ", "))] = true + Addon.uselessRaceStrings[format(ITEM_RACES_ALLOWED, tblConcat(factionRaces.Horde, ", "))] = true +end + + + +do + Addon.MY_CLASS = select(2, UnitClassBase"player") + + -- WARRIOR, PALADIN, HUNTER, ROGUE, PRIEST, DEATHKNIGHT, SHAMAN, MAGE, WARLOCK, MONK, DRUID, DEMONHUNTER + local ID = {} + for i = 1, GetNumClasses() do + local classInfo = C_CreatureInfo.GetClassInfo(i) + if classInfo then + ID[classInfo.classFile] = classInfo.classID + end + end + + local weapon = Enum.ItemClass.Weapon + local subWeapon = Enum.ItemWeaponSubclass + local armor = Enum.ItemClass.Armor + local subArmor = Enum.ItemArmorSubclass + local usableTypes = Addon:MakeLookupTable({weapon, armor}, function() return {} end) + + usableTypes[weapon][subWeapon.Unarmed] = Addon:MakeLookupTable{ID.DRUID, ID.HUNTER, ID.ROGUE, ID.SHAMAN, ID.WARRIOR} -- Fist Weapons + usableTypes[weapon][subWeapon.Axe1H] = Addon:MakeLookupTable{ID.DEATHKNIGHT, ID.HUNTER, ID.PALADIN, ID.ROGUE, ID.SHAMAN, ID.WARRIOR} + usableTypes[weapon][subWeapon.Axe2H] = Addon:MakeLookupTable{ID.DEATHKNIGHT, ID.HUNTER, ID.PALADIN, ID.SHAMAN, ID.WARRIOR} + usableTypes[weapon][subWeapon.Bows] = Addon:MakeLookupTable{ID.HUNTER, ID.ROGUE, ID.WARRIOR} + usableTypes[weapon][subWeapon.Mace1H] = Addon:MakeLookupTable{ID.DEATHKNIGHT, ID.DRUID, ID.PALADIN, ID.PRIEST, ID.ROGUE, ID.SHAMAN, ID.WARRIOR} + usableTypes[weapon][subWeapon.Mace2H] = Addon:MakeLookupTable{ID.DEATHKNIGHT, ID.DRUID, ID.PALADIN, ID.SHAMAN, ID.WARRIOR} + usableTypes[weapon][subWeapon.Polearm] = Addon:MakeLookupTable{ID.DEATHKNIGHT, ID.DRUID, ID.HUNTER, ID.PALADIN, ID.WARRIOR} + usableTypes[weapon][subWeapon.Sword1H] = Addon:MakeLookupTable{ID.DEATHKNIGHT, ID.HUNTER, ID.MAGE, ID.PALADIN, ID.ROGUE, ID.WARLOCK, ID.WARRIOR} + usableTypes[weapon][subWeapon.Sword2H] = Addon:MakeLookupTable{ID.DEATHKNIGHT, ID.HUNTER, ID.PALADIN, ID.WARRIOR} + usableTypes[weapon][subWeapon.Staff] = Addon:MakeLookupTable{ID.DRUID, ID.HUNTER, ID.MAGE, ID.PRIEST, ID.SHAMAN, ID.WARLOCK, ID.WARRIOR} + usableTypes[weapon][subWeapon.Dagger] = Addon:MakeLookupTable{ID.DRUID, ID.HUNTER, ID.MAGE, ID.PRIEST, ID.ROGUE, ID.SHAMAN, ID.WARLOCK, ID.WARRIOR} + usableTypes[weapon][subWeapon.Guns] = Addon:MakeLookupTable{ID.HUNTER, ID.ROGUE, ID.WARRIOR} + usableTypes[weapon][subWeapon.Crossbow] = Addon:MakeLookupTable{ID.HUNTER, ID.ROGUE, ID.WARRIOR} + usableTypes[weapon][subWeapon.Thrown] = Addon:MakeLookupTable{ID.HUNTER, ID.ROGUE, ID.WARRIOR} + usableTypes[weapon][subWeapon.Wand] = Addon:MakeLookupTable{ID.MAGE, ID.PRIEST, ID.WARLOCK} + + usableTypes[armor][subArmor.Leather] = Addon:MakeLookupTable{ID.DEATHKNIGHT, ID.DRUID, ID.HUNTER, ID.PALADIN, ID.ROGUE, ID.SHAMAN, ID.WARRIOR} + usableTypes[armor][subArmor.Mail] = Addon:MakeLookupTable{ID.DEATHKNIGHT, ID.HUNTER, ID.PALADIN, ID.SHAMAN, ID.WARRIOR} + usableTypes[armor][subArmor.Plate] = Addon:MakeLookupTable{ID.DEATHKNIGHT, ID.PALADIN, ID.WARRIOR} + usableTypes[armor][subArmor.Shield] = Addon:MakeLookupTable{ID.PALADIN, ID.SHAMAN, ID.WARRIOR} + usableTypes[armor][subArmor.Libram] = Addon:MakeLookupTable{ID.PALADIN} + usableTypes[armor][subArmor.Idol] = Addon:MakeLookupTable{ID.DRUID} + usableTypes[armor][subArmor.Totem] = Addon:MakeLookupTable{ID.SHAMAN} + usableTypes[armor][subArmor.Sigil] = Addon:MakeLookupTable{ID.DEATHKNIGHT} + -- usableTypes[weapon][subWeapon.Warglaive] = Addon:MakeLookupTable{} + -- usableTypes[weapon][subWeapon.Bearclaw] = Addon:MakeLookupTable{} + -- usableTypes[weapon][subWeapon.Catclaw] = Addon:MakeLookupTable{} + -- usableTypes[weapon][subWeapon.Generic] = Addon:MakeLookupTable{} + -- usableTypes[weapon][subWeapon.Obsolete3] = Addon:MakeLookupTable{} -- Spears + -- usableTypes[weapon][subWeapon.Fishingpole] = Addon:MakeLookupTable{} + + -- usableTypes[armor][subArmor.Generic] = Addon:MakeLookupTable{} + -- usableTypes[armor][subArmor.Cloth] = Addon:MakeLookupTable{} + -- usableTypes[armor][subArmor.Cosmetic] = Addon:MakeLookupTable{} + -- usableTypes[armor][subArmor.Relic] = Addon:MakeLookupTable{} + + + local dualWielders = Addon:MakeLookupTable{ID.DEATHKNIGHT, ID.HUNTER, ID.ROGUE, ID.SHAMAN, ID.WARRIOR} + + local MY_CLASS = Addon.MY_CLASS + function Addon:IsItemUsable(itemID, classID) + local invType, _, itemClassID, subClassID = select(4, GetItemInfoInstant(itemID)) + if usableTypes[itemClassID] and usableTypes[itemClassID][subClassID] then + local class = classID or MY_CLASS + return usableTypes[itemClassID][subClassID][class] and (invType ~= "INVTYPE_WEAPONOFFHAND" or dualWielders[class]) and true or false + end + return true + end +end + + + + + +function Addon:RegenerateStatOrder() + wipe(self.statList[self.expac]) + wipe(self.statOrder) + for stat in strGmatch(self:GetOption("order", self.expac), "[^,]+") do + tinsert(self.statList[self.expac], stat) + self.statOrder[stat] = #self.statList[self.expac] + end +end + + + +local function rgb(r, g, b) + return Addon:GetHexFromColor(r, g, b) +end + + +-- https://colornamer.robertcooper.me/ +Addon.COLORS = { + WHITE = rgb(255, 255, 255), + GRAY = rgb(127, 127, 127), + RED = rgb(255, 32, 32), + ORANGE = rgb(255, 127, 32), + GREEN = rgb( 0, 255, 0), + BLUE = rgb( 0, 0, 255), + + ARCANE = rgb(255, 127, 255), + FIRE = rgb(255, 128, 0), + NATURE = rgb( 76, 255, 76), + FROST = rgb(127, 255, 255), + SHADOW = rgb(127, 127, 255), + HOLY = rgb(255, 229, 127), + + HONEYSUCKLE = rgb(237, 252, 132), + LIGHT_YELLOW_GREEN = rgb(204, 253, 127), + REEF = rgb(201, 255, 162), + PALE_LIGHT_GREEN = rgb(177, 252, 153), + FOAM_GREEN = rgb(144, 253, 169), + PARIS_GREEN = rgb( 80, 200, 120), + LEMON_LIME = rgb(191, 254, 40), + + YELLOW = rgb(255, 255, 0), + SANDY_YELLOW = rgb(253, 238, 115), + + CITRON = rgb(158, 169, 31), + BRASS = rgb(181, 166, 66), + + TUMBLEWEED = rgb(222, 166, 129), + ATOMIC_TANGERINE = rgb(255, 153, 102), + PUMPKIN_ORANGE = rgb(248, 114, 23), + + SUNSET_ORANGE = rgb(253, 94, 83), + ROSSO_CORSA = rgb(212, 0, 0), + + TICKLE_ME_PINK = rgb(253, 135, 178), + PINK_SHERBET = rgb(247, 143, 167), + BLUSH_PINK = rgb(230, 169, 236), + LIGHT_FUSCHIA_PINK = rgb(249, 132, 239), + VENUS_SLIPPER_ORCHID = rgb(221, 101, 253), + PURPLE_PIZZAZZ = rgb(255, 80, 218), + BRIGHT_NEON_PINK = rgb(244, 51, 255), + + LILAC = rgb(206, 162, 253), + PERIWINKLE = rgb(150, 136, 253), + PURPLE_MIMOSA = rgb(158, 123, 255), + HELIOTROPE_PURPLE = rgb(212, 98, 255), + NEON_PURPLE = rgb(188, 19, 254), + + LIGHT_AQUA = rgb(140, 255, 219), + LIGHT_CYAN = rgb(172, 255, 252), + FRENCH_PASS = rgb(189, 237, 253), + BABY_BLUE = rgb(162, 207, 254), + JORDY_BLUE = rgb(138, 185, 241), + DENIM_BLUE = rgb(121, 186, 236), + CRYSTAL_BLUE = rgb( 92, 179, 255), +} + + +do + local ITEM_MOD_HASTE_SPELL_RATING_SHORT = ITEM_MOD_HASTE_SPELL_RATING_SHORT or strGsub(ITEM_MOD_CRIT_SPELL_RATING_SHORT, Addon:CoverSpecialCharacters(ITEM_MOD_CRIT_RATING_SHORT), Addon:CoverSpecialCharacters(ITEM_MOD_HASTE_RATING_SHORT)) + local ITEM_MOD_HASTE_SPELL_RATING = ITEM_MOD_HASTE_SPELL_RATING or strGsub(ITEM_MOD_CRIT_SPELL_RATING, Addon:CoverSpecialCharacters(ITEM_MOD_CRIT_RATING), Addon:CoverSpecialCharacters(ITEM_MOD_HASTE_RATING)) + + + local statsData = { + {true, true, true, "Stamina" , SPELL_STAT3_NAME , ITEM_MOD_STAMINA , Addon.COLORS.WHITE, Addon.COLORS.PALE_LIGHT_GREEN}, + {true, true, true, "Strength" , SPELL_STAT1_NAME , ITEM_MOD_STRENGTH , Addon.COLORS.WHITE, Addon.COLORS.TUMBLEWEED}, + {true, true, true, "Agility" , SPELL_STAT2_NAME , ITEM_MOD_AGILITY , Addon.COLORS.WHITE, Addon.COLORS.PUMPKIN_ORANGE}, + {true, true, true, "Intellect" , SPELL_STAT4_NAME , ITEM_MOD_INTELLECT , Addon.COLORS.WHITE, Addon.COLORS.JORDY_BLUE}, + {true, true, true, "Spirit" , SPELL_STAT5_NAME , ITEM_MOD_SPIRIT , Addon.COLORS.WHITE, Addon.COLORS.LIGHT_AQUA}, + + -- {true, true, true, "Arcane Resistance", RESISTANCE6_NAME, format(strGsub(Addon:CoverSpecialCharacters(ITEM_RESIST_SINGLE), "%%%%s", "%%s"), STRING_SCHOOL_ARCANE), Addon.COLORS.WHITE, Addon.COLORS.ARCANE}, + -- {true, true, true, "Fire Resistance" , RESISTANCE2_NAME, format(strGsub(Addon:CoverSpecialCharacters(ITEM_RESIST_SINGLE), "%%%%s", "%%s"), STRING_SCHOOL_FIRE ), Addon.COLORS.WHITE, Addon.COLORS.FIRE}, + -- {true, true, true, "Nature Resistance", RESISTANCE3_NAME, format(strGsub(Addon:CoverSpecialCharacters(ITEM_RESIST_SINGLE), "%%%%s", "%%s"), STRING_SCHOOL_NATURE), Addon.COLORS.WHITE, Addon.COLORS.NATURE}, + -- {true, true, true, "Frost Resistance" , RESISTANCE4_NAME, format(strGsub(Addon:CoverSpecialCharacters(ITEM_RESIST_SINGLE), "%%%%s", "%%s"), STRING_SCHOOL_FROST ), Addon.COLORS.WHITE, Addon.COLORS.FROST}, + -- {true, true, true, "Shadow Resistance", RESISTANCE5_NAME, format(strGsub(Addon:CoverSpecialCharacters(ITEM_RESIST_SINGLE), "%%%%s", "%%s"), STRING_SCHOOL_SHADOW), Addon.COLORS.WHITE, Addon.COLORS.SHADOW}, + -- -- {true, true, true, "Holy Resistance" , RESISTANCE1_NAME, format(strGsub(Addon:CoverSpecialCharacters(ITEM_RESIST_SINGLE), "%%%%s", "%%s"), STRING_SCHOOL_HOLY ), Addon.COLORS.WHITE, Addon.COLORS.HOLY}, + + {true, true, true, "Arcane Resistance", RESISTANCE6_NAME, format(Addon:ChainGsub(ITEM_RESIST_SINGLE, {"%%[^s]", "%%%0"}), STRING_SCHOOL_ARCANE), Addon.COLORS.WHITE, Addon.COLORS.ARCANE}, + {true, true, true, "Fire Resistance" , RESISTANCE2_NAME, format(Addon:ChainGsub(ITEM_RESIST_SINGLE, {"%%[^s]", "%%%0"}), STRING_SCHOOL_FIRE ), Addon.COLORS.WHITE, Addon.COLORS.FIRE}, + {true, true, true, "Nature Resistance", RESISTANCE3_NAME, format(Addon:ChainGsub(ITEM_RESIST_SINGLE, {"%%[^s]", "%%%0"}), STRING_SCHOOL_NATURE), Addon.COLORS.WHITE, Addon.COLORS.NATURE}, + {true, true, true, "Frost Resistance" , RESISTANCE4_NAME, format(Addon:ChainGsub(ITEM_RESIST_SINGLE, {"%%[^s]", "%%%0"}), STRING_SCHOOL_FROST ), Addon.COLORS.WHITE, Addon.COLORS.FROST}, + {true, true, true, "Shadow Resistance", RESISTANCE5_NAME, format(Addon:ChainGsub(ITEM_RESIST_SINGLE, {"%%[^s]", "%%%0"}), STRING_SCHOOL_SHADOW), Addon.COLORS.WHITE, Addon.COLORS.SHADOW}, + -- {true, true, true, "Holy Resistance" , RESISTANCE1_NAME, format(strGsub(Addon:ChainGsub(ITEM_RESIST_SINGLE), {"%%[^s]", "%%0"}), STRING_SCHOOL_HOLY ), Addon.COLORS.WHITE, Addon.COLORS.HOLY}, + + {true, true, true, "Defense Rating" , ITEM_MOD_DEFENSE_SKILL_RATING_SHORT, ITEM_MOD_DEFENSE_SKILL_RATING, Addon.COLORS.GREEN, Addon.COLORS.YELLOW}, + {true, true, true, "Dodge Rating" , ITEM_MOD_DODGE_RATING_SHORT , ITEM_MOD_DODGE_RATING , Addon.COLORS.GREEN, Addon.COLORS.YELLOW}, + {true, true, true, "Parry Rating" , ITEM_MOD_PARRY_RATING_SHORT , ITEM_MOD_PARRY_RATING , Addon.COLORS.GREEN, Addon.COLORS.YELLOW}, + {true, true, true, "Block Rating" , ITEM_MOD_BLOCK_RATING_SHORT , ITEM_MOD_BLOCK_RATING , Addon.COLORS.GREEN, Addon.COLORS.YELLOW}, + {true, true, true, "Block Value" , ITEM_MOD_BLOCK_VALUE_SHORT , ITEM_MOD_BLOCK_VALUE , Addon.COLORS.GREEN, Addon.COLORS.YELLOW}, + {true, true, true, "Resilience Rating", ITEM_MOD_RESILIENCE_RATING_SHORT , ITEM_MOD_RESILIENCE_RATING , Addon.COLORS.GREEN, Addon.COLORS.YELLOW}, + + {true, true, true, "Expertise Rating" , ITEM_MOD_EXPERTISE_RATING_SHORT , ITEM_MOD_EXPERTISE_RATING , Addon.COLORS.GREEN, Addon.COLORS.TUMBLEWEED}, + {true, true, true, "Attack Power" , ITEM_MOD_ATTACK_POWER_SHORT , ITEM_MOD_ATTACK_POWER , Addon.COLORS.GREEN, Addon.COLORS.TUMBLEWEED}, + {true, true, true, "Attack Power In Forms" , ITEM_MOD_FERAL_ATTACK_POWER_SHORT , ITEM_MOD_FERAL_ATTACK_POWER , Addon.COLORS.GREEN, Addon.COLORS.TUMBLEWEED}, + {true, true, true, "Armor Penetration Rating", ITEM_MOD_ARMOR_PENETRATION_RATING_SHORT, ITEM_MOD_ARMOR_PENETRATION_RATING, Addon.COLORS.GREEN, Addon.COLORS.TUMBLEWEED}, + + {nil , nil , true, "Spell Power" , ITEM_MOD_SPELL_POWER_SHORT , ITEM_MOD_SPELL_POWER , Addon.COLORS.GREEN, Addon.COLORS.PERIWINKLE}, + {true, true, nil , "Healing" , ITEM_MOD_SPELL_HEALING_DONE_SHORT, ITEM_MOD_SPELL_HEALING_DONE, Addon.COLORS.GREEN, Addon.COLORS.LIGHT_CYAN}, + {true, true, nil , "Spell Damage", ITEM_MOD_SPELL_DAMAGE_DONE_SHORT , ITEM_MOD_SPELL_DAMAGE_DONE , Addon.COLORS.GREEN, Addon.COLORS.PERIWINKLE}, + + {true, true, true, "Spell Penetration", ITEM_MOD_SPELL_PENETRATION_SHORT, ITEM_MOD_SPELL_PENETRATION, Addon.COLORS.GREEN, Addon.COLORS.VENUS_SLIPPER_ORCHID}, + + {nil , nil , true, "Hit Rating" , ITEM_MOD_HIT_RATING_SHORT , ITEM_MOD_HIT_RATING , Addon.COLORS.GREEN, Addon.COLORS.PINK_SHERBET}, + {nil , nil , true, "Critical Strike Rating" , ITEM_MOD_CRIT_RATING_SHORT , ITEM_MOD_CRIT_RATING , Addon.COLORS.GREEN, Addon.COLORS.PARIS_GREEN} , + {nil , nil , true, "Haste Rating" , ITEM_MOD_HASTE_RATING_SHORT , ITEM_MOD_HASTE_RATING , Addon.COLORS.GREEN, Addon.COLORS.LEMON_LIME} , + {true, true, nil , "Physical Hit Rating" , ITEM_MOD_HIT_RATING_SHORT , ITEM_MOD_HIT_RATING , Addon.COLORS.GREEN, Addon.COLORS.PINK_SHERBET}, + {true, true, nil , "Physical Critical Strike Rating", ITEM_MOD_CRIT_RATING_SHORT , ITEM_MOD_CRIT_RATING , Addon.COLORS.GREEN, Addon.COLORS.PARIS_GREEN}, + {nil , true, nil , "Physical Haste Rating" , ITEM_MOD_HASTE_RATING_SHORT , ITEM_MOD_HASTE_RATING , Addon.COLORS.GREEN, Addon.COLORS.LEMON_LIME}, + {true, true, nil , "Spell Hit Rating" , ITEM_MOD_HIT_SPELL_RATING_SHORT , ITEM_MOD_HIT_SPELL_RATING , Addon.COLORS.GREEN, Addon.COLORS.PINK_SHERBET}, + {true, true, nil , "Spell Critical Strike Rating" , ITEM_MOD_CRIT_SPELL_RATING_SHORT , ITEM_MOD_CRIT_SPELL_RATING , Addon.COLORS.GREEN, Addon.COLORS.PARIS_GREEN}, + {nil , true, nil , "Spell Haste Rating" , ITEM_MOD_HASTE_SPELL_RATING_SHORT, ITEM_MOD_HASTE_SPELL_RATING, Addon.COLORS.GREEN, Addon.COLORS.LEMON_LIME}, + + {true, true, true, "Health Regeneration", ITEM_MOD_HEALTH_REGENERATION_SHORT, ITEM_MOD_HEALTH_REGEN , Addon.COLORS.GREEN, Addon.COLORS.PALE_LIGHT_GREEN}, + {true, true, true, "Mana Regeneration" , ITEM_MOD_MANA_REGENERATION_SHORT , ITEM_MOD_MANA_REGENERATION, Addon.COLORS.GREEN, Addon.COLORS.JORDY_BLUE}, + + + -- {"Ranged Attack Power", ITEM_MOD_RANGED_ATTACK_POWER_SHORT , ITEM_MOD_RANGED_ATTACK_POWER}, + } + + + local isReversedLocale = not ITEM_MOD_STAMINA:find"^%%" + local GetLocaleStatFormat = ITEM_MOD_STAMINA:find"^%%" and function(pre, suf) return format("%s %s", pre, suf) end or function(pre, suf) return format("%s %s", suf, pre) end + -- instead of flipping them, mess with the normal form pattern instead. format("%s %s", isBaseStat and sign or "+", normalName) vs format("%2$s %1$s", isBaseStat and sign or "+", normalName) + + for i, data in ipairs(statsData) do + local expacs = {} + expacs.classic = data[1] + expacs.tbc = data[2] + expacs.wrath = data[3] + local stat = data[4] + + + for expac, list in pairs(Addon.statList) do + if expacs[expac] then + tinsert(list, stat) + end + end + if expacs[Addon.expac] then + local normalName = data[5] + -- local function ReorderByLocale() return GetLocaleStatFormat(reorderLocaleMode, normalName) end + -- local normalPattern = GetLocaleStatFormat(normalName) + + local tooltipPattern = data[6] + local tooltipPattern2 = strGsub(strGsub(tooltipPattern, "%%c", "%%s"), "%%d", "%%s") + + local tooltipColor = data[7] + + local color = data[8] + + Addon.statsInfo[stat] = {} + local StatInfo = Addon.statsInfo[stat] + + StatInfo.tooltipColor = tooltipColor + StatInfo.color = color + + local isBaseStat = strFind(tooltipPattern, "%%%d?%$?c") + local reorderLocaleMode = isBaseStat and "%s%s" or "+%s" + + + + + + + local normalNameReplacePattern = Addon:CoverSpecialCharacters(normalName) + + local normalFormPattern = GetLocaleStatFormat(isBaseStat and "%1$s%2$s" or "+%1$s", normalName) + local normalFormCapture = strGsub(Addon:ReversePattern(GetLocaleStatFormat(isBaseStat and "%c%s" or "+%s", normalName)), "%$", "%%.?%0") + local normalFormPattern2 = GetLocaleStatFormat(isBaseStat and "%s%s" or "+%s", normalName) + -- local aliasPattern = + + + + local function ApplyMod(text, normalForm) + local match1, match2 = strMatch(normalForm, normalFormCapture) + local origStrNumber = match1 .. (match2 or "") + local strNumber, percent = strMatch(origStrNumber, "(%d+)(%%?)") + if DECIMAL_SEPERATOR ~= "." then + strNumber = strGsub(strNumber, "%"..DECIMAL_SEPERATOR, ".") + end + local number = Addon:Round(tonumber(strNumber) * Addon:GetOption("mod", stat), 1 / 10^Addon:GetOption("precision", stat)) + strNumber = tostring(number) + if DECIMAL_SEPERATOR ~= "." then + strNumber = strGsub(strNumber, "%.", DECIMAL_SEPERATOR) + end + if isBaseStat and number > 0 then + strNumber = "+" .. strNumber + end + return strGsub(text, Addon:CoverSpecialCharacters(origStrNumber), Addon:CoverSpecialCharacters(strNumber .. percent)) + end + + local function ConvertToAliasForm(text) + local alias = Addon:GetOption("reword", stat) + if alias and alias ~= "" and alias ~= normalName then + text = strGsub(text, normalNameReplacePattern, alias) + end + return text + end + + function StatInfo:Reword(text, normalForm) + if Addon:GetOption("allow", "reword") and Addon:GetOption("doReword", stat) then + text = ConvertToAliasForm(ApplyMod(text, normalForm)) + end + return text + end + + local function HasNumber(match1, match2) + local strNumber = match1 + if isBaseStat then + strNumber = match2 + end + return tonumber((strGsub(strNumber, "%%", ""))) + end + + function StatInfo:ConvertToNormalForm(text) + local match1, match2 = strMatch(text, Addon:ReversePattern(tooltipPattern)) + if match1 then + if not HasNumber(match1, match2) then return end + return format(normalFormPattern, match1, match2) + end + local match1, match2 = strMatch(strLower(text), strLower(normalFormCapture)) + if match1 then + if not HasNumber(match1, match2) then return end + return format(normalFormPattern, match1, match2) + end + for _, rule in ipairs(Addon.localeExtras[stat] or {}) do + local matches = rule.OUTPUT and {rule.OUTPUT(strMatch(text, rule.INPUT))} or {strMatch(text, rule.INPUT)} + if #matches > 0 then + if not HasNumber(matches[1], matches[2]) then return end + return format(normalFormPattern, matches[1], matches[2]) + end + end + return nil + end + + function StatInfo:GetDefaultForm(number) + local strNumber = tostring(number) + if DECIMAL_SEPERATOR ~= "." then + strNumber = strGsub(strNumber, "%.", DECIMAL_SEPERATOR) + end + return format(tooltipPattern2, isBaseStat and (number < 0 and "" or "+") or strNumber, isBaseStat and strNumber or nil) + end + end + end + + Addon.statsInfo["Trainable"] = {color = Addon.COLORS.ORANGE} + Addon.statsInfo["Damage"] = {color = Addon.COLORS.WHITE} + Addon.statsInfo["DamagePerSecond"] = {color = Addon.COLORS.WHITE} + Addon.statsInfo["Enchant"] = {color = Addon.COLORS.GREEN} + Addon.statsInfo["Speed"] = {color = Addon.COLORS.WHITE} + Addon.statsInfo["Speedbar"] = {color = Addon.COLORS.WHITE} + Addon.statsInfo["SocketHint"] = {color = Addon.COLORS.GREEN} +end + + + + + + + + + + + + diff --git a/Locale/enUs.lua b/Locale/enUs.lua index 523ef72..28ed285 100644 --- a/Locale/enUs.lua +++ b/Locale/enUs.lua @@ -1,1801 +1,65 @@ local ADDON_NAME, Data = ... -local locale = LibStub("AceLocale-3.0"):NewLocale(ADDON_NAME, "enUS", true) -local L = {} +local Addon = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME) +local L = LibStub("AceLocale-3.0"):NewLocale(ADDON_NAME, "enUS", true, not Addon.debug) +if not L then return end -L["Miscellaneous"] = MISCELLANEOUS +L["Reorder"] = true +L["Recolor"] = true +L["Group Secondary Stats with Base Stats"] = true +L["Space Above Bonus Effects"] = true +L["Modifier"] = true +-- padding locations +L["Spacing"] = true +L["Hide Extra Spacing"] = true +L["Space Above"] = true +L["Space Below"] = true +L["Secondary Stats"] = true +L["Sockets"] = true +L["Set List"] = true +L["Set Bonus"] = true -for i, element in ipairs(Data:GetElements()) do - L[Data:GetElementEnglish(i) .. " Resist"] = element .. " Resist" - L[Data:GetElementEnglish(i) .. " Damage"] = element .. " Damage" -end -L["Equip PATTERN"] = "^%s*Equip:%s*" -L["Use PATTERN"] = "^%s*Use:%s*" -L["Set PATTERN"] = "^%(?%d*%)?%s*Set:%s*" -L["Socket PATTERN"] = "^%u%l+%s+Socket$" -L["SocketBonus PATTERN"] = "^%s*Socket Bonus:%s*" -L["Weapon Speed PATTERN"] = "^(Speed) ([%d%.]+)" -L["ConjunctiveWord PATTERN"] = "%s+and%s+" -L["DisjunctiveWord PATTERN"] = "%s+or%s+" +-- trainable +L["Trainable Equipment"] = true +-- weapon damage +L["Show Minimum and Maximum"] = true +L["Show Average"] = true +L["Show Variance"] = true +L["Variance Prefix"] = true --- Removes leading/trailing spaces. Also removes leading "your " and appending " spell" or " ability" text when it's meaningless -local function TrimSpell(spell) - local spell = spell:gsub("^%s*", ""):gsub("%s*$", ""):gsub("%.$", "") - if spell:match(" spells$") or spell:match(" abilities$") then - if spell:match(L["ConjunctiveWord PATTERN"]) or spell:match(L["DisjunctiveWord PATTERN"]) then - spell = spell:gsub(" spells$", ""):gsub( "abilities$", ""):gsub("^your ", "") - end - else - spell = spell:gsub(" spell$", ""):gsub(" ability$", ""):gsub("^your ", "") - end - return spell -end +-- dps +L["Remove Brackets"] = true -local function FixPercent(amount) - return amount:gsub("%%", "%%%%") -end +-- speed +L["Prefix"] = true +L["Precision"] = true +-- speed bar +L["Speed Bar"] = true +L["Test"] = true +L["Show Speed"] = true +L["Fill Character"] = true +L["Blank Character"] = true +-- races +L["Hide Pointless Lines"] = true +-- prefixes +L["Remove Space"] = true +L["Icon Space"] = true +-- reset +L["Order"] = true +L["Mod"] = true -L["Reword tooltips"] = "Reword tooltips" -L["REWORD TOOLTIPS DESCRIPTION"] = "Shortens some long lines of text on item tooltips. Does not remove any information." - -L["Reorder stats"] = "Reorder stats" -L["REORDER STATS DESCRIPTION"] = "Makes tooltips display stats in a consistent order. Always Stamina before Intellect, for example." - -L["Recolor stats"] = "Recolor stats" -L["RECOLOR STATS DESCRIPTION"] = "Adds customizable coloring to stats in tooltips." - -L["Recolor Usable Effects"] = "Recolor usable effects" -L["Recolor Usable Effects DESCRIPTION"] = "This applies to active trinkets, as well as consumable items like food, drinks, potions, and bandages." - -L["Show Speedbar"] = "Show Speedbar" -L["SHOW SPEEDBAR DESCRIPTION"] = "Displays a bar which visualizes weapon speed. The bar will be more filled for slower weapons." - -L["Speedbar width"] = "Speedbar width" -L["SPEEDBAR SIZE DESCRIPTION"] = "The maximum length of the speedbar (for a slow weapon). Higher values make the bar more accurate, but also make the tooltip wider." - -L["Speed accuracy"] = "Speed accuracy" -L["SPEED ACCURACY DESCRIPTION"] = "The number of decimal places to appear in a weapon's speed. Default tooltips show two, but only one is ever needed." - - -L["Reset"] = "Reset" -L["Color"] = "Color" -L["Speedbar Configuration"] = "Speedbar" -L["Colors Configuration"] = "Colors" -L["Reset Color Options"] = "Reset Color Options" - -L["Base Stats"] = "Base Stats" -L["Elemental Resistances"] = "Elemental Resistances" -L["Elemental Damage"] = "Elemental Damage" -L["Defensive"] = "Defensive" -L["Physical"] = "Physical" -L["Magical"] = "Magical" -L["Healing"] = "Healing" - -L["Trainable Equipment"] = "Trainable Equipment" -L["Trainable Equipment DESCRIPTION"] = "Items which are equippable after more training will appear as a customizable color instead of the default red." - -L["Weapon Damage"] = "Weapon Damage" -L["Weapon Damage DESCRIPTION"] = "This will only affect weapons which deal physical damage (not wands)." - -L["Weapon Speed"] = "Weapon Speed" -L["Weapon Speed DESCRIPTION"] = "This will also recolor the weapon speedbar, if enabled." - -L["Enchantment"] = "Enchantment" -L["Enchantment DESCRIPTION"] = "Enchantments will appear in a customizable color." - -L["Skill"] = "Skill" -L["Skill DESCRIPTION"] = "This applies to weapon and profession skill bonuses." - - - -L["Armor"] = "Armor" - -L["Stamina"] = "Stamina" -L["Strength"] = "Strength" -L["Agility"] = "Agility" -L["Intellect"] = "Intellect" -L["Spirit"] = "Spirit" - -L["Defense"] = "Defense" -L["Resilience"] = "Resilience" -L["Dodge"] = "Dodge" -L["Parry"] = "Parry" -if Data:IsBCC() then - L["Block Rating"] = "Block Rating" -elseif Data:IsClassic() then - L["Block Rating"] = "Block Chance" -end -L["Block Value"] = "Block Value" -L["Resist All"] = "Resist All" - -L["Attack Power"] = "Attack Power" -L["Ranged Attack Power"] = "Ranged Attack Power" -L["Physical Hit"] = "Physical Hit" -L["Physical Crit"] = "Physical Crit" -L["Physical Haste"] = "Physical Haste" -L["Armor Pen"] = "Armor Pen" -L["Expertise"] = "Expertise" - -L["Spell Damage"] = "Spell Damage" -L["Spell Hit"] = "Spell Hit" -L["Spell Crit"] = "Spell Crit" -L["Spell Haste"] = "Spell Haste" -L["Spell Pen"] = "Spell Pen" - -L["Healing"] = "Healing" -L["Health"] = "Health" -L["Mana"] = "Mana" - - - - --- Get localized item subtype names from https://wow.tools/dbc/?dbc=itemsubclass --- Get correct build with GetBuildInfo() - -L["Axe"] = "Axe" -L["Sword"] = "Sword" -L["Mace"] = "Mace" -L["Polearm"] = "Polearm" -L["Staff"] = "Staff" -L["Dagger"] = "Dagger" -L["Fist Weapon"] = "Fist Weapon" -L["Bow"] = "Bow" -L["Crossbow"] = "Crossbow" -L["Gun"] = "Gun" -L["Thrown"] = "Thrown" -L["Wand"] = "Wand" - --- L["Miscellaneous"] = "Miscellaneous" --- L["Cloth"] = "Cloth" -L["Leather"] = "Leather" -L["Mail"] = "Mail" -L["Plate"] = "Plate" -L["Shield"] = "Shield" -L["Libram"] = "Libram" -L["Idol"] = "Idol" -L["Totem"] = "Totem" - - - - - - - - - - - - - - --- ██╗ ██╗███████╗ █████╗ ██████╗ ██████╗ ███╗ ██╗ ███████╗████████╗ █████╗ ████████╗███████╗ --- ██║ ██║██╔════╝██╔══██╗██╔══██╗██╔═══██╗████╗ ██║ ██╔════╝╚══██╔══╝██╔══██╗╚══██╔══╝██╔════╝ --- ██║ █╗ ██║█████╗ ███████║██████╔╝██║ ██║██╔██╗ ██║ ███████╗ ██║ ███████║ ██║ ███████╗ --- ██║███╗██║██╔══╝ ██╔══██║██╔═══╝ ██║ ██║██║╚██╗██║ ╚════██║ ██║ ██╔══██║ ██║ ╚════██║ --- ╚███╔███╔╝███████╗██║ ██║██║ ╚██████╔╝██║ ╚████║ ███████║ ██║ ██║ ██║ ██║ ███████║ --- ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ - - -L[#L+1] = {LABEL = "Physical Damage"} -L[#L].COLOR = "WEAP_DAMAGE" -L[#L].MAP = { - { - INPUT = "^(%d+) %- (%d+)%s+Damage", - OUTPUT = function(min, max) return ("%d - %d (%d) Damage"):format(min, max, Data:Round((min + max)/2, 0)) end, - -- OUTPUT = function(min, max) return ("%d - %d - %d Damage"):format(min, Data:Round((min + max)/2, 0), max) end, - -- OUTPUT = function(min, max) return ("%d - (%d) - %d Damage"):format(min, Data:Round((min + max)/2, 0), max) end, - }, -} -L[#L].CAPTURES = { - "%d+ %- %d+ %(%d+%) Damage", - -- "%d+ %- %d+ %- %d+ Damage", - -- "%d+ %- %(%d+%) %- %d+ Damage", -} - -for i, element in pairs(Data:GetElements()) do - L[#L+1] = {LABEL = element .. " Damage"} - L[#L].COLOR = Data:GetElementKey(i) .. "_DAMAGE" - L[#L].MAP = { - { - INPUT = "^(%d+) %- (%d+) " .. Data:GetElementPattern(i) .. " Damage$", - OUTPUT = function(min, max) return ("%d - %d (%d) %s Damage"):format(min, max, Data:Round((min + max)/2, 0), element) end, - }, - } - L[#L].CAPTURES = { - "%d+ %- %d+ %(%d+%) " .. element .. " Damage", - } -end - -L[#L+1] = {LABEL = "Bonus Physical Damage"} -L[#L].COLOR = "WEAP_DAMAGE" -L[#L].MAP = { - { - INPUT = "%+ (%d+) %- (%d+)%s+Damage", - OUTPUT = function(min, max) return ("+ %d - %d (%d) Damage"):format(min, max, Data:Round((min + max)/2, 0)) end, - }, -} -L[#L].CAPTURES = { - "%+ %d+ %- %d+ %(%d+%) Damage", -} - -for i, element in pairs(Data:GetElements()) do - L[#L+1] = {LABEL = "Bonus " .. element .. " Damage"} - L[#L].COLOR = Data:GetElementKey(i) .. "_DAMAGE" - L[#L].MAP = { - { - INPUT = "%+ (%d+) %- (%d+) " .. Data:GetElementPattern(i) .. " Damage$", - OUTPUT = function(min, max) return ("+ %d - %d (%d) %s Damage"):format(min, max, Data:Round((min + max)/2, 0), element) end, - }, - } - L[#L].CAPTURES = { - "%+ %d+ %- %d+ %(%d+%) " .. element .. " Damage", - } -end - -L[#L+1] = {LABEL = "Damage per Second"} -L[#L].MAP = { - { - INPUT = "%(([%d%.]+) damage per second%)", - OUTPUT = "(%s DPS)", - }, - { - INPUT = "Adds ([%d%.]+) damage per second", - OUTPUT = "+%s DPS", - }, -} -L[#L].CAPTURES = { - "%(%s+ DPS%)", -} - - - - - - - - - - --- ██████╗ █████╗ ███████╗███████╗ ███████╗████████╗ █████╗ ████████╗███████╗ --- ██╔══██╗██╔══██╗██╔════╝██╔════╝ ██╔════╝╚══██╔══╝██╔══██╗╚══██╔══╝██╔════╝ --- ██████╔╝███████║███████╗█████╗ ███████╗ ██║ ███████║ ██║ ███████╗ --- ██╔══██╗██╔══██║╚════██║██╔══╝ ╚════██║ ██║ ██╔══██║ ██║ ╚════██║ --- ██████╔╝██║ ██║███████║███████╗ ███████║ ██║ ██║ ██║ ██║ ███████║ --- ╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ - - -L[#L+1] = {LABEL = "Armor"} -L[#L].COLOR = "ARMOR" -L[#L].MAP = { - { - INPUT = "^([%+%-]%d+) Armor$", - OUTPUT = "%s " .. L["Armor"], - }, - { - INPUT = "Increases armor by (%d+)", - OUTPUT = "+%d " .. L["Armor"], - }, -} -L[#L].CAPTURES = { - "[%+%-]?%d+ " .. L["Armor"], -} - -L[#L+1] = {LABEL = "Block"} -L[#L].COLOR = "BLOCK_VALUE" -L[#L].MAP = { - { - INPUT = "^(%d+) " .. "Block" .. "$", - OUTPUT = "%d Block", - }, -} -L[#L].CAPTURES = { - "%d+ Block$", -} - -for _, stat in ipairs{"Stamina", "Strength", "Agility", "Intellect", "Spirit"} do - L[#L+1] = {LABEL = stat} - L[#L].COLOR = stat:upper() - L[#L].MAP = { - { - INPUT = "^([%+%-])(%d+) " .. stat .. "$", - OUTPUT = "%s%d " .. L[stat], - }, - { - INPUT = "Increases your " .. stat .. " by %+?(%d+)", - OUTPUT = "+%d " .. L[stat], - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ " .. L[stat] .. "", - } -end - -L[#L+1] = {LABEL = "All Resist"} -L[#L].COLOR = "RESIST_ALL" -L[#L].MAP = { - { - INPUT = "^[%+%-](%d+) All Resistances$", - OUTPUT = "+%d All Resist", - }, - { - INPUT = "Increases your resistance to all schools of magic by (%d+)", - OUTPUT = "+%d All Resist", - }, -} -L[#L].CAPTURES = { - "[%+%-]%d+ All Resist", -} - -for i, element in pairs(Data:GetElements()) do - L[#L+1] = {LABEL = element .. " Resist"} - L[#L].COLOR = Data:GetElementKey(i) .. "_RESIST" - L[#L].MAP = { - { - INPUT = "^%+(%d+) " .. Data:GetElementPattern(i) .. " Resista?n?c?e?$", - OUTPUT = "+%d " .. L[element .. " Resist"], - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ " .. L[element .. " Resist"] .. ".*", - } -end - - - - - - - - - - - --- ██████╗ ███████╗███████╗███████╗███╗ ██╗███████╗██╗██╗ ██╗███████╗ --- ██╔══██╗██╔════╝██╔════╝██╔════╝████╗ ██║██╔════╝██║██║ ██║██╔════╝ --- ██║ ██║█████╗ █████╗ █████╗ ██╔██╗ ██║███████╗██║██║ ██║█████╗ --- ██║ ██║██╔══╝ ██╔══╝ ██╔══╝ ██║╚██╗██║╚════██║██║╚██╗ ██╔╝██╔══╝ --- ██████╔╝███████╗██║ ███████╗██║ ╚████║███████║██║ ╚████╔╝ ███████╗ --- ╚═════╝ ╚══════╝╚═╝ ╚══════╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═══╝ ╚══════╝ - - -L[#L+1] = {LABEL = "Defense"} -L[#L].COLOR = "ARMOR" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "Increases defense rating by (%d+)", - OUTPUT = "+%d Defense Rating", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Defense Rating.*", - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Increased Defense %+(%d+)", - OUTPUT = "+%d Defense", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Defense.*", - } -end - - - - -if Data:IsBCC() then - L[#L+1] = {LABEL = "Resilience"} - L[#L].COLOR = "RESILIENCE" - L[#L].MAP = { - { - INPUT = "Improves your resilience rating by (%d+)", - OUTPUT = "+%d Resilience", - }, - { - INPUT = "%+(%d+) Resilience Rating", - OUTPUT = "+%d Resilience", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Resilience.*", - } -end - -L[#L+1] = {LABEL = "Dodge"} -L[#L].COLOR = "DODGE" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "Increases your dodge rating by (%d+)", - OUTPUT = "+%d Dodge Rating", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Dodge Rating.*", - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Increases your chance to dodge an attack by (%d+)%%", - OUTPUT = "+%d%%%% Dodge", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+%% Dodge.*", - } -end - -L[#L+1] = {LABEL = "Parry"} -L[#L].COLOR = "PARRY" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "Increases your parry rating by (%d+)", - OUTPUT = "+%d Parry Rating", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Parry Rating.*", - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Increases your chance to parry ?a?n? ?a?t?t?a?c?k? by (%d+)%%", - OUTPUT = "+%d%%%% Parry", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+%% Parry.*", - } -end - -L[#L+1] = {LABEL = "Block Rating"} -L[#L].COLOR = "BLOCK_RATING" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "Increases your ?s?h?i?e?l?d? block rating by (%d+)", - OUTPUT = "+%d Block Rating", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Block Rating.*", - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Increases ?y?o?u?r? chance to block attacks with a shield by (%d+)%%", - OUTPUT = "+%d%%%% Block Chance", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+%% Block Chance.*", - } -end - -L[#L+1] = {LABEL = "Block Value"} -L[#L].MAP = { - { - INPUT = "Increases the block value of your shield by (%d+)", - OUTPUT = "+%d Block Value", - }, -} -L[#L].CAPTURES = { - "[%+%-]%d+ Block Value.*", -} -L[#L].COLOR = "BLOCK_VALUE" - -for i, element in pairs(Data:GetElements()) do - L[#L+1] = {LABEL = element .. " Reflect Damage"} - L[#L].MAP = { - { - INPUT = "When struck in combat inflicts (%d+) " .. Data:GetElementPattern(i) .. " damage to the attacker", - OUTPUT = "+%d " .. element .. " damage reflected to melee attackers", - }, - { - INPUT = "Deals (%d+) " .. Data:GetElementPattern(i) .. " damage to anyone who strikes you with a melee attack", - OUTPUT = "+%d " .. element .. " damage reflected to melee attackers", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ " .. element .. " damage reflected to melee attackers.*", - } - L[#L].COLOR = Data:GetElementKey(i) .. "_DAMAGE" - -end -L[#L+1] = {LABEL = "Resist All"} -L[#L].MAP = { - { - INPUT = "Increases resistances to all schools of magic by (%d+)", - OUTPUT = "+%d All Resistances", - }, -} -L[#L].CAPTURES = { - "[%+%-]%d+ All Resistances.*", -} -L[#L].COLOR = "RESIST_ALL" - - - - - - - - - - --- ██████╗ ██╗ ██╗██╗ ██╗███████╗██╗ ██████╗ █████╗ ██╗ --- ██╔══██╗██║ ██║╚██╗ ██╔╝██╔════╝██║██╔════╝██╔══██╗██║ --- ██████╔╝███████║ ╚████╔╝ ███████╗██║██║ ███████║██║ --- ██╔═══╝ ██╔══██║ ╚██╔╝ ╚════██║██║██║ ██╔══██║██║ --- ██║ ██║ ██║ ██║ ███████║██║╚██████╗██║ ██║███████╗ --- ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝ - - -L[#L+1] = {LABEL = "Attack Power In Form"} -L[#L].COLOR = "ATTACK_POW" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "Increases attack power by (%d+) in Cat, Bear, Dire Bear, and Moonkin forms only", - OUTPUT = "+%d Attack Power while shapeshifted", - }, - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "%+(%d+) Attack Power in Cat, Bear, and Dire Bear forms only", - OUTPUT = "+%d Attack Power while shapeshifted", - }, - } -end -L[#L].CAPTURES = { - "[%+%-]%d+ Attack Power while shapeshifted.*", -} - -L[#L+1] = {LABEL = "Attack Power"} -L[#L].COLOR = "ATTACK_POW" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "Increases [Aa]ttack [Pp]ower by (%d+)", - OUTPUT = "+%d Attack Power", - }, - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Increases [Aa]ttack [Pp]ower by (%d+)", - OUTPUT = "+%d Attack Power", - }, - { - INPUT = "%+(%d+) Attack Power", - OUTPUT = "+%d Attack Power", - }, - } -end -L[#L].CAPTURES = { - "[%+%-]%d+ Attack Power.*", -} - -L[#L+1] = {LABEL = "Ranged Attack Power"} -L[#L].COLOR = "R_ATTACK_POW" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "Increases ranged attack power by (%d+)", - OUTPUT = "+%d Ranged Attack Power", - }, - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "%+(%d+) ranged Attack Power", - OUTPUT = "+%d Ranged Attack Power", - }, - } -end -L[#L].CAPTURES = { - "[%+%-]%d+ Ranged Attack Power.*", -} - -L[#L+1] = {LABEL = "Physical Hit"} -L[#L].COLOR = "PHYS_HIT" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "I[mn][pc]r[oe][va]s?es ?y?o?u?r? hit rating by (%d+)", - OUTPUT = "+%d Physical Hit Rating", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Physical Hit Rating.*", - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Improves your chance to hit by (%d+)%%", - OUTPUT = "+%d%%%% Physical Hit Chance", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+%% Physical Hit Chance.*", - } -end - -L[#L+1] = {LABEL = "Physical Crit"} -L[#L].COLOR = "PHYS_CRIT" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "I[mn][pc]r[oe][va]s?es ?y?o?u?r? critical strike rating by (%d+)", - OUTPUT = "+%d Physical Crit Rating", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Physical Crit Rating.*", - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Improves your chance to get a critical strike by (%d+)%%", - OUTPUT = "+%d%%%% Physical Crit Chance", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+%% Physical Crit Chance.*", - } -end - -if Data:IsBCC() then - L[#L+1] = {LABEL = "Physical Haste"} - L[#L].COLOR = "PHYS_HASTE" - L[#L].MAP = { - { - INPUT = "I[mn][pc]r[oe][va]s?es ?y?o?u?r? haste rating by (%d+)", - OUTPUT = "+%d Physical Haste Rating", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Physical Haste Rating.*", - } - - L[#L+1] = {LABEL = "Armor Penetration"} - L[#L].COLOR = "PHYS_PEN" - L[#L].MAP = { - { - INPUT = "Your attacks ignore (%d+) of your opponent's armor", - OUTPUT = "+%d Armor Pen", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Armor Pen.*", - } - - L[#L+1] = {LABEL = "Expertise"} - L[#L].COLOR = "EXPERTISE" - L[#L].MAP = { - { - INPUT = "Increases? ?y?o?u?r? expertise rating by (%d+)", - OUTPUT = "+%d Expertise Rating", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Expertise Rating.*", - } -end - -for i, element in pairs(Data:GetElements()) do - L[#L+1] = {LABEL = element .. " Melee Damage"} - L[#L].COLOR = Data:GetElementKey(i) .. "_DAMAGE" - L[#L].MAP = { - { - INPUT = "Adds (%d+) " .. Data:GetElementPattern(i) .. " damage to your melee attacks", - OUTPUT = "+%d melee " .. element .. " damage", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ melee " .. element .. " damage.*", - } -end - - - - - - - --- ███╗ ███╗ █████╗ ██████╗ ██╗ ██████╗ █████╗ ██╗ --- ████╗ ████║██╔══██╗██╔════╝ ██║██╔════╝██╔══██╗██║ --- ██╔████╔██║███████║██║ ███╗██║██║ ███████║██║ --- ██║╚██╔╝██║██╔══██║██║ ██║██║██║ ██╔══██║██║ --- ██║ ╚═╝ ██║██║ ██║╚██████╔╝██║╚██████╗██║ ██║███████╗ --- ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝ - - -L[#L+1] = {LABEL = "Spell Power"} -L[#L].COLOR = "MAGICAL" -L[#L].MAP = { - { - INPUT = "Increases damage and healing done by magical spells and effects by up to (%d+)", - OUTPUT = "+%d Spell Power", - }, -} -L[#L].CAPTURES = { - "[%+%-]%d+ Spell Power.*", -} - -for i, element in pairs(Data:GetElements()) do - L[#L+1] = {LABEL = element .. " Spell Damage"} - L[#L].COLOR = Data:GetElementKey(i) .. "_DAMAGE" - L[#L].MAP = { - { - INPUT = "%+(%d+) " .. Data:GetElementPattern(i) .. " Damage", - OUTPUT = "+%d " .. element .. " Spell Damage", - }, - { - INPUT = "Increases ?t?h?e? damage done by " .. Data:GetElementPattern(i) .. " spells and effects by up to (%d+)", - OUTPUT = "+%d " .. element .. " Spell Damage", - }, - { - INPUT = "Increases " .. Data:GetElementPattern(i) .. " spell damage by (%d+)", - OUTPUT = "+%d " .. element .. " Spell Damage", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ " .. element .. " Spell Damage.*", - } -end - -L[#L+1] = {LABEL = "Spell Damage"} -L[#L].COLOR = "MAGICAL" -L[#L].MAP = { - { - INPUT = "Increases damage done to (%D+) by magical spells and effects by up to (%d+)", - OUTPUT = function(targets, amount) return ("+%d Spell Damage against %s"):format(amount, targets) end, - }, - { - INPUT = "Increases damage done by magical spells and effects by up to (%d+)", - OUTPUT = "+%d Spell Damage", - }, - { - INPUT = "Increases damage done from spells by up to (%d+)", - OUTPUT = "+%d Spell Damage", - }, - { - INPUT = "(Increases spell damage by up to %d+)%%", - OUTPUT = "%s%%%%", - }, - { - INPUT = "Increases spell damage by up to (%d+)", - OUTPUT = "+%d Spell Damage", - }, -} -L[#L].CAPTURES = { - "[%+%-]%d+ Spell Damage.*", - "[%+%-]%d+ Spell Damage and Healing.*", -} - -L[#L+1] = {LABEL = "Healing"} -L[#L].COLOR = "HEALING" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "Increases healing done by up to (%d+) and damage done by up to (%d+) for all magical spells and effects", - OUTPUT = "+%d Healing and +%d Spell Damage", - }, - { - INPUT = "Increases healing done by spells by up to (%d+) and damage done by spells by up to (%d+)", - OUTPUT = "+%d Healing and +%d Spell Damage", - }, - { - INPUT = "Increases your spell damage by up to (%d+) and your healing by up to (%d+)", - OUTPUT = function(damage, healing) return ("+%d Healing and +%d Spell Damage"):format(healing, damage) end, - }, - { - INPUT = "Increases healing done by magical spells by up to (%d+)", - OUTPUT = "+%d Healing", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Healing and [%+%-]%d+ Spell Damage.*", - "[%+%-]%d+ Healing [%+%-]%d+ Spell Damage.*", - "[%+%-]%d+ Healing.*", - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Increases healing done by spells and effects by up to (%d+)", - OUTPUT = "+%d Healing", - }, - } - L[#L].CAPTURES = { - "%+%d+ Healing.*", - } -end - -L[#L+1] = {LABEL = "Spell Hit"} -L[#L].COLOR = "MAGIC_HIT" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "I[mn][pc]r[oe][va]s?es ?y?o?u?r? spell hit rating by (%d+)", - OUTPUT = "+%d Spell Hit Rating", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Spell Hit Rating.*", - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Improves your chance to hit with spells by (%d+)%%", - OUTPUT = "+%d%%%% Spell Hit Chance", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+%% Spell Hit Chance.*", - } -end - -L[#L+1] = {LABEL = "Spell Crit"} -L[#L].COLOR = "MAGIC_CRIT" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "I[mn][pc]r[oe][va]s?es ?y?o?u?r? spell critical strike rating by (%d+)", - OUTPUT = "+%d Spell Crit Rating", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Spell Crit Rating.*", - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Improves your chance to get a critical strike with spells by (%d+)%%", - OUTPUT = "+%d%%%% Spell Crit Chance", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+%% Spell Crit Chance.*", - } -end - -if Data:IsBCC() then - L[#L+1] = {LABEL = "Spell Haste"} - L[#L].COLOR = "MAGIC_HASTE" - L[#L].MAP = { - { - INPUT = "I[mn][pc]r[oe][va]s?es ?y?o?u?r? spell haste rating by (%d+)", - OUTPUT = "+%d Spell Haste Rating", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Spell Haste Rating.*", - } -end - -L[#L+1] = {LABEL = "Spell Penetration"} -L[#L].COLOR = "MAGIC_PEN" -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "I[mn][pc]r[oe][va]s?es ?y?o?u?r? spell penetration by (%d+)", - OUTPUT = "+%d Spell Pen", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Spell Pen.*", - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Decreases the magical resistances of your spell targets by (%d+)", - OUTPUT = "+%d Spell Pen", - }, - } - L[#L].CAPTURES = { - "[%+%-]%d+ Spell Pen.*", - } -end - - - - - --- ██████╗ ███████╗███████╗ ██████╗ ██╗ ██╗██████╗ ██████╗███████╗███████╗ --- ██╔══██╗██╔════╝██╔════╝██╔═══██╗██║ ██║██╔══██╗██╔════╝██╔════╝██╔════╝ --- ██████╔╝█████╗ ███████╗██║ ██║██║ ██║██████╔╝██║ █████╗ ███████╗ --- ██╔══██╗██╔══╝ ╚════██║██║ ██║██║ ██║██╔══██╗██║ ██╔══╝ ╚════██║ --- ██║ ██║███████╗███████║╚██████╔╝╚██████╔╝██║ ██║╚██████╗███████╗███████║ --- ╚═╝ ╚═╝╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝╚══════╝ - - -L[#L+1] = {LABEL = "Health Restore"} -L[#L].COLOR = "HEALTH" -L[#L].MAP = { - { - INPUT = "Restores (%d+) health per (%d+) sec", - OUTPUT = function(amount, period) return ("+%d Hp%d%s"):format(amount, period, tonumber(period) > 1 and (" (+%s HpM)"):format(Data:Round(amount/period*60, 0)) or "") end, - } -} -L[#L].CAPTURES = { - "[%+%-]%d+ Hp%d.*", -} - -L[#L+1] = {LABEL = "Mana Restore"} -L[#L].COLOR = "MANA" -L[#L].MAP = { - { - INPUT = "Restores (%d+) mana per (%d+) seco?n?d?s?", - OUTPUT = function(amount, period) return ("+%d Mp%d%s"):format(amount, period, tonumber(period) > 1 and (" (+%s MpM)"):format(Data:Round(amount/period*60, 0)) or "") end, - } -} -L[#L].CAPTURES = { - "[%+%-]%d+ Mp%d.*", -} - -L[#L+1] = {LABEL = "Mana Regen"} -L[#L].COLOR = "MANA" -L[#L].MAP = { - { - INPUT = "Allows? (%d+)%% of your Mana regeneration to continue while casting", - OUTPUT = "+%d%%%% of Mana Regen continues while casting", - }, -} -L[#L].CAPTURES = { - "[%+%-]%d+ of Mana Regen continues while casting.*", -} - - - - - - - - - - --- ███╗ ███╗ ██████╗ ██╗ ██╗███████╗███████╗██████╗ ███████╗███████╗██████╗ --- ████╗ ████║██╔═══██╗██║ ██║██╔════╝██╔════╝██╔══██╗██╔════╝██╔════╝██╔══██╗ --- ██╔████╔██║██║ ██║██║ ██║█████╗ ███████╗██████╔╝█████╗ █████╗ ██║ ██║ --- ██║╚██╔╝██║██║ ██║╚██╗ ██╔╝██╔══╝ ╚════██║██╔═══╝ ██╔══╝ ██╔══╝ ██║ ██║ --- ██║ ╚═╝ ██║╚██████╔╝ ╚████╔╝ ███████╗███████║██║ ███████╗███████╗██████╔╝ --- ╚═╝ ╚═╝ ╚═════╝ ╚═══╝ ╚══════╝╚══════╝╚═╝ ╚══════╝╚══════╝╚═════╝ - - - -L[#L+1] = {LABEL = "Shapeshift Run Speed"} -L[#L].MAP = { - { - INPUT = "Increases your movement speed by (%d+)%% while in Bear Form, Cat Form, or Travel Form", - OUTPUT = "+%d%%%% Run Speed in Bear Form, Cat Form, or Travel Form", - }, - { - INPUT = "Increases the speed of your Ghost Wolf ability by (%d+)%%", - OUTPUT = "+%d%%%% Run Speed in Ghost Wolf", - }, -} -L[#L].CAPTURES = { - "%+%d+%%? Run Speed in Bear Form, Cat Form, or Travel Form.*", - "%+%d+%%? Run Speed in Ghost Wolf.*", -} - -L[#L+1] = {LABEL = "Run Speed"} -L[#L].MAP = { - { - INPUT = "Minor Speed Increase", - OUTPUT = "+8%%%% Run Speed", - }, - { - INPUT = "Minor Speed and %+(%d+) (.*)", - OUTPUT = "+8%%%% Run Speed and +%d %s", - }, - { - INPUT = "Minor increase to running and swimming speed", - OUTPUT = "+8%%%% Run Speed and +8%%%% Swim Speed", - }, - { - INPUT = "Increases run speed by (%d+)%%", - OUTPUT = "+%d%%%% Run Speed", - }, - { - INPUT = "Run speed increased slightly", - OUTPUT = "+8%%%% Run Speed", - }, -} -L[#L].CAPTURES = { - "%+%d+%%? Run Speed.*", -} - -L[#L+1] = {LABEL = "Swim Speed"} -L[#L].MAP = { - { - INPUT = "Increases swim speed by ([%d%.]*%d+%%?)", - OUTPUT = function(amount) return ("+%s Swim Speed"):format(FixPercent(amount)) end, - } -} -L[#L].CAPTURES = { - "%+%d+%%? Swim Speed.*", -} - -L[#L+1] = {LABEL = "Mount Speed"} -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "Increases mount speed by ([%d%.]*%d+%%?)", - OUTPUT = function(amount) return ("+%s Mount Speed"):format(FixPercent(amount)) end, - }, - { - INPUT = "Increases speed in Flight Form and Swift Flight Form by ([%d%.]*%d+%%?)", - OUTPUT = function(amount) return ("+%s Speed in Flight Forms"):format(FixPercent(amount)) end, - }, - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Increases mount speed by ([%d%.]*%d+%%?)", - OUTPUT = function(amount) return ("+%s Mount Speed"):format(FixPercent(amount)) end, - }, - { - INPUT = "^Mithril Spurs$", - OUTPUT = "+4%%%% Mount Speed", - }, - { - INPUT = "^Minor Mount Speed Increase$", - OUTPUT = "+2%%%% Mount Speed", - }, - { - INPUT = "Attaches spurs to your boots that increase your mounted movement speed slightly", - OUTPUT = "+4%%%% Mount Speed when attached to boots", - }, - } -end -L[#L].CAPTURES = { - "%+%d+%%? Mount Speed.*", - "%+%d+%%? Speed in Flight Forms.*", -} - - - - - - - - - --- ███████╗ ██████╗ ██████╗ ██████╗ ██╗ ██████╗ ██████╗ ██╗███╗ ██╗██╗ ██╗ --- ██╔════╝██╔═══██╗██╔═══██╗██╔══██╗ ██║ ██╔══██╗██╔══██╗██║████╗ ██║██║ ██╔╝ --- █████╗ ██║ ██║██║ ██║██║ ██║ ████████╗ ██║ ██║██████╔╝██║██╔██╗ ██║█████╔╝ --- ██╔══╝ ██║ ██║██║ ██║██║ ██║ ██╔═██╔═╝ ██║ ██║██╔══██╗██║██║╚██╗██║██╔═██╗ --- ██║ ╚██████╔╝╚██████╔╝██████╔╝ ██████║ ██████╔╝██║ ██║██║██║ ╚████║██║ ██╗ --- ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ - - -L[#L+1] = {LABEL = "Food And Drink"} -L[#L].MAP = { - { - INPUT = "Restores (%d+) health and (%d+) mana over (%d+) sec%.%s*Must remain seated while eating", - OUTPUT = function(healthAmount, manaAmount, duration) return ("+%d health (+%s HpS) and +%d mana (+%s MpS) over %ds while sitting"):format(healthAmount, Data:Round(healthAmount/duration, 0), manaAmount, Data:Round(manaAmount/duration, 0), duration) end, - }, -} -L[#L].CAPTURES = { - "%+%d+ health and %+%d+ mana over %d+s %(%+[%d%.]+ HpS% and %+[%d%.]+ MpS%) while sitting", -} - -L[#L+1] = {LABEL = "Buff Food"} -L[#L].MAP = { - { - INPUT = "Restores (%d+) health over (%d+) sec%.%s*Must remain seated while eating.%s+If you spend at least 10 seconds eating you will become well fed and gain (.+) for (%d+) min", - OUTPUT = function(amount, duration, buff, buffDuration) return ("+%d health (+%s HpS) over %ds while sitting. After 10s, gain %s for %dm"):format(amount, Data:Round(amount/duration, 0), duration, buff, buffDuration) end, - }, -} -L[#L].CAPTURES = { - "%+%d+ health %(%+[%d%.]+ HpS%) over %d+s while sitting%. After %d+s, gain .+ for %d+s", -} - -L[#L+1] = {LABEL = "Food"} -L[#L].COLOR = "HEALTH" -L[#L].MAP = { - { - INPUT = "Restores (%d+) health over (%d+) sec%.%s*Must remain seated while eating", - OUTPUT = function(amount, duration) return ("+%d health (+%s HpS) over %ds while sitting"):format(amount, Data:Round(amount/duration, 0), duration) end, - }, -} -L[#L].CAPTURES = { - "%+%d+ health %(%+[%d%.]+ HpS%) over %d+s while sitting", -} - -L[#L+1] = {LABEL = "Buff Drink"} -L[#L].MAP = { - { - INPUT = "Restores (%d+) mana over (%d+) sec%.%s*Must remain seated while drinking.%s+ Also (.+) for (%d+) min", - OUTPUT = function(amount, duration, buff, buffDuration) return ("+%d mana (+%s HpS) over %ds while sitting. Also %s for %dm"):format(amount, Data:Round(amount/duration, 0), duration, buff, buffDuration) end, - }, -} -L[#L].CAPTURES = { - "%+%d+ health %(%+[%d%.]+ HpS%) over %d+s while sitting%. Also .+ for %d+s", -} - -L[#L+1] = {LABEL = "Drink"} -L[#L].COLOR = "MANA" -L[#L].MAP = { - { - INPUT = "Restores (%d+) mana over (%d+) sec%.%s*Must remain seated while drinking", - OUTPUT = function(amount, duration) return ("+%d mana (+%s MpS) over %ds while sitting"):format(amount, Data:Round(amount/duration, 0), duration) end, - }, -} -L[#L].CAPTURES = { - "%+%d+ mana %(%+[%d%.]+ MpS%) over %d+s while sitting", -} - -L[#L+1] = {LABEL = "Bandage"} -L[#L].COLOR = "HEALTH" -L[#L].MAP = { - { - INPUT = "Heals (%d+) damage over (%d+) sec", - OUTPUT = function(amount, duration) return ("+%d health (+%s HpS) over %ds"):format(amount, Data:Round(amount/duration, 0), duration) end, - }, -} -L[#L].CAPTURES = { - "%+%d+ health %(%+[%d%.]+ HpS%) over %d+s", -} - - - -L[#L+1] = {LABEL = "Instant Mana and Health"} -L[#L].MAP = { - { - INPUT = "Restores? (%d+) to (%d+) mana and health", - OUTPUT = function(amount1, amount2) return ("+%s (%d-%d) mana and health"):format(Data:Round((amount1+amount2)/2, 0), amount1, amount2) end, - }, - { - INPUT = "Restores? (%d+) mana and health", - OUTPUT = "+%d mana and health", - }, -} -L[#L].CAPTURES = { - "%+%d+ %(%d+%-%d+%) mana and health.*", - "%+%d+%%? mana and health.*", -} - -L[#L+1] = {LABEL = "Instant Health"} -L[#L].COLOR = "HEALTH" -L[#L].MAP = { - { - INPUT = "Restores? (%d+) to (%d+) health", - OUTPUT = function(amount1, amount2) return ("+%s (%d-%d) health"):format(Data:Round((amount1+amount2)/2, 0), amount1, amount2) end, - }, - { - INPUT = "Restores? (%d+) health", - OUTPUT = "+%d health", - }, -} -L[#L].CAPTURES = { - "%+%d+ %(%d+%-%d+%) health.*", - "%+%d+%%? health.*", -} - -L[#L+1] = {LABEL = "Instant Mana"} -L[#L].COLOR = "MANA" -L[#L].MAP = { - { - INPUT = "Restores? (%d+) to (%d+) mana", - OUTPUT = function(amount1, amount2) return ("+%s (%d-%d) mana"):format(Data:Round((amount1+amount2)/2, 0), amount1, amount2) end, - }, - { - INPUT = "Restores? (%d+) mana", - OUTPUT = "+%d mana", - }, -} -L[#L].CAPTURES = { - "%+%d+ %(%d+%-%d+%) mana.*", - "%+%d+%%? mana.*", -} - -L[#L+1] = {LABEL = "Instant Resource"} -L[#L].MAP = { - { - INPUT = "Regain up to (%d+%%?) ", - OUTPUT = function(amount) return ("+%s instant "):format(FixPercent(amount)) end, - }, - { - INPUT = "Gain up to (%d+%%?) ", - OUTPUT = function(amount) return ("+%s instant "):format(FixPercent(amount)) end, - }, - { - INPUT = "Instantly increases your (.+) by (%d+%%?)", - OUTPUT = function(resource, amount) return ("+%s instant %s"):format(FixPercent(amount), resource) end, - }, - { - INPUT = "Restores? (%d+) to (%d+) ", - OUTPUT = "+%d to +%d instant ", - }, - { - INPUT = "Restores? (%d+) ", - OUTPUT = "+%d instant ", - }, -} -L[#L].CAPTURES = { - "%+%d+%%? instant .*", - "%+%d+%%? to %+%d+%%? instant .*", -} - - - - - - - --- ███████╗██████╗ ███████╗ ██████╗██╗ █████╗ ██╗ ███████╗███████╗███████╗███████╗ ██████╗████████╗███████╗ --- ██╔════╝██╔══██╗██╔════╝██╔════╝██║██╔══██╗██║ ██╔════╝██╔════╝██╔════╝██╔════╝██╔════╝╚══██╔══╝██╔════╝ --- ███████╗██████╔╝█████╗ ██║ ██║███████║██║ █████╗ █████╗ █████╗ █████╗ ██║ ██║ ███████╗ --- ╚════██║██╔═══╝ ██╔══╝ ██║ ██║██╔══██║██║ ██╔══╝ ██╔══╝ ██╔══╝ ██╔══╝ ██║ ██║ ╚════██║ --- ███████║██║ ███████╗╚██████╗██║██║ ██║███████╗ ███████╗██║ ██║ ███████╗╚██████╗ ██║ ███████║ --- ╚══════╝╚═╝ ╚══════╝ ╚═════╝╚═╝╚═╝ ╚═╝╚══════╝ ╚══════╝╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚══════╝ - - - - -L[#L+1] = {LABEL = "Skill"} -L[#L].COLOR = "SKILL" -L[#L].MAP = { - { - INPUT = "^(Mining) %+(%d+)", - OUTPUT = function(skill, amount) return ("+%d %s skill"):format(amount, skill) end, - }, - { - INPUT = "^(Herbalism) %+(%d+)", - OUTPUT = function(skill, amount) return ("+%d %s skill"):format(amount, skill) end, - }, - { - INPUT = "^(Skinning) %+(%d+)", - OUTPUT = function(skill, amount) return ("+%d %s skill"):format(amount, skill) end, - }, - { - INPUT = "^%+(%d+) (Fishing)", - OUTPUT = function(amount, skill) return ("+%d %s skill"):format(amount, skill) end, - }, - { - INPUT = "^%+(%d+) (Herbalism)", - OUTPUT = function(amount, skill) return ("+%d %s skill"):format(amount, skill) end, - }, - { - INPUT = "^%+(%d+) (Mining)", - OUTPUT = function(amount, skill) return ("+%d %s skill"):format(amount, skill) end, - }, - { - INPUT = "^%+(%d+) (Skinning)", - OUTPUT = function(amount, skill) return ("+%d %s skill"):format(amount, skill) end, - }, - { - INPUT = "^Increased ([%u][%a%-%s]+) %+(%d+)", - OUTPUT = function(skill, amount) return ("+%d %s skill"):format(amount, skill) end, - }, - { - INPUT = "^Increases your lockpicking skill slightly", - OUTPUT = "+5 Lockpicking skill", - }, - { - INPUT = "^Truesilver Line$", - OUTPUT = "+3 Fishing skill", - }, - { - INPUT = "^Eternium Line$", - OUTPUT = "+5 Fishing skill", - }, - { - INPUT = "Replaces the fishing line on your fishing pole with a delicately spun truesilver line", - OUTPUT = "+3 Fishing skill when applied to a fishing pole", - }, - { - INPUT = "Replaces the fishing line on your fishing pole with a high test eternium line", - OUTPUT = "+5 Fishing skill when applied to a fishing pole", - }, -} -L[#L].CAPTURES = { - "[%+%-]%d+ .+ skill.*", -} - -L[#L+1] = {LABEL = "Hit With Ability"} -L[#L].MAP = { - { - INPUT = "Reduces the chance (%D-) will be resisted by (%d+%%)", - OUTPUT = function(spell, amount) return ("+%s Hit Chance with %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Improves your chance to hit with (%D-) by (%d+%%)", - OUTPUT = function(spell, amount) return ("+%s Hit Chance with %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "[%+%-]%d+ Hit Chance with .*", -} - - -L[#L+1] = {LABEL = "Crit With Ability"} -L[#L].MAP = { - { - INPUT = "Increases the critical strike chance of (%D-) by (%d+%%)", - OUTPUT = function(spell, amount) return ("+%s Crit Chance with %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Increases the critical hit chance of (%D-) by (%d+%%)", - OUTPUT = function(spell, amount) return ("+%s Crit Chance with %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Increases the critical hit chance of (%D-) (%d+%%)", - OUTPUT = function(spell, amount) return ("+%s Crit Chance with %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Increases your chance of a critical hit with (%D-) by (%d+%%)", - OUTPUT = function(spell, amount) return ("+%s Crit Chance with %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Improves your chance to get a critical strike with (%D-) by (%d+%%)", - OUTPUT = function(spell, amount) return ("+%s Crit Chance with %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Your (%D-) has (%d+%%) increased critical strike chance", - OUTPUT = function(spell, amount) return ("+%s Crit Chance with %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "[%+%-]%d+ Crit Chance with .*", -} - - - - - - -L[#L+1] = {LABEL = "Increase Pet Damage"} -L[#L].MAP = { - { - INPUT = "(%d+%%) increased damage from your summoned pets' melee attacks and damage spells", - OUTPUT = function(amount) return ("+%s pet Damage"):format(FixPercent(amount)) end, - }, - { - INPUT = "Increases? your pet's damage by (%d+%%?)", - OUTPUT = function(amount) return ("+%s pet Damage"):format(FixPercent(amount)) end, - }, - { - INPUT = "Increases? damage dealt by your pet by (%d+%%?)", - OUTPUT = function(amount) return ("+%s pet Damage"):format(FixPercent(amount)) end, - }, -} -L[#L].CAPTURES = { - "[%+%-]%S* pet Damage.*", -} - - -L[#L+1] = {LABEL = "Increase Pet Critical Chance"} -L[#L].MAP = { - { - INPUT = "Increases? your pet's critical strike chance by (%d+%%?)", - OUTPUT = function(amount) return ("+%s pet Crit Chance"):format(FixPercent(amount)) end, - }, -} -L[#L].CAPTURES = { - "[%+%-]%S* pet Crit Chance.*", -} - - -L[#L+1] = {LABEL = "Pet Defences"} -L[#L].MAP = { - { - INPUT = "Your pet gains (%d+) stamina and (%d+) spell resistance against all schools of magic%.?$", - OUTPUT = function(amount1, amount2) return ("+%s pet Stamina and +%s pet Resist All"):format(amount1, amount2) end, - }, - { - INPUT = "Increases your pet's stamina by (%d+%%?) and all spell resistances by (%d+%%?)%.?$", - OUTPUT = function(amount1, amount2) return ("+%s pet Stamina and +%s pet Resist All"):format(amount1, amount2) end, - }, -} -L[#L].CAPTURES = { - "%+%d+ pet Stamina and %+%d+ pet Resist All", -} - - - - -L[#L+1] = {LABEL = "Proc Spellpower"} -L[#L].MAP = { - { - INPUT = "Chance on (%D-) to increase your damage and healing done by magical spells and effects by up to (%d+) for (%d+) sec%.?$", - OUTPUT = function(trigger, amount1, amount2) return ("Chance on %s for +%d Spell Power for %ds"):format(trigger, amount1, amount2) end, - }, - { - INPUT = "Chance on (%D-) to increase your damage and healing by up to (%d+) for (%d+) sec%.?$", - OUTPUT = function(trigger, amount1, amount2) return ("Chance on %s for +%d Spell Power for %ds"):format(trigger, amount1, amount2) end, - }, -} -L[#L].CAPTURES = { - "Chance on .+ for %+%d+ Spell Power for %d+s", -} - - - - - - -L[#L+1] = {LABEL = "Increase Maximum Resource"} -L[#L].MAP = { - { - INPUT = "Increases your maximum (%D-) by (%d+%%?)%.?$", - OUTPUT = function(resource, amount) return ("+%s maximum %s"):format(FixPercent(amount), resource) end, - }, -} -L[#L].CAPTURES = { - "%+%d+ maximum .*", -} - - - - - - -L[#L+1] = {LABEL = "Reduce Cost"} -L[#L].MAP = { - { - INPUT = "Reduces ?t?h?e? (%D*)cost of (%D-) by (%d+%%?)", - OUTPUT = function(resource, spell, amount) return ("-%s %scost for %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "Decreases? ?t?h?e? (%D*)cost of (%D-) by (%d+%%?)", - OUTPUT = function(resource, spell, amount) return ("-%s %scost for %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "Your (%D-) each costs? (%d+%%?) less ([mre][aan][nge][aer]g?y?)", - OUTPUT = function(spell, amount, resource) return ("-%s %s cost for %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "Your (%D-) costs? (%d+%%?) less ([mre][aan][nge][aer]g?y?)", - OUTPUT = function(spell, amount, resource) return ("-%s %s cost for %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "All of your (%D-) costs? (%d+%%?) less ([mre][aan][nge][aer]g?y?)", - OUTPUT = function(spell, amount, resource) return ("-%s %s cost for %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "(%D+) cost of (%D-) reduced by (%d+%%?)", - OUTPUT = function(resource, spell, amount) return ("-%s %s cost for %s"):format(FixPercent(amount), resource:lower(), TrimSpell(spell)) end, - }, - { - INPUT = "%-(%d+) (%D-) cost to ([%a%s]+)", - OUTPUT = function(amount, resource, spell) return ("-%s %s cost for %s"):format(FixPercent(amount), resource:lower(), TrimSpell(spell)) end, - }, - { - INPUT = "%-(%d+) (%D-) cost for ([%a%s]+)", - OUTPUT = function(amount, resource, spell) return ("-%s %s cost for %s"):format(FixPercent(amount), resource:lower(), TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "%-%d+%%? cost for .*", -} - -L[#L+1] = {LABEL = "Cooldown Reduction"} -L[#L].MAP = { - { - INPUT = "Reduces ?t?h?e? cooldown o[fn] (%D-) by (%d+) seco?n?d?s?", - OUTPUT = function(spell, amount) return ("-%ss cooldown on %s"):format(amount, TrimSpell(spell)) end, - }, - { - INPUT = "Decreases ?t?h?e? cooldown o[fn] (%D-) by (%d+) seco?n?d?s?", - OUTPUT = function(spell, amount) return ("-%ss cooldown on %s"):format(amount, TrimSpell(spell)) end, - }, - { - INPUT = "Reduces ?t?h?e? cooldown o[fn] (%D-) by %-?(%d+) minu?t?e?s?", - OUTPUT = function(spell, amount) return ("-%sm cooldown on %s"):format(amount, TrimSpell(spell)) end, - }, - { - INPUT = "Reduces ?t?h?e? cooldown o[fn] (%D-) by (%d+%%)", - OUTPUT = function(spell, amount) return ("-%s cooldown on %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Decreases ?t?h?e? cooldown o[fn] (%D-) by (%d+%%)", - OUTPUT = function(spell, amount) return ("-%s cooldown on %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "%-[%d%.]+%%? cooldown on .*", -} - -L[#L+1] = {LABEL = "Increase Damage"} -L[#L].MAP = { - { - INPUT = "Increases your (%D-) damage against (%D+) by (%d+%%?)", - OUTPUT = function(spell, targets, amount) return ("+%s damage for %s against %s"):format(FixPercent(amount), TrimSpell(spell), targets) end, - }, - { - INPUT = "Increases your damage against (%D+) by (%d+%%?)", - OUTPUT = function(targets, amount) return ("+%s damage against %s"):format(FixPercent(amount), targets) end, - }, - { - INPUT = "Increases the damage dealt by (%D-) by (%d+%%?)", - OUTPUT = function(spell, amount) return ("+%s damage for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Increases damage caused by (%D-) by (%d+%%?)", - OUTPUT = function(spell, amount) return ("+%s damage for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Increases the damage from (%D-) by (%d+%%?)", - OUTPUT = function(spell, amount) return ("+%s damage for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Increases the damage of (%D-) by (%d+%%?)", - OUTPUT = function(spell, amount) return ("+%s damage for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Increases the damage done by (%D-) by (%d+%%?)", - OUTPUT = function(spell, amount) return ("+%s damage for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Your (%D-) deals? (%d+%%?) more damage", - OUTPUT = function(spell, amount) return ("+%s damage for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "(%d+%%?) increased damage [to][on] (%D+)", - OUTPUT = function(amount, spell) return ("+%s damage for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "%+%d+%%? damage for .+", - "%+%d+%%? damage against .+", -} - -L[#L+1] = {LABEL = "Increase Healing"} -L[#L].MAP = { - { - INPUT = "Your (%D-) heals an additional (%d+) health", - OUTPUT = function(spell, amount) return ("+%s healing for %s"):format(amount, TrimSpell(spell)) end, - }, - { - INPUT = "Increases the healing from (%D-) by (%d+%%?)", - OUTPUT = function(spell, amount) return ("+%s healing for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Increases the amount healed by (%D-) by (%d+%%?)", - OUTPUT = function(spell, amount) return ("+%s healing for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Increases healing done by (%D-) by up to (%d+%%?)", - OUTPUT = function(spell, amount) return ("+%s healing for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "%+%d+%%? healing for .+", -} - - - - -L[#L+1] = {LABEL = "Modify Threat"} -L[#L].MAP = { - { - INPUT = "Increases the threat generated by (%D-) by (%d+%%?)", - OUTPUT = function(spell, amount) return ("+%s threat from %s"):format(FixPercent(amount), spell) end, - }, - { - INPUT = "Decreases the threat generated by your spells by (%d+%%?)", - OUTPUT = function(amount) return ("-%s threat from spells"):format(FixPercent(amount)) end, - }, - { - INPUT = "Reduces the threat generated by (%D-) by (%d+%%?)", - OUTPUT = function(spell, amount) return ("-%s threat from %s"):format(FixPercent(amount), spell) end, - }, - { - INPUT = "Reduces the threat you generate by (%d+%%)", - OUTPUT = function(amount) return ("-%s threat generated"):format(FixPercent(amount)) end, - }, -} -L[#L].CAPTURES = { - "[%+%-]%d+%%? threat from .*", - "[%+%-]%d+%%? threat generated.*", -} - - -L[#L+1] = {LABEL = "Pushback Resist"} -L[#L].MAP = { - { - INPUT = "Gives you a (%d-%%) chance to avoid interruption caused by damage while casting ([%a%s]+)", - OUTPUT = function(amount, spell) return ("+%s Spell Pushback Resist for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "%+%d+%% Spell Pushback Resist for .*", -} - -L[#L+1] = {LABEL = "Increase Duration"} -L[#L].MAP = { - { - INPUT = "Increases the duration of (%D-) by (%d+%%)", - OUTPUT = function(spell, amount) return ("+%s duration for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "I[mn][pc]r[oe][va]s?es the duration of (%D-) by (%d+) sec?o?n?d?s?%.?$", - OUTPUT = function(spell, amount) return ("+%ss duration for %s"):format(amount, TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "%+%d+[%s%a%%]* duration for .+", -} - -L[#L+1] = {LABEL = "Reduce Cast Time"} -L[#L].MAP = { - { - INPUT = "%-([%d%.]+) seco?n?d?s? [to][on] ?t?h?e? casting time of (%D+)", - OUTPUT = function(amount, spell) return ("-%ss cast time for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Reduces ?t?h?e? casti?n?g? time o[fn] (%D-) by ([%d%.]+%%?) seco?n?d?s?", - OUTPUT = function(spell, amount) return ("-%ss cast time for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "%-[%d%.]+%%? cast time for .*", -} - -L[#L+1] = {LABEL = "Increase Attack Speed"} -L[#L].MAP = { - { - INPUT = "Increases ranged attack speed by (%d+%%)", - OUTPUT = function(amount) return ("+%s Ranged Attack Speed"):format(FixPercent(amount)) end, - }, - { - INPUT = "Increases your attack speed by (%d+%%)", - OUTPUT = function(amount) return ("+%s Attack Speed"):format(FixPercent(amount)) end, - }, -} -L[#L].CAPTURES = { - "%+%d+%% Ranged Attack Speed.*", - "%+%d+%% Attack Speed.*", -} - -L[#L+1] = {LABEL = "Increase Range"} -L[#L].MAP = { - { - INPUT = "I[mn][pc]r[oe][va]s?es the range of (%D-) by (%d+) ya?r?ds", - OUTPUT = function(spell, amount) return ("+%sy range for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "%+%d+y range for .*", -} - -L[#L+1] = {LABEL = "Increase Radius"} -L[#L].MAP = { - { - INPUT = "Increases ?t?h?e? radius of (%D-) by (%d+%%?)", - OUTPUT = function(spell, amount) return ("+%s radius for %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "%+%d+%%? radius for .*", -} - -L[#L+1] = {LABEL = "Resist Silence or Interrupt"} -if Data:IsBCC() then - L[#L].MAP = { - { - INPUT = "Reduces the duration of any Silence or Interrupt effects used against the wearer by (%d+%%)%. This effect does not stack with other similar effects", - OUTPUT = function(amount) return ("-%s duration to incoming Silence and Interrupt effects. Does not stack with similar effects."):format(FixPercent(amount)) end, - }, - } - L[#L].CAPTURES = { - "%-%d+%% duration to incoming Silence and Interrupt effects%. Does not stack with similar effects%..*", - } -elseif Data:IsClassic() then - L[#L].MAP = { - { - INPUT = "Increases your resistance to [Ss]ilence ?e?f?f?e?c?t?s? by (%d+%%)", - OUTPUT = function(amount) return ("+%s Resistance to Silence effects"):format(FixPercent(amount)) end, - }, - } - L[#L].CAPTURES = { - "%+%d+%% Resistance to Silence effects.*", - } -end - -L[#L+1] = {LABEL = "Increase Absorb"} -L[#L].MAP = { - { - INPUT = "Increases the amount of %D- absorbed by (%D-) by (%d+%%?)", - OUTPUT = function(spell, amount) return ("+%s damage absorbed by %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Increases the %D- absorbed by (%D-) by (%d+%%?)", - OUTPUT = function(spell, amount) return ("+%s damage absorbed by %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "(%d+%%) increase to the ?t?o?t?a?l? damage absorbed by ([%a%s]+%%?)", - OUTPUT = function(amount, spell) return ("+%s damage absorbed by %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "%+%d+%%? damage absorbed by .*", -} - - - - - - -L[#L+1] = {LABEL = "Increase Ability Effectiveness"} -L[#L].MAP = { - { - INPUT = "You gain (%d+%%? additional) (%D-) from ([%a%s]+)", - OUTPUT = function(amount, resource, spell) return ("+%s %s from %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "Your (%D-) generates an additional (%d+) ([mre][aan][nge][aer]g?y?)", - OUTPUT = function(spell, amount, resource) return ("+%s %s generated by %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "Your (%D-) grants an additional (%d+) ([mre][aan][nge][aer]g?y?)", - OUTPUT = function(spell, amount, resource) return ("+%s %s granted by %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "Your (%D-) grants an additional (%d+) spell damage", - OUTPUT = function(spell, amount) return ("+%s Spell Damage granted by %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "Your (%D-) grants an additional (%d+) attack power", - OUTPUT = function(spell, amount) return ("+%s Attack Power granted by %s"):format(FixPercent(amount), TrimSpell(spell)) end, - }, - { - INPUT = "(%D+ gained) from (%D-) increased by (%d+%%?)", - OUTPUT = function(resource, spell, amount) return ("+%s %s from %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "Increases the (%D- bonus) [of][fr]om (%D-) by (%d+%%?)", - OUTPUT = function(resource, spell, amount) return ("+%s %s from %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "Increases the (%D- gained) from (%D-) by (%d+%%?)", - OUTPUT = function(resource, spell, amount) return ("+%s %s from %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "Increases the (%D- granted) by (%D-) by (%d+%%?)", - OUTPUT = function(resource, spell, amount) return ("+%s %s from %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "Increases the (%D-) from your (%D-) by (%d+%%?)", - OUTPUT = function(resource, spell, amount) return ("+%s %s from %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, - { - INPUT = "I[mn][pc]r[oe][va]s?es the (%D-) of (%D-) by (%d+%%?)", - OUTPUT = function(resource, spell, amount) return ("+%s %s for %s"):format(FixPercent(amount), resource, TrimSpell(spell)) end, - }, -} -L[#L].CAPTURES = { - "%+%d+%%? .+ from .*", - "%+%d+%%? .+ for .*", - "%+%d+%%? .+ generated by .*", - "%+%d+%%? .+ absorbed by .*", -} - - - -for k, v in pairs(L) do - locale[k] = v -end diff --git a/Locale/locale.xml b/Locale/locale.xml new file mode 100644 index 0000000..28cb90f --- /dev/null +++ b/Locale/locale.xml @@ -0,0 +1,4 @@ +