diff --git a/ElvUI/Modules/Nameplates/Nameplates.lua b/ElvUI/Modules/Nameplates/Nameplates.lua
index 9025637..7a3df37 100644
--- a/ElvUI/Modules/Nameplates/Nameplates.lua
+++ b/ElvUI/Modules/Nameplates/Nameplates.lua
@@ -228,8 +228,28 @@ function NP:GetUnitClassByGUID(frame, guid)
end
end
+local grenColorToClass = {}
+for class, color in pairs(RAID_CLASS_COLORS) do
+ grenColorToClass[color.g] = class
+end
+
function NP:UnitClass(frame, unitType)
- return "DRUID"
+ if frame._class then
+ return frame._class
+ end
+ if unitType == "FRIENDLY_PLAYER" then
+ if frame.unit then
+ local _, class = UnitClass(frame.unit)
+ if class then
+ return class
+ end
+ else
+ return NP:GetUnitClassByGUID(frame, frame.guid)
+ end
+ elseif unitType == "ENEMY_PLAYER" then
+ local _, g = frame.oldHealthBar:GetStatusBarColor()
+ return grenColorToClass[floor(g*100 + 0.5) / 100]
+ end
end
function NP:UnitDetailedThreatSituation(frame)
diff --git a/ElvUI_Enhanced/Config/Config.lua b/ElvUI_Enhanced/Config/Config.lua
new file mode 100644
index 0000000..3343488
--- /dev/null
+++ b/ElvUI_Enhanced/Config/Config.lua
@@ -0,0 +1,2015 @@
+local E, L, V, P, G = unpack(ElvUI)
+local EE = E:GetModule("ElvUI_Enhanced")
+
+local function GeneralOptions()
+ local M = E:GetModule("Enhanced_Misc")
+
+ return {
+ type = "group",
+ name = L["General"],
+ get = function(info) return E.db.enhanced.general[info[#info]] end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = EE:ColorizeSettingName(L["General"])
+ },
+ pvpAutoRelease = {
+ type = "toggle",
+ name = L["PvP Autorelease"],
+ desc = L["Automatically release body when killed inside a battleground."],
+ set = function(info, value)
+ E.db.enhanced.general[info[#info]] = value
+ M:AutoRelease()
+ end
+ },
+ autoRepChange = {
+ type = "toggle",
+ name = L["Track Reputation"],
+ desc = L["Automatically change your watched faction on the reputation bar to the faction you got reputation points for."],
+ set = function(info, value)
+ E.db.enhanced.general[info[#info]] = value
+ M:WatchedFaction()
+ end
+ },
+ selectQuestReward = {
+ type = "toggle",
+ name = L["Select Quest Reward"],
+ desc = L["Automatically select the quest reward with the highest vendor sell value."],
+ get = function(info) return E.private.general[info[#info]] end,
+ set = function(info, value)
+ E.private.general[info[#info]] = value
+ M:ToggleQuestReward()
+ end
+ },
+ declineduel = {
+ type = "toggle",
+ name = L["Decline Duel"],
+ desc = L["Auto decline all duels"],
+ set = function(info, value)
+ E.db.enhanced.general[info[#info]] = value
+ M:DeclineDuel()
+ end
+ },
+ hideZoneText = {
+ type = "toggle",
+ name = L["Hide Zone Text"],
+ set = function(info, value)
+ E.db.enhanced.general[info[#info]] = value
+ M:HideZone()
+ end
+ },
+ alreadyKnown = {
+ type = "toggle",
+ name = L["Already Known"],
+ desc = L["Change color of item icons which already known."],
+ set = function(info, value)
+ E.db.enhanced.general[info[#info]] = value
+ E:GetModule("Enhanced_AlreadyKnown"):ToggleState()
+ end
+ },
+ altBuyMaxStack = {
+ type = "toggle",
+ name = L["Alt-Click Merchant"],
+ desc = L["Holding Alt key while buying something from vendor will now buy an entire stack."],
+ set = function(info, value)
+ E.db.enhanced.general[info[#info]] = value
+ M:BuyStackToggle()
+ end
+ },
+ trainAllSkills = {
+ type = "toggle",
+ name = L["Train All Button"],
+ desc = L["Add button to Trainer frame with ability to train all available skills in one click."],
+ set = function(info, value)
+ E.db.enhanced.general.trainAllSkills = value
+ E:GetModule("Enhanced_TrainAll"):ToggleState()
+ end
+ },
+ showQuestLevel = {
+ type = "toggle",
+ name = L["Show Quest Level"],
+ desc = L["Display quest levels at Quest Log."],
+ set = function(info, value)
+ E.db.enhanced.general.showQuestLevel = value
+ M:QuestLevelToggle()
+ end
+ },
+ dpsLinks = {
+ type = "toggle",
+ name = L["Filter DPS meters Spam"],
+ desc = L["Replaces reports from damage meters with a clickable hyperlink to reduce chat spam"],
+ get = function(info) return E.db.enhanced.chat.dpsLinks end,
+ set = function(info, value)
+ E.db.enhanced.chat.dpsLinks = value
+ E:GetModule("Enhanced_DPSLinks"):UpdateSettings()
+ end
+ },
+ moverTransparancy = {
+ order = -2,
+ type = "range",
+ isPercent = true,
+ name = L["Mover Transparency"],
+ desc = L["Changes the transparency of all the movers."],
+ min = 0, max = 1, step = 0.01,
+ set = function(info, value)
+ E.db.enhanced.general[info[#info]] = value
+ M:UpdateMoverTransparancy()
+ end
+ }
+ }
+ }
+end
+
+local function ActionbarOptions()
+ local KPA = E:GetModule("Enhanced_KeyPressAnimation")
+
+ return {
+ type = "group",
+ name = L["ActionBars"],
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = EE:ColorizeSettingName(L["ActionBars"])
+ },
+ keyPressAnimation = {
+ order = 1,
+ type = "group",
+ name = L["Key Press Animation"],
+ guiInline = true,
+ get = function(info) return E.db.enhanced.actionbar.keyPressAnimation[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.actionbar.keyPressAnimation[info[#info]] = value
+ KPA:UpdateSetting()
+ end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.private.enhanced.actionbar.keyPressAnimation end,
+ set = function(info, value)
+ E.private.enhanced.actionbar.keyPressAnimation = value
+ E:StaticPopup_Show("PRIVATE_RL")
+ end,
+ },
+ color = {
+ order = 2,
+ type = "color",
+ name = L["COLOR"],
+ get = function(info)
+ local t = E.db.enhanced.actionbar.keyPressAnimation[info[#info]]
+ local d = P.enhanced.actionbar.keyPressAnimation[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.enhanced.actionbar.keyPressAnimation[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ KPA:UpdateSetting()
+ end,
+ disabled = function() return not E.private.enhanced.actionbar.keyPressAnimation end,
+ },
+ scale = {
+ order = 3,
+ type = "range",
+ min = 1, max = 3, step = 0.1,
+ isPercent = true,
+ name = L["Scale"],
+ disabled = function() return not E.private.enhanced.actionbar.keyPressAnimation end,
+ },
+ rotation = {
+ order = 4,
+ type = "range",
+ min = 0, max = 360, step = 1,
+ name = L["Rotation"],
+ disabled = function() return not E.private.enhanced.actionbar.keyPressAnimation end,
+ },
+ }
+ }
+ }
+ }
+end
+
+local function BlizzardOptions()
+ local B = E:GetModule("Enhanced_Blizzard")
+ local WF = E:GetModule("Enhanced_WatchFrame")
+ local TAM = E:GetModule("Enhanced_TakeAllMail")
+ local CHAR = E:GetModule("Enhanced_CharacterFrame")
+
+ local choices = {
+ ["NONE"] = L["NONE"],
+ ["COLLAPSED"] = L["Collapsed"],
+ ["HIDDEN"] = L["Hidden"]
+ }
+
+ return {
+ type = "group",
+ childGroups = "tree",
+ name = L["BlizzUI Improvements"],
+ get = function(info) return E.private.enhanced[info[#info]] end,
+ set = function(info, value)
+ E.private.enhanced[info[#info]] = value
+ E:StaticPopup_Show("PRIVATE_RL")
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = EE:ColorizeSettingName(L["BlizzUI Improvements"])
+ },
+ general = {
+ order = 2,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ deathRecap = {
+ order = 2,
+ type = "toggle",
+ name = L["Death Recap Frame"]
+ },
+ takeAllMail = {
+ order = 3,
+ type = "toggle",
+ name = L["Take All Mail"],
+ get = function(info) return E.db.enhanced.blizzard.takeAllMail end,
+ set = function(info, value)
+ E.db.enhanced.blizzard.takeAllMail = value
+ if value and not TAM.initialized then
+ TAM:Initialize()
+ elseif not value then
+ E:StaticPopup_Show("CONFIG_RL")
+ end
+ end
+ },
+ animatedAchievementBars = {
+ order = 4,
+ type = "toggle",
+ name = L["Animated Achievement Bars"]
+ }
+ }
+ },
+ characterFrame = {
+ order = 3,
+ type = "group",
+ name = L["Character Frame"],
+ get = function(info) return E.private.enhanced.character[info[#info]] end,
+ set = function(info, value)
+ E.private.enhanced.character[info[#info]] = value
+ E:StaticPopup_Show("PRIVATE_RL")
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Character Frame"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enhanced Character Frame"]
+ },
+ modelFrames = {
+ order = 3,
+ type = "toggle",
+ name = L["Enhanced Model Frames"]
+ },
+ animations = {
+ order = 4,
+ type = "toggle",
+ name = L["Smooth Animations"],
+ get = function(info) return E.db.enhanced.character.animations end,
+ set = function(info, value)
+ E.db.enhanced.character.animations = value
+ E:StaticPopup_Show("PRIVATE_RL")
+ end,
+ disabled = function() return not E.private.enhanced.character.enable end
+ },
+ paperdollBackgrounds = {
+ order = 5,
+ type = "group",
+ name = L["Paperdoll Backgrounds"],
+ guiInline = true,
+ get = function(info) return E.db.enhanced.character[info[#info]] end,
+ disabled = function() return not E.private.enhanced.character.enable end,
+ args = {
+ characterBackground = {
+ order = 1,
+ type = "toggle",
+ name = L["Character Background"],
+ set = function(info, value)
+ E.db.enhanced.character.characterBackground = value
+ CHAR:UpdateCharacterModelFrame()
+ end
+ },
+ desaturateCharacter = {
+ order = 2,
+ type = "toggle",
+ name = L["Desaturate"],
+ get = function(info) return E.db.enhanced.character.desaturateCharacter end,
+ set = function(info, value)
+ E.db.enhanced.character.desaturateCharacter = value
+ CHAR:UpdateCharacterModelFrame()
+ end,
+ disabled = function() return not E.private.enhanced.character.enable or not E.db.enhanced.character.characterBackground end
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = " "
+ },
+ petBackground = {
+ order = 4,
+ type = "toggle",
+ name = L["Pet Background"],
+ set = function(info, value)
+ E.db.enhanced.character.petBackground = value
+ CHAR:UpdatePetModelFrame()
+ end
+ },
+ desaturatePet = {
+ order = 5,
+ type = "toggle",
+ name = L["Desaturate"],
+ get = function(info) return E.db.enhanced.character.desaturatePet end,
+ set = function(info, value)
+ E.db.enhanced.character.desaturatePet = value
+ CHAR:UpdatePetModelFrame()
+ end,
+ disabled = function() return not E.private.enhanced.character.enable or not E.db.enhanced.character.petBackground end
+ },
+ spacer2 = {
+ order = 6,
+ type = "description",
+ name = " "
+ },
+ inspectBackground = {
+ order = 6,
+ type = "toggle",
+ name = L["Inspect Background"],
+ set = function(info, value)
+ E.db.enhanced.character.inspectBackground = value
+ CHAR:UpdateInspectModelFrame()
+ end
+ },
+ desaturateInspect = {
+ order = 8,
+ type = "toggle",
+ name = L["Desaturate"],
+ get = function(info) return E.db.enhanced.character.desaturateInspect end,
+ set = function(info, value)
+ E.db.enhanced.character.desaturateInspect = value
+ CHAR:UpdateInspectModelFrame()
+ end,
+ disabled = function() return not E.private.enhanced.character.enable or not E.db.enhanced.character.inspectBackground end
+ },
+ spacer3 = {
+ order = 9,
+ type = "description",
+ name = " "
+ },
+ companionBackground = {
+ order = 10,
+ type = "toggle",
+ name = L["Companion Background"],
+ set = function(info, value)
+ E.db.enhanced.character.companionBackground = value
+ CHAR:UpdateCompanionModelFrame()
+ end
+ },
+ desaturateCompanion = {
+ order = 11,
+ type = "toggle",
+ name = L["Desaturate"],
+ get = function(info) return E.db.enhanced.character.desaturateCompanion end,
+ set = function(info, value)
+ E.db.enhanced.character.desaturateCompanion = value
+ CHAR:UpdateCompanionModelFrame()
+ end,
+ disabled = function() return not E.private.enhanced.character.enable or not E.db.enhanced.character.companionBackground end
+ }
+ }
+ }
+ }
+ },
+ dressingRoom = {
+ order = 4,
+ type = "group",
+ name = L["Dressing Room"],
+ get = function(info) return E.db.enhanced.blizzard.dressUpFrame[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.blizzard.dressUpFrame[info[#info]] = value
+ E:GetModule("Enhanced_Blizzard"):UpdateDressUpFrame()
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Dressing Room"],
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value)
+ E.db.enhanced.blizzard.dressUpFrame[info[#info]] = value
+ E:StaticPopup_Show("PRIVATE_RL")
+ end,
+ },
+ multiplier = {
+ order = 3,
+ type = "range",
+ min = 1, max = 2, step = 0.01,
+ isPercent = true,
+ name = L["Scale"],
+ disabled = function() return not E.db.enhanced.blizzard.dressUpFrame.enable end
+ },
+ undressButton = {
+ order = 4,
+ type = "toggle",
+ name = L["Undress Button"],
+ desc = L["Add button to Dressing Room frame with ability to undress model."],
+ get = function(info) return E.db.enhanced.general.undressButton end,
+ set = function(info, value)
+ E.db.enhanced.general.undressButton = value
+ E:GetModule("Enhanced_UndressButtons"):ToggleState()
+ end
+ }
+ }
+ },
+ timerTracker = {
+ order = 5,
+ type = "group",
+ name = L["Timer Tracker"],
+ get = function(info) return E.db.enhanced.timerTracker[info[#info]] end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Timer Tracker"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value)
+ E.db.enhanced.timerTracker.enable = value
+ E:GetModule("Enhanced_TimerTracker"):ToggleState()
+ end
+ },
+ dbm = {
+ order = 3,
+ type = "toggle",
+ name = L["Hook DBM"],
+ set = function(info, value)
+ E.db.enhanced.timerTracker.dbm = value
+ E:GetModule("Enhanced_TimerTracker"):HookDBM()
+ end,
+ disabled = function() return not E.db.enhanced.timerTracker.enable end
+ }
+ }
+ },
+ watchframe = {
+ order = 6,
+ type = "group",
+ name = L["Watch Frame"],
+ get = function(info) return E.db.enhanced.watchframe[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.watchframe[info[#info]] = value
+ WF:UpdateSettings()
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Watch Frame"],
+ },
+ intro = {
+ order = 2,
+ type = "description",
+ name = L["WATCHFRAME_DESC"]
+ },
+ enable = {
+ order = 3,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ settings = {
+ order = 4,
+ type = "group",
+ name = L["Visibility State"],
+ guiInline = true,
+ get = function(info) return E.db.enhanced.watchframe[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.watchframe[info[#info]] = value
+ WF:ChangeState()
+ end,
+ disabled = function() return not E.db.enhanced.watchframe.enable end,
+ args = {
+ city = {
+ order = 1,
+ type = "select",
+ name = L["City (Resting)"],
+ values = choices
+ },
+ pvp = {
+ order = 2,
+ type = "select",
+ name = L["PvP"],
+ values = choices
+ },
+ arena = {
+ order = 3,
+ type = "select",
+ name = L["Arena"],
+ values = choices
+ },
+ party = {
+ order = 4,
+ type = "select",
+ name = L["Party"],
+ values = choices
+ },
+ raid = {
+ order = 5,
+ type = "select",
+ name = L["Raid"],
+ values = choices
+ }
+ }
+ }
+ }
+ },
+ errorFrame = {
+ order = 7,
+ type = "group",
+ name = L["Error Frame"],
+ get = function(info) return E.db.enhanced.blizzard.errorFrame[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.blizzard.errorFrame[info[#info]] = value
+ B:ErrorFrameSize()
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Error Frame"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value)
+ E.db.enhanced.blizzard.errorFrame[info[#info]] = value
+ B:CustomErrorFrameToggle()
+ end
+ },
+ width = {
+ order = 3,
+ type = "range",
+ min = 100, max = 1000, step = 1,
+ name = L["Width"],
+ desc = L["Set the width of Error Frame. Too narrow frame may cause messages to be split in several lines"],
+ disabled = function() return not E.db.enhanced.blizzard.errorFrame.enable end
+ },
+ height = {
+ order = 4,
+ type = "range",
+ min = 30, max = 300, step = 1,
+ name = L["Height"],
+ desc = L["Set the height of Error Frame. Higher frame can show more lines at once."],
+ disabled = function() return not E.db.enhanced.blizzard.errorFrame.enable end
+ },
+ spacer = {
+ order = 5,
+ type = "description",
+ name = " "
+ },
+ font = {
+ order = 6,
+ type = "select",
+ dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font,
+ disabled = function() return not E.db.enhanced.blizzard.errorFrame.enable end
+ },
+ fontSize = {
+ order = 7,
+ type = "range",
+ min = 6, max = 36, step = 1,
+ name = L["FONT_SIZE"],
+ disabled = function() return not E.db.enhanced.blizzard.errorFrame.enable end
+ },
+ fontOutline = {
+ order = 8,
+ type = "select",
+ name = L["Font Outline"],
+ values = {
+ ["NONE"] = L["NONE"],
+ ["OUTLINE"] = "OUTLINE",
+ ["MONOCHROMEOUTLINE"] = "MONOCROMEOUTLINE",
+ ["THICKOUTLINE"] = "THICKOUTLINE"
+ },
+ disabled = function() return not E.db.enhanced.blizzard.errorFrame.enable end
+ }
+ }
+ }
+ }
+ }
+end
+
+local function EquipmentInfoOptions()
+ local EI = E:GetModule("Enhanced_EquipmentInfo")
+
+ return {
+ type = "group",
+ name = L["Equipment Info"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = EE:ColorizeSettingName(L["Equipment Info"])
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ width = "full",
+ name = L["Enable"],
+ get = function(info) return E.db.enhanced.equipment[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.equipment[info[#info]] = value
+ EI:ToggleState()
+ end,
+ },
+ itemlevel = {
+ order = 3,
+ type = "group",
+ guiInline = true,
+ name = L["Item Level"],
+ get = function(info) return E.db.enhanced.equipment.itemlevel[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.equipment.itemlevel[info[#info]] = value
+ EI:UpdateText()
+ end,
+ disabled = function() return not (E.db.enhanced.equipment.enable and E.db.enhanced.equipment.itemlevel.enable) end,
+ args = {
+ info = {
+ order = 1,
+ type = "description",
+ name = L["ITEMLEVEL_DESC"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Enable/Disable the display of item levels on the character screen."],
+ disabled = function() return not E.db.enhanced.equipment.enable end,
+ },
+ qualityColor = {
+ order = 3,
+ type = "toggle",
+ name = L["Quality Color"]
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ position = {
+ order = 5,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["TOP"] = "TOP",
+ ["TOPLEFT"] = "TOPLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT",
+ ["BOTTOM"] = "BOTTOM",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT"
+ },
+ set = function(info, value)
+ E.db.enhanced.equipment.itemlevel[info[#info]] = value
+ EI:UpdateTextSettings()
+ end
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ min = -50, max = 50, step = 1,
+ name = L["X-Offset"],
+ set = function(info, value)
+ E.db.enhanced.equipment.itemlevel[info[#info]] = value
+ EI:UpdateTextSettings()
+ end
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ min = -50, max = 50, step = 1,
+ name = L["Y-Offset"],
+ set = function(info, value)
+ E.db.enhanced.equipment.itemlevel[info[#info]] = value
+ EI:UpdateTextSettings()
+ end
+ }
+ }
+ },
+ durability = {
+ order = 4,
+ type = "group",
+ name = DURABILITY,
+ guiInline = true,
+ get = function(info) return E.db.enhanced.equipment.durability[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.equipment.durability[info[#info]] = value
+ EI:UpdateText()
+ end,
+ disabled = function() return not (E.db.enhanced.equipment.enable and E.db.enhanced.equipment.durability.enable) end,
+ args = {
+ info = {
+ order = 1,
+ type = "description",
+ name = L["DURABILITY_DESC"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Enable/Disable the display of durability information on the character screen."],
+ disabled = function() return not E.db.enhanced.equipment.enable end,
+ },
+ onlydamaged = {
+ order = 3,
+ type = "toggle",
+ name = L["Damaged Only"],
+ desc = L["Only show durabitlity information for items that are damaged."],
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ position = {
+ order = 5,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["TOP"] = "TOP",
+ ["TOPLEFT"] = "TOPLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT",
+ ["BOTTOM"] = "BOTTOM",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT"
+ },
+ set = function(info, value)
+ E.db.enhanced.equipment.durability[info[#info]] = value
+ EI:UpdateTextSettings()
+ end
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ min = -50, max = 50, step = 1,
+ name = L["X-Offset"],
+ set = function(info, value)
+ E.db.enhanced.equipment.durability[info[#info]] = value
+ EI:UpdateTextSettings()
+ end
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ min = -50, max = 50, step = 1,
+ name = L["Y-Offset"],
+ set = function(info, value)
+ E.db.enhanced.equipment.durability[info[#info]] = value
+ EI:UpdateTextSettings()
+ end
+ }
+ }
+ },
+ fontGroup = {
+ order = 5,
+ type = "group",
+ guiInline = true,
+ name = L["Font"],
+ get = function(info) return E.db.enhanced.equipment[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.equipment[info[#info]] = value
+ EI:UpdateTextSettings()
+ end,
+ disabled = function() return not E.db.enhanced.equipment.enable end,
+ args = {
+ font = {
+ order = 1,
+ type = "select",
+ dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontSize = {
+ order = 2,
+ type = "range",
+ min = 6, max = 36, step = 1,
+ name = L["FONT_SIZE"]
+ },
+ fontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ values = {
+ ["NONE"] = L["NONE"],
+ ["OUTLINE"] = "OUTLINE",
+ ["MONOCHROMEOUTLINE"] = "MONOCROMEOUTLINE",
+ ["THICKOUTLINE"] = "THICKOUTLINE"
+ }
+ }
+ }
+ }
+ }
+ }
+end
+
+local function MapOptions()
+ local MFC = E:GetModule("Enhanced_FogClear")
+
+ return {
+ type = "group",
+ name = L["Map"],
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = EE:ColorizeSettingName(L["Map"])
+ },
+ fogClear ={
+ type = "group",
+ name = L["Fog of War"],
+ guiInline = true,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.db.enhanced.map.fogClear.enable end,
+ set = function(info, value)
+ E.db.enhanced.map.fogClear.enable = value
+ MFC:UpdateFog()
+ end
+ },
+ overlay = {
+ order = 2,
+ type = "color",
+ name = L["Overlay Color"],
+ hasAlpha = true,
+ get = function(info)
+ local t = E.db.enhanced.map.fogClear.color
+ local d = E.db.enhanced.map.fogClear.color
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(_, r, g, b, a)
+ local color = E.db.enhanced.map.fogClear.color
+ color.r, color.g, color.b, color.a = r, g, b, a
+ MFC:UpdateWorldMapOverlays()
+ end,
+ disabled = function() return not E.db.enhanced.map.fogClear.enable end
+ }
+ }
+ }
+ }
+ }
+end
+
+local function MinimapOptions()
+ E.Options.args.maps.args.minimap.args.locationTextGroup.args.locationText.values = {
+ ["MOUSEOVER"] = L["Minimap Mouseover"],
+ ["SHOW"] = L["Always Display"],
+ ["ABOVE"] = EE:ColorizeSettingName(L["Above Minimap"]),
+ ["HIDE"] = L["HIDE"]
+ }
+
+ local MBG = E:GetModule("Enhanced_MinimapButtonGrabber")
+
+ return {
+ type = "group",
+ name = L["Minimap"],
+ get = function(info) return E.db.enhanced.minimap[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.minimap[info[#info]] = value
+ E:GetModule("Enhanced_MinimapLocation"):UpdateSettings()
+ end,
+ disabled = function() return not E.private.general.minimap.enable end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = EE:ColorizeSettingName(L["Minimap"])
+ },
+ location = {
+ order = 1,
+ type = "toggle",
+ name = L["Location Panel"],
+ desc = L["Toggle Location Panel."]
+ },
+ locationText = E.Options.args.maps.args.minimap.args.locationTextGroup.args.locationText,
+ showlocationdigits = {
+ order = 2,
+ type = "toggle",
+ name = L["Show Location Digits"],
+ desc = L["Toggle Location Digits."],
+ disabled = function() return not (E.db.enhanced.minimap.location and E.db.general.minimap.locationText == "ABOVE") end
+ },
+ locationdigits = {
+ order = 3,
+ type = "range",
+ name = L["Location Digits"],
+ desc = L["Number of digits for map location."],
+ min = 0, max = 2, step = 1,
+ set = function(info, value)
+ E.db.enhanced.minimap[info[#info]] = value
+ E:GetModule("Minimap"):UpdateSettings()
+ end,
+ disabled = function() return not (E.db.enhanced.minimap.location and E.db.general.minimap.locationText == "ABOVE" and E.db.enhanced.minimap.showlocationdigits) end
+ },
+ combatHide = {
+ order = 4,
+ type = "group",
+ name = L["Combat Hide"],
+ guiInline = true,
+ args = {
+ hideincombat = {
+ order = 5,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Hide minimap while in combat."],
+ },
+ fadeindelay = {
+ order = 6,
+ type = "range",
+ name = L["FadeIn Delay"],
+ desc = L["The time to wait before fading the minimap back in after combat hide. (0 = Disabled)"],
+ min = 0, max = 20, step = 1,
+ disabled = function() return not E.db.enhanced.minimap.hideincombat end
+ }
+ }
+ },
+ minimapButtons = {
+ order = 5,
+ type = "group",
+ name = L["Minimap Button Grabber"],
+ guiInline = true,
+ get = function(info) return E.db.enhanced.minimap.buttonGrabber[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.minimap.buttonGrabber[info[#info]] = value
+ MBG:UpdateLayout()
+ end,
+ disabled = function() return not E.private.enhanced.minimapButtonGrabber end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.private.enhanced.minimapButtonGrabber end,
+ set = function(info, value)
+ E.private.enhanced.minimapButtonGrabber = value
+ if value and not MBG.initialized then
+ MBG:Initialize()
+ elseif not value then
+ E:StaticPopup_Show("PRIVATE_RL")
+ end
+ end,
+ disabled = false
+ },
+ spacer = {
+ order = 2,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ growFrom = {
+ order = 3,
+ type = "select",
+ name = L["Grow direction"],
+ values = {
+ ["TOPLEFT"] = "DOWN -> RIGHT",
+ ["TOPRIGHT"] = "DOWN -> LEFT",
+ ["BOTTOMLEFT"] = "UP -> RIGHT",
+ ["BOTTOMRIGHT"] = "UP -> LEFT"
+ }
+ },
+ buttonsPerRow = {
+ order = 4,
+ type = "range",
+ name = L["Buttons Per Row"],
+ desc = L["The amount of buttons to display per row."],
+ min = 1, max = 12, step = 1
+ },
+ buttonSize = {
+ order = 5,
+ type = "range",
+ name = L["Button Size"],
+ min = 2, max = 60, step = 1
+ },
+ buttonSpacing = {
+ order = 6,
+ type = "range",
+ name = L["Button Spacing"],
+ desc = L["The spacing between buttons."],
+ min = -1, max = 24, step = 1
+ },
+ backdrop = {
+ order = 7,
+ type = "toggle",
+ name = L["Backdrop"]
+ },
+ backdropSpacing = {
+ order = 8,
+ type = "range",
+ name = L["Backdrop Spacing"],
+ desc = L["The spacing between the backdrop and the buttons."],
+ min = -1, max = 15, step = 1,
+ disabled = function() return not E.private.enhanced.minimapButtonGrabber or not E.db.enhanced.minimap.buttonGrabber.backdrop end,
+ },
+ mouseover = {
+ order = 9,
+ type = "toggle",
+ name = L["Mouse Over"],
+ desc = L["The frame is not shown unless you mouse over the frame."],
+ set = function(info, value)
+ E.db.enhanced.minimap.buttonGrabber[info[#info]] = value
+ MBG:ToggleMouseover()
+ end
+ },
+ alpha = {
+ order = 10,
+ type = "range",
+ name = L["Alpha"],
+ min = 0, max = 1, step = 0.01,
+ set = function(info, value)
+ E.db.enhanced.minimap.buttonGrabber[info[#info]] = value
+ MBG:UpdateAlpha()
+ end
+ },
+ insideMinimapGroup = {
+ order = 11,
+ type = "group",
+ name = L["Inside Minimap"],
+ guiInline = true,
+ get = function(info) return E.db.enhanced.minimap.buttonGrabber.insideMinimap[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.minimap.buttonGrabber.insideMinimap[info[#info]] = value
+ MBG:UpdatePosition()
+ end,
+ disabled = function() return not E.db.enhanced.minimap.buttonGrabber.insideMinimap.enable end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ disabled = function() return not E.private.enhanced.minimapButtonGrabber end
+ },
+ position = {
+ order = 2,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["TOPLEFT"] = "TOPLEFT",
+ ["LEFT"] = "LEFT",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["RIGHT"] = "RIGHT",
+ ["TOPRIGHT"] = "TOPRIGHT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT",
+ ["CENTER"] = "CENTER",
+ ["TOP"] = "TOP",
+ ["BOTTOM"] = "BOTTOM"
+ }
+ },
+ xOffset = {
+ order = 3,
+ type = "range",
+ name = L["xOffset"],
+ min = -20, max = 20, step = 1
+ },
+ yOffset = {
+ order = 4,
+ type = "range",
+ name = L["yOffset"],
+ min = -20, max = 20, step = 1
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+end
+
+local function NamePlatesOptions()
+ return {
+ type = "group",
+ name = L["NamePlates"],
+ get = function(info) return E.db.enhanced.nameplates[info[#info]] end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = EE:ColorizeSettingName(L["NamePlates"])
+ },
+ classCache = {
+ order = 1,
+ type = "toggle",
+ name = L["Cache Unit Class"],
+ set = function(info, value)
+ E.db.enhanced.nameplates[info[#info]] = value
+ E:GetModule("Enhanced_NamePlates"):UpdateAllSettings()
+ end
+ },
+ chatBubbles = {
+ order = 2,
+ type = "toggle",
+ name = L["Chat Bubbles"],
+ set = function(info, value)
+ E.db.enhanced.nameplates[info[#info]] = value
+ E:GetModule("Enhanced_NamePlates"):UpdateAllSettings()
+ E:GetModule("NamePlates"):ConfigureAll()
+ end
+ },
+ titleCacheGroup = {
+ order = 3,
+ type = "group",
+ name = L["Cache Unit Guilds / NPC Titles"],
+ guiInline = true,
+ get = function(info) return E.db.enhanced.nameplates[info[#info]] end,
+ args = {
+ titleCache = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value)
+ E.db.enhanced.nameplates[info[#info]] = value
+ E:GetModule("Enhanced_NamePlates"):UpdateAllSettings()
+ E:GetModule("NamePlates"):ConfigureAll()
+ end
+ },
+ guildGroup = {
+ order = 3,
+ type = "group",
+ name = L["Guild"],
+ guiInline = true,
+ get = function(info) return E.db.enhanced.nameplates.guild[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.nameplates.guild[info[#info]] = value
+ E:GetModule("NamePlates"):ConfigureAll()
+ end,
+ disabled = function() return not E.db.enhanced.nameplates.titleCache end,
+ args = {
+ font = {
+ order = 1,
+ type = "select",
+ dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font,
+ },
+ fontSize = {
+ order = 2,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 4, max = 33, step = 1,
+ },
+ fontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ values = {
+ ["NONE"] = L["NONE"],
+ ["OUTLINE"] = "OUTLINE",
+ ["MONOCHROMEOUTLINE"] = "MONOCROMEOUTLINE",
+ ["THICKOUTLINE"] = "THICKOUTLINE"
+ }
+ },
+ separator = {
+ order = 4,
+ type = "select",
+ name = L["Separator"],
+ values = {
+ [" "] = L["NONE"],
+ ["<"] = "< >",
+ ["("] = "( )",
+ ["["] = "[ ]",
+ ["{"] = "{ }"
+ }
+ },
+ colorsGroup = {
+ order = 5,
+ type = "group",
+ name = L["COLORS"],
+ guiInline = true,
+ get = function(info)
+ local t = E.db.enhanced.nameplates.guild.colors[info[#info]]
+ local d = P.enhanced.nameplates.guild.colors[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.enhanced.nameplates.guild.colors[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ E:GetModule("NamePlates"):ConfigureAll()
+ end,
+ args = {
+ raid = {
+ order = 1,
+ type = "color",
+ name = L["RAID"],
+ },
+ party = {
+ order = 2,
+ type = "color",
+ name = L["PARTY"],
+ },
+ guild = {
+ order = 3,
+ type = "color",
+ name = L["GUILD"],
+ },
+ none = {
+ order = 4,
+ type = "color",
+ name = L["ALL"],
+ },
+ }
+ },
+ visabilityGroup = {
+ order = 6,
+ type = "group",
+ name = L["Visibility State"],
+ guiInline = true,
+ get = function(info) return E.db.enhanced.nameplates.guild.visibility[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.nameplates.guild.visibility[info[#info]] = value
+ E:GetModule("NamePlates"):ConfigureAll()
+ end,
+ args = {
+ city = {
+ order = 1,
+ type = "toggle",
+ name = L["City (Resting)"]
+ },
+ pvp = {
+ order = 2,
+ type = "toggle",
+ name = L["PvP"]
+ },
+ arena = {
+ order = 3,
+ type = "toggle",
+ name = L["Arena"]
+ },
+ party = {
+ order = 4,
+ type = "toggle",
+ name = L["Party"]
+ },
+ raid = {
+ order = 5,
+ type = "toggle",
+ name = L["Raid"]
+ }
+ }
+ }
+ }
+ },
+ npcGroup = {
+ order = 3,
+ type = "group",
+ name = L["NPC"],
+ guiInline = true,
+ get = function(info) return E.db.enhanced.nameplates.npc[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.nameplates.npc[info[#info]] = value
+ E:GetModule("NamePlates"):ConfigureAll()
+ end,
+ disabled = function() return not E.db.enhanced.nameplates.titleCache end,
+ args = {
+ font = {
+ order = 1,
+ type = "select",
+ dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontSize = {
+ order = 2,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 4, max = 33, step = 1
+ },
+ fontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ values = {
+ ["NONE"] = L["NONE"],
+ ["OUTLINE"] = "OUTLINE",
+ ["MONOCHROMEOUTLINE"] = "MONOCROMEOUTLINE",
+ ["THICKOUTLINE"] = "THICKOUTLINE"
+ }
+ },
+ reactionColor = {
+ order = 4,
+ type = "toggle",
+ name = L["Reaction Color"],
+ desc = L["Color based on reaction type."]
+ },
+ color = {
+ order = 5,
+ type = "color",
+ name = L["COLOR"],
+ get = function(info)
+ local t = E.db.enhanced.nameplates.npc[info[#info]]
+ local d = P.enhanced.nameplates.npc[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.enhanced.nameplates.npc[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ E:GetModule("NamePlates"):ConfigureAll()
+ end,
+ disabled = function() return E.db.enhanced.nameplates.npc.reactionColor end
+ },
+ separator = {
+ order = 5,
+ type = "select",
+ name = L["Separator"],
+ values = {
+ [" "] = L["NONE"],
+ ["<"] = "< >",
+ ["("] = "( )"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+end
+
+local function TooltipOptions()
+ local TI = E:GetModule("Enhanced_TooltipIcon")
+ local PI = E:GetModule("Enhanced_ProgressionInfo")
+
+ return {
+ type = "group",
+ name = L["Tooltip"],
+ get = function(info) return E.db.enhanced.tooltip[info[#info]] end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = EE:ColorizeSettingName(L["Tooltip"])
+ },
+ itemQualityBorderColor = {
+ order = 1,
+ type = "toggle",
+ name = L["Item Border Color"],
+ desc = L["Colorize the tooltip border based on item quality."],
+ set = function(info, value)
+ E.db.enhanced.tooltip.itemQualityBorderColor = value
+ E:GetModule("Enhanced_ItemBorderColor"):ToggleState()
+ end
+ },
+ tooltipIcon = {
+ order = 2,
+ type = "group",
+ name = L["Tooltip Icon"],
+ guiInline = true,
+ get = function(info) return E.db.enhanced.tooltip.tooltipIcon[info[#info]] end,
+ args = {
+ tooltipIcon = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Show/Hides an Icon for Spells and Items on the Tooltip."],
+ get = function(info) return E.db.enhanced.tooltip.tooltipIcon.enable end,
+ set = function(info, value)
+ E.db.enhanced.tooltip.tooltipIcon.enable = value
+ TI:ToggleItemsState()
+ TI:ToggleSpellsState()
+ TI:ToggleAchievementsState()
+ end
+ },
+ spacer = {
+ order = 2,
+ type = "description",
+ name = "",
+ width = "full"
+ },
+ tooltipIconSpells = {
+ order = 3,
+ type = "toggle",
+ name = SPELLS,
+ desc = L["Show/Hides an Icon for Spells on the Tooltip."],
+ get = function(info) return E.db.enhanced.tooltip.tooltipIcon.tooltipIconSpells end,
+ set = function(info, value)
+ E.db.enhanced.tooltip.tooltipIcon.tooltipIconSpells = value
+ TI:ToggleSpellsState()
+ end,
+ disabled = function() return not E.db.enhanced.tooltip.tooltipIcon.enable end
+ },
+ tooltipIconItems = {
+ order = 4,
+ type = "toggle",
+ name = ITEMS,
+ desc = L["Show/Hides an Icon for Items on the Tooltip."],
+ get = function(info) return E.db.enhanced.tooltip.tooltipIcon.tooltipIconItems end,
+ set = function(info, value)
+ E.db.enhanced.tooltip.tooltipIcon.tooltipIconItems = value
+ TI:ToggleItemsState()
+ end,
+ disabled = function() return not E.db.enhanced.tooltip.tooltipIcon.enable end
+ },
+ tooltipIconAchievements = {
+ order = 5,
+ type = "toggle",
+ name = ACHIEVEMENTS,
+ desc = L["Show/Hides an Icon for Achievements on the Tooltip."],
+ get = function(info) return E.db.enhanced.tooltip.tooltipIcon.tooltipIconAchievements end,
+ set = function(info, value)
+ E.db.enhanced.tooltip.tooltipIcon.tooltipIconAchievements = value
+ TI:ToggleAchievementsState()
+ end,
+ disabled = function() return not E.db.enhanced.tooltip.tooltipIcon.enable end
+ }
+ }
+ },
+ progressInfo = {
+ order = 3,
+ type = "group",
+ name = L["Progress Info"],
+ guiInline = true,
+ get = function(info) return E.db.enhanced.tooltip.progressInfo[info[#info]] end,
+ set = function(info, value) E.db.enhanced.tooltip.progressInfo[info[#info]] = value end,
+ disabled = function() return not E.db.enhanced.tooltip.progressInfo.enable end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value)
+ E.db.enhanced.tooltip.progressInfo[info[#info]] = value
+ PI:ToggleState()
+ end,
+ disabled = false
+ },
+ checkAchievements = {
+ order = 2,
+ type = "toggle",
+ name = L["Check Achievements"],
+ desc = L["Check achievement completion instead of boss kill stats.\nSome servers log incorrect boss kill statistics, this is an alternative way to get player progress."]
+ },
+ checkPlayer = {
+ order = 3,
+ type = "toggle",
+ name = L["Check Player"]
+ },
+ modifier = {
+ order = 4,
+ type = "select",
+ name = L["Visibility"],
+ set = function(info, value)
+ E.db.enhanced.tooltip.progressInfo[info[#info]] = value
+ PI:UpdateModifier()
+ end,
+ values = {
+ ["ALL"] = ALWAYS,
+ ["SHIFT"] = L["SHIFT_KEY"],
+ ["ALT"] = L["ALT_KEY"],
+ ["CTRL"] = L["CTRL_KEY"]
+ }
+ },
+ tiers = {
+ order = 5,
+ type = "group",
+ name = L["Tiers"],
+ get = function(info) return E.db.enhanced.tooltip.progressInfo.tiers[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.tooltip.progressInfo.tiers[info[#info]] = value
+ PI:UpdateSettings()
+ end,
+ disabled = function() return not E.db.enhanced.tooltip.progressInfo.enable end,
+ args = {
+ RS = {
+ order = 1,
+ type = "toggle",
+ name = L["Ruby Sanctum"]
+ },
+ ICC = {
+ order = 2,
+ type = "toggle",
+ name = L["Icecrown Citadel"]
+ },
+ ToC = {
+ order = 3,
+ type = "toggle",
+ name = L["Trial of the Crusader"]
+ },
+ Ulduar = {
+ order = 4,
+ type = "toggle",
+ name = L["Ulduar"]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+end
+
+local function LoseControlOptions()
+ return {
+ type = "group",
+ name = L["Lose Control"],
+ get = function(info) return E.db.enhanced.loseControl[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.loseControl[info[#info]] = value
+ E:GetModule("Enhanced_LoseControl"):UpdateSettings()
+ end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = EE:ColorizeSettingName(L["Lose Control"])
+ },
+ enable = {
+ order = 1,
+ type = "toggle",
+ width = "full",
+ name = L["Enable"],
+ get = function(info) return E.private.enhanced.loseControl.enable end,
+ set = function(info, value)
+ E.private.enhanced.loseControl.enable = value
+ E:GetModule("Enhanced_LoseControl"):ToggleState()
+ end,
+ },
+ compactMode = {
+ order = 2,
+ type = "toggle",
+ name = L["Compact mode"],
+ disabled = function() return not E.private.enhanced.loseControl.enable end
+ },
+ iconSize = {
+ order = 3,
+ type = "range",
+ min = 30, max = 120, step = 1,
+ name = L["Icon Size"],
+ disabled = function() return not E.private.enhanced.loseControl.enable end
+ },
+ typeGroup = {
+ order = 4,
+ type = "group",
+ name = TYPE,
+ guiInline = true,
+ get = function(info) return E.db.enhanced.loseControl[info[#info]] end,
+ set = function(info, value) E.db.enhanced.loseControl[info[#info]] = value end,
+ disabled = function() return not E.private.enhanced.loseControl.enable end,
+ args = {
+ CC = {
+ order = 1,
+ type = "toggle",
+ name = L["CC"]
+ },
+ PvE = {
+ order = 2,
+ type = "toggle",
+ name = L["PvE"]
+ },
+ Silence = {
+ order = 3,
+ type = "toggle",
+ name = L["Silence"]
+ },
+ Disarm = {
+ order = 4,
+ type = "toggle",
+ name = L["Disarm"]
+ },
+ Root = {
+ order = 5,
+ type = "toggle",
+ name = L["Root"]
+ },
+ Snare = {
+ order = 6,
+ type = "toggle",
+ name = L["Snare"]
+ }
+ }
+ }
+ }
+ }
+end
+
+local function InterruptTrackerOptions()
+ return {
+ type = "group",
+ name = L["Interrupt Tracker"],
+ get = function(info) return E.db.enhanced.interruptTracker[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.interruptTracker[info[#info]] = value
+ E:GetModule("Enhanced_InterruptTracker"):UpdateAllIconsTimers()
+ end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = EE:ColorizeSettingName(L["Interrupt Tracker"])
+ },
+ enable = {
+ order = 1,
+ type = "toggle",
+ width = "full",
+ name = L["Enable"],
+ get = function(info) return E.private.enhanced.interruptTracker.enable end,
+ set = function(info, value)
+ E.private.enhanced.interruptTracker.enable = value
+ E:StaticPopup_Show("PRIVATE_RL")
+ end
+ },
+ size = {
+ order = 2,
+ type = "range",
+ min = 10, max = 120, step = 1,
+ name = L["Size"],
+ disabled = function() return not E.private.enhanced.interruptTracker.enable end,
+ },
+ enableGroup = {
+ order = 3,
+ type = "group",
+ name = L["Where to show"],
+ guiInline = true,
+ get = function(info) return E.private.enhanced.interruptTracker[info[#info]] end,
+ set = function(info, value)
+ E.private.enhanced.interruptTracker[info[#info]] = value
+ E:GetModule("Enhanced_InterruptTracker"):UpdateState()
+ end,
+ disabled = function() return not E.private.enhanced.interruptTracker.enable end,
+ args = {
+ everywhere = {
+ order = 1,
+ type = "toggle",
+ name = L["Everywhere"],
+ desc = L["Show Everywhere"]
+ },
+ arena = {
+ order = 2,
+ type = "toggle",
+ name = ARENA,
+ desc = L["Show on Arena."],
+ disabled = function() return not E.private.enhanced.interruptTracker.enable or E.private.enhanced.interruptTracker.everywhere end
+ },
+ battleground = {
+ order = 3,
+ type = "toggle",
+ name = BATTLEGROUND,
+ desc = L["Show on Battleground."],
+ disabled = function() return not E.private.enhanced.interruptTracker.enable or E.private.enhanced.interruptTracker.everywhere end
+ }
+ }
+ },
+ textGroup = {
+ order = 4,
+ type = "group",
+ name = L["Text"],
+ guiInline = true,
+ get = function(info) return E.db.enhanced.interruptTracker.text[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.interruptTracker.text[info[#info]] = value
+ E:GetModule("Enhanced_InterruptTracker"):UpdateAllIconsTimers()
+ end,
+ disabled = function() return not E.private.enhanced.interruptTracker.enable end,
+ args = {
+ position = {
+ order = 1,
+ type = "select",
+ name = L["Text Position"],
+ values = {
+ TOPLEFT = "TOPLEFT",
+ LEFT = "LEFT",
+ BOTTOMLEFT = "BOTTOMLEFT",
+ RIGHT = "RIGHT",
+ TOPRIGHT = "TOPRIGHT",
+ BOTTOMRIGHT = "BOTTOMRIGHT",
+ CENTER = "CENTER",
+ TOP = "TOP",
+ BOTTOM = "BOTTOM"
+ }
+ },
+ xOffset = {
+ order = 2,
+ type = "range",
+ name = L["X-Offset"],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 3,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -300, max = 300, step = 1
+ },
+ font = {
+ order = 4,
+ type = "select",
+ dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontSize = {
+ order = 5,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 6, max = 32, step = 1
+ },
+ fontOutline = {
+ order = 6,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = {
+ ["NONE"] = L["NONE"],
+ ["OUTLINE"] = "OUTLINE",
+ ["MONOCHROMEOUTLINE"] = "MONOCROMEOUTLINE",
+ ["THICKOUTLINE"] = "THICKOUTLINE"
+ }
+ }
+ }
+ }
+ }
+ }
+end
+
+local function UnitFrameOptions()
+ local TC = E:GetModule("Enhanced_TargetClass")
+
+ return {
+ type = "group",
+ name = L["UnitFrames"],
+ childGroups = "tab",
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = EE:ColorizeSettingName(L["UnitFrames"])
+ },
+ general = {
+ order = 2,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ portraitHDModelFix = {
+ order = 2,
+ type = "group",
+ guiInline = true,
+ name = L["Portrait HD Fix"],
+ get = function(info) return E.db.enhanced.unitframe.portraitHDModelFix[info[#info]] end,
+ set = function(info, value) E.db.enhanced.unitframe.portraitHDModelFix[info[#info]] = value end,
+ disabled = function() return not E.db.enhanced.unitframe.portraitHDModelFix.enable end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value)
+ E.db.enhanced.unitframe.portraitHDModelFix.enable = value
+ E:GetModule("Enhanced_PortraitHDModelFix"):ToggleState()
+ end,
+ disabled = false
+ },
+ debug = {
+ order = 2,
+ type = "toggle",
+ name = L["Debug"],
+ desc = L["Print to chat model names of units with enabled 3D portraits."]
+ },
+ modelsToFix = {
+ order = 3,
+ type = "input",
+ name = L["Models to fix"],
+ desc = L["List of models with broken portrait camera. Separete each model name with ';' simbol"],
+ width = "full",
+ multiline = true,
+ set = function(info, value)
+ E.db.enhanced.unitframe.portraitHDModelFix.modelsToFix = value
+ E:GetModule("Enhanced_PortraitHDModelFix"):UpdatePortraits()
+ end
+ }
+ }
+ }
+ }
+ },
+ player = {
+ order = 3,
+ type = "group",
+ name = L["PLAYER"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["PLAYER"]
+ },
+ detachPortrait = {
+ order = 3,
+ type = "group",
+ name = L["Detached Portrait"],
+ get = function(info) return E.db.enhanced.unitframe.detachPortrait.player[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.unitframe.detachPortrait.player[info[#info]] = value
+ E:GetModule("UnitFrames"):CreateAndUpdateUF("player")
+ end,
+ disabled = function() return not E.db.unitframe.units.player.portrait.enable or E.db.unitframe.units.player.portrait.overlay end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Portrait"]
+ },
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Detach From Frame"],
+ set = function(info, value)
+ E.db.enhanced.unitframe.detachPortrait.player[info[#info]] = value
+ E:GetModule("Enhanced_DetachedPortrait"):ToggleState("player")
+ end
+ },
+ spacer = {
+ order = 2,
+ type = "description",
+ name = " "
+ },
+ width = {
+ order = 3,
+ type = "range",
+ name = L["Detached Width"],
+ min = 10, max = 600, step = 1
+ },
+ height = {
+ order = 4,
+ type = "range",
+ name = L["Detached Height"],
+ min = 10, max = 600, step = 1
+ }
+ }
+ }
+ }
+ },
+ target = {
+ order = 4,
+ type = "group",
+ name = L["TARGET"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["TARGET"]
+ },
+ classIcon = {
+ order = 2,
+ type = "group",
+ name = L["Class Icons"],
+ get = function(info) return E.db.enhanced.unitframe.units.target.classicon[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.unitframe.units.target.classicon[info[#info]] = value
+ TC:ToggleSettings()
+ end,
+ disabled = function() return not E.db.enhanced.unitframe.units.target.classicon.enable end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Class Icons"]
+ },
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Show class icon for units."],
+ disabled = false
+ },
+ spacer = {
+ order = 2,
+ type = "description",
+ name = " "
+ },
+ size = {
+ order = 3,
+ type = "range",
+ name = L["Size"],
+ desc = L["Size of the indicator icon."],
+ min = 16, max = 40, step = 1
+ },
+ xOffset = {
+ order = 4,
+ type = "range",
+ name = L["X-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ yOffset = {
+ order = 5,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -80, max = 40, step = 1
+ }
+ }
+ },
+ detachPortrait = {
+ order = 3,
+ type = "group",
+ name = L["Detached Portrait"],
+ get = function(info) return E.db.enhanced.unitframe.detachPortrait.target[info[#info]] end,
+ set = function(info, value)
+ E.db.enhanced.unitframe.detachPortrait.target[info[#info]] = value
+ E:GetModule("UnitFrames"):CreateAndUpdateUF("target")
+ end,
+ disabled = function() return not E.db.unitframe.units.target.portrait.enable or E.db.unitframe.units.target.portrait.overlay end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Portrait"]
+ },
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Detach From Frame"],
+ set = function(info, value)
+ E.db.enhanced.unitframe.detachPortrait.target[info[#info]] = value
+ E:GetModule("Enhanced_DetachedPortrait"):ToggleState("target")
+ end
+ },
+ spacer = {
+ order = 2,
+ type = "description",
+ name = " "
+ },
+ width = {
+ order = 3,
+ type = "range",
+ name = L["Detached Width"],
+ min = 10, max = 600, step = 1
+ },
+ height = {
+ order = 4,
+ type = "range",
+ name = L["Detached Height"],
+ min = 10, max = 600, step = 1
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+end
+
+function EE:GetOptions()
+ E.Options.args.enhanced = {
+ order = 50,
+ type = "group",
+ childGroups = "tab",
+ name = EE:ColorizeSettingName(L["Enhanced"]),
+ args = {
+ generalGroup = GeneralOptions(),
+ actionbarGroup = ActionbarOptions(),
+ blizzardGroup = BlizzardOptions(),
+ equipmentInfoGroup = EquipmentInfoOptions(),
+ mapGroup = MapOptions(),
+ minimapGroup = MinimapOptions(),
+ namePlatesGroup = NamePlatesOptions(),
+ tooltipGroup = TooltipOptions(),
+ unitframesGroup = UnitFrameOptions(),
+ loseControlGroup = LoseControlOptions(),
+ interruptGroup = InterruptTrackerOptions(),
+ }
+ }
+
+ E.Options.args.enhanced.args.generalGroup.order = 1
+ E.Options.args.enhanced.args.blizzardGroup.order = 2
+-- E.Options.args.enhanced.args.actionbarGroup.order = 3
+-- E.Options.args.enhanced.args.equipmentInfoGroup.order = 4
+-- E.Options.args.enhanced.args.minimapGroup.order = 5
+-- E.Options.args.enhanced.args.namePlatesGroup.order = 6
+-- E.Options.args.enhanced.args.tooltipGroup.order = 7
+-- E.Options.args.enhanced.args.loseControlGroup.order = 8
+-- E.Options.args.enhanced.args.interruptGroup.order = 9
+-- E.Options.args.enhanced.args.unitframesGroup.order = 10
+end
diff --git a/ElvUI_Enhanced/Config/Load_Config.xml b/ElvUI_Enhanced/Config/Load_Config.xml
new file mode 100644
index 0000000..10b3b74
--- /dev/null
+++ b/ElvUI_Enhanced/Config/Load_Config.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Developer/Analyzer.lua b/ElvUI_Enhanced/Developer/Analyzer.lua
new file mode 100644
index 0000000..515e8d6
--- /dev/null
+++ b/ElvUI_Enhanced/Developer/Analyzer.lua
@@ -0,0 +1,30 @@
+SLASH_ANALYZE1 = "/analyze"
+SlashCmdList.ANALYZE = function(arg)
+ if arg == "" then
+ arg = GetMouseFocus()
+ else
+ arg = _G[arg]
+ end
+
+ if arg and arg:GetName() then
+ ChatFrame1:AddMessage("|cffCC0000----------------------------")
+ ChatFrame1:AddMessage(arg:GetName())
+ for _, child in ipairs({arg:GetChildren()}) do
+ if child:GetName() then
+ ChatFrame1:AddMessage("+="..child:GetName())
+ end
+ end
+ ChatFrame1:AddMessage("|cffCC0000----------------------------")
+ end
+end
+
+SLASH_PROFILE1 = "/profile"
+SlashCmdList.PROFILE = function()
+ local cpuProfiling = GetCVar("scriptProfile") == "1"
+ if cpuProfiling then
+ SetCVar("scriptProfile", "0")
+ else
+ SetCVar("scriptProfile", "1")
+ end
+ ReloadUI()
+end
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Developer/Load_Developer.xml b/ElvUI_Enhanced/Developer/Load_Developer.xml
new file mode 100644
index 0000000..7dd6e5f
--- /dev/null
+++ b/ElvUI_Enhanced/Developer/Load_Developer.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/ElvUI_Enhanced.lua b/ElvUI_Enhanced/ElvUI_Enhanced.lua
new file mode 100644
index 0000000..8b65248
--- /dev/null
+++ b/ElvUI_Enhanced/ElvUI_Enhanced.lua
@@ -0,0 +1,207 @@
+local E, L, V, P, G = unpack(ElvUI)
+local addon = E:NewModule("ElvUI_Enhanced")
+local EP = E.Libs.EP
+
+local addonName = ...
+
+local format = string.format
+
+local function gsPopupShow()
+ local url = "https://www.wowinterface.com/downloads/getfile.php?id=12245&aid=47105"
+
+ E.PopupDialogs["GS_VERSION_INVALID"] = {
+ text = L["GearScore '3.1.20b - Release' is not for WotLK. Download 3.1.7. Disable this version?"],
+ button1 = DISABLE,
+ hideOnEscape = 1,
+ showAlert = 1,
+ OnShow = function(self)
+ self.editBox:SetAutoFocus(false)
+ self.editBox.width = self.editBox:GetWidth()
+ self.editBox:SetWidth(220)
+ self.editBox:SetText(url)
+ self.editBox:HighlightText()
+ ChatEdit_FocusActiveWindow()
+ end,
+ OnAccept = function()
+ DisableAddOn("GearScore")
+ DisableAddOn("BonusScanner")
+ ReloadUI()
+ end,
+ OnHide = function(self)
+ self.editBox:SetWidth(self.editBox.width or 50)
+ self.editBox.width = nil
+ end,
+ EditBoxOnEnterPressed = function(self)
+ ChatEdit_FocusActiveWindow()
+ self:GetParent():Hide()
+ end,
+ EditBoxOnEscapePressed = function(self)
+ ChatEdit_FocusActiveWindow()
+ self:GetParent():Hide()
+ end,
+ EditBoxOnTextChanged = function(self)
+ if self:GetText() ~= url then
+ self:SetText(url)
+ end
+ self:HighlightText()
+ self:ClearFocus()
+ ChatEdit_FocusActiveWindow()
+ end,
+ OnEditFocusGained = function(self)
+ self:HighlightText()
+ end
+ }
+
+ E:StaticPopup_Show("GS_VERSION_INVALID")
+end
+
+function addon:ColorizeSettingName(name)
+ return format("|cffff8000%s|r", name)
+end
+
+function addon:DBConversions()
+ if E.db.enhanced.general.trainAllButton ~= nil then
+ E.db.enhanced.general.trainAllSkills = E.db.enhanced.general.trainAllButton
+ E.db.enhanced.general.trainAllButton = nil
+ end
+
+ if E.private.skins.animations ~= nil then
+ E.private.enhanced.animatedAchievementBars = E.private.skins.animations
+ E.private.skins.animations = nil
+ end
+
+ if E.private.enhanced.blizzard and E.private.enhanced.blizzard.deathRecap ~= nil then
+ E.private.enhanced.deathRecap = E.private.enhanced.blizzard.deathRecap
+ E.private.enhanced.blizzard.deathRecap = nil
+ end
+
+ if E.private.enhanced.character.model and E.private.enhanced.character.model.enable ~= nil then
+ E.private.enhanced.character.modelFrames = E.private.enhanced.character.model.enable
+ E.private.enhanced.character.model.enable = nil
+ end
+
+ if P.unitframe.units.player.portrait.detachFromFrame ~= nil then
+ E.db.enhanced.unitframe.detachPortrait.player.enable = P.unitframe.units.player.portrait.detachFromFrame
+ E.db.enhanced.unitframe.detachPortrait.player.width = P.unitframe.units.player.portrait.detachedWidth
+ E.db.enhanced.unitframe.detachPortrait.player.height = P.unitframe.units.player.portrait.detachedHeight
+ E.db.enhanced.unitframe.detachPortrait.target.enable = P.unitframe.units.target.portrait.detachFromFrame
+ E.db.enhanced.unitframe.detachPortrait.target.width = P.unitframe.units.target.portrait.detachedWidth
+ E.db.enhanced.unitframe.detachPortrait.target.height = P.unitframe.units.target.portrait.detachedHeight
+
+ P.unitframe.units.player.portrait.detachFromFrame = nil
+ P.unitframe.units.player.portrait.detachedWidth = nil
+ P.unitframe.units.player.portrait.detachedHeight = nil
+ P.unitframe.units.target.portrait.detachFromFrame = nil
+ P.unitframe.units.target.portrait.detachedWidth = nil
+ P.unitframe.units.target.portrait.detachedHeight = nil
+ end
+
+ if E.db.enhanced.nameplates.cacheUnitClass ~= nil then
+ E.db.enhanced.nameplates.classCache = true
+ end
+ if EnhancedDB and EnhancedDB.UnitClass and next(EnhancedDB.UnitClass) then
+ local classMap = {}
+ for i, class in ipairs(CLASS_SORT_ORDER) do
+ classMap[class] = i
+ end
+ for name, class in pairs(EnhancedDB.UnitClass) do
+ if type(class) == "string" then
+ EnhancedDB.UnitClass[name] = classMap[class]
+ end
+ end
+
+ EnhancedDB.UnitClass[UNKNOWN] = nil
+ end
+
+ if E.db.general.minimap.buttons then
+ E.private.enhanced.minimapButtonGrabber = true
+
+ E.db.enhanced.minimap.buttonGrabber.buttonSize = E.db.general.minimap.buttons.buttonsize
+ E.db.enhanced.minimap.buttonGrabber.buttonSpacing = E.db.general.minimap.buttons.buttonspacing
+ E.db.enhanced.minimap.buttonGrabber.backdrop = E.db.general.minimap.buttons.backdrop
+ E.db.enhanced.minimap.buttonGrabber.backdropSpacing = E.db.general.minimap.buttons.backdropSpacing
+ E.db.enhanced.minimap.buttonGrabber.buttonsPerRow = E.db.general.minimap.buttons.buttonsPerRow
+ E.db.enhanced.minimap.buttonGrabber.alpha = E.db.general.minimap.buttons.alpha
+ E.db.enhanced.minimap.buttonGrabber.mouseover = E.db.general.minimap.buttons.mouseover
+ E.db.enhanced.minimap.buttonGrabber.growFrom = E.db.general.minimap.buttons.point
+
+ if E.db.general.minimap.buttons.insideMinimap then
+ E.db.enhanced.minimap.buttonGrabber.insideMinimap.enable = E.db.general.minimap.buttons.insideMinimap.enable
+ E.db.enhanced.minimap.buttonGrabber.insideMinimap.position = E.db.general.minimap.buttons.insideMinimap.position
+ E.db.enhanced.minimap.buttonGrabber.insideMinimap.xOffset = E.db.general.minimap.buttons.insideMinimap.xOffset
+ E.db.enhanced.minimap.buttonGrabber.insideMinimap.yOffset = E.db.general.minimap.buttons.insideMinimap.yOffset
+ end
+
+ E.db.general.minimap.buttons = nil
+ end
+
+ if E.db.fogofwar then
+ E.db.enhanced.map.fogClear.enable = E.db.fogofwar.enable
+
+ if E.db.fogofwar.color then
+ E.db.enhanced.map.fogClear.color.r = E.db.fogofwar.color.r
+ E.db.enhanced.map.fogClear.color.g = E.db.fogofwar.color.g
+ E.db.enhanced.map.fogClear.color.b = E.db.fogofwar.color.b
+ E.db.enhanced.map.fogClear.color.a = E.db.fogofwar.color.a
+ end
+
+ E.db.fogofwar = nil
+ end
+end
+
+function addon:PrintAddonMerged(mergedAddonName)
+ local _, _, _, enabled, _, reason = GetAddOnInfo(mergedAddonName)
+ if reason == "MISSING" then return end
+
+ local text = format(L["Addon |cffFFD100%s|r was merged into |cffFFD100ElvUI_Enhanced|r.\nPlease remove it to avoid conflicts."], mergedAddonName)
+ E:Print(text)
+
+ if enabled then
+ if not E.PopupDialogs.ENHANCED_MERGED_ADDON then
+ E.PopupDialogs.ENHANCED_MERGED_ADDON = {
+ button2 = CANCEL,
+ OnAccept = function()
+ DisableAddOn(E.PopupDialogs.ENHANCED_MERGED_ADDON.mergedAddonName)
+ ReloadUI()
+ end,
+ whileDead = 1,
+ hideOnEscape = false
+ }
+ end
+
+ local popup = E.PopupDialogs.ENHANCED_MERGED_ADDON
+ popup.text = text
+ popup.button1 = format("Disable %s", string.gsub(mergedAddonName, "^ElvUI_", ""))
+
+ E:StaticPopup_Show("ENHANCED_MERGED_ADDON")
+ end
+end
+
+function addon:Initialize()
+ EnhancedDB = EnhancedDB or {}
+
+ self.version = GetAddOnMetadata("ElvUI_Enhanced", "Version")
+
+ self:DBConversions()
+
+ EP:RegisterPlugin(addonName, self.GetOptions)
+
+ if E.db.general.loginmessage then
+ print(format(L["ENH_LOGIN_MSG"], E.media.hexvaluecolor, addon.version))
+ end
+
+ if IsAddOnLoaded("GearScore") and IsAddOnLoaded("BonusScanner") then
+ if GetAddOnMetadata("GearScore", "Version") == "3.1.20b - Release" then
+ gsPopupShow()
+ end
+ end
+
+ self:PrintAddonMerged("ElvUI_MinimapButtons")
+ self:PrintAddonMerged("ElvUI_FogofWar")
+end
+
+local function InitializeCallback()
+ addon:Initialize()
+end
+
+E:RegisterModule(addon:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/ElvUI_Enhanced.toc b/ElvUI_Enhanced/ElvUI_Enhanced.toc
new file mode 100644
index 0000000..b4a2899
--- /dev/null
+++ b/ElvUI_Enhanced/ElvUI_Enhanced.toc
@@ -0,0 +1,18 @@
+## Interface: 30300
+## Author: Bunny, Apollyon, Loaal, Crum
+## Version: 1.05
+## Title: |cff1784d1E|r|cffe5e3e3lvUI|r |cff1784d1E|r|cffe5e3e3nhanced|r
+## Notes: Plugin-Enhancements for |cff1784d1E|r|cffe5e3e3lvUI|r.
+## SavedVariables: EnhancedDB
+## RequiredDeps: ElvUI
+## DefaultState: Enabled
+## Dependencies: AscensionUI
+
+Developer\Load_Developer.xml
+Libraries\Load_Libraries.xml
+Locales\Load_Locales.xml
+Media\Load_Media.xml
+ElvUI_Enhanced.lua
+Settings\Load_Settings.xml
+Modules\Load_Modules.xml
+Config\Load_Config.xml
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Libraries/LibRangeCheck-2.0/LibRangeCheck-2.0.lua b/ElvUI_Enhanced/Libraries/LibRangeCheck-2.0/LibRangeCheck-2.0.lua
new file mode 100644
index 0000000..261d18c
--- /dev/null
+++ b/ElvUI_Enhanced/Libraries/LibRangeCheck-2.0/LibRangeCheck-2.0.lua
@@ -0,0 +1,1031 @@
+--[[
+Name: LibRangeCheck-2.0
+Revision: $Revision: 98 $
+Author(s): mitch0
+Website: http://www.wowace.com/projects/librangecheck-2-0/
+Description: A range checking library based on interact distances and spell ranges
+Dependencies: LibStub
+License: Public Domain
+]]
+
+--- LibRangeCheck-2.0 provides an easy way to check for ranges and get suitable range checking functions for specific ranges.\\
+-- The checkers use spell and item range checks, or interact based checks for special units where those two cannot be used.\\
+-- The lib handles the refreshing of checker lists in case talents / spells / glyphs change and in some special cases when equipment changes (for example some of the mage pvp gloves change the range of the Fire Blast spell), and also handles the caching of items used for item-based range checks.\\
+-- A callback is provided for those interested in checker changes.
+-- @usage
+-- local rc = LibStub("LibRangeCheck-2.0")
+--
+-- rc.RegisterCallback(self, rc.CHECKERS_CHANGED, function() print("need to refresh my stored checkers") end)
+--
+-- local minRange, maxRange = rc:GetRange('target')
+-- if not minRange then
+-- print("cannot get range estimate for target")
+-- elseif not maxRange then
+-- print("target is over " .. minRange .. " yards")
+-- else
+-- print("target is between " .. minRange .. " and " .. maxRange .. " yards")
+-- end
+--
+-- local meleeChecker = rc:GetFriendMaxChecker(rc.MeleeRange) -- 5 yds
+-- for i = 1, 4 do
+-- -- TODO: check if unit is valid, etc
+-- if meleeChecker("party" .. i) then
+-- print("Party member " .. i .. " is in Melee range")
+-- end
+-- end
+--
+-- local safeDistanceChecker = rc:GetHarmMinChecker(30)
+-- -- negate the result of the checker!
+-- local isSafelyAway = not safeDistanceChecker('target')
+--
+-- @class file
+-- @name LibRangeCheck-2.0
+local MAJOR_VERSION = "LibRangeCheck-2.0"
+local MINOR_VERSION = tonumber(("$Revision: 98 $"):match("%d+")) + 100000
+
+local lib, oldminor = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION)
+if not lib then
+ return
+end
+
+-- << STATIC CONFIG
+
+local UpdateDelay = .5
+local ItemRequestTimeout = 10.0
+
+-- interact distance based checks. ranges are based on my own measurements (thanks for all the folks who helped me with this)
+local DefaultInteractList = {
+ [3] = 8,
+ [2] = 9,
+ [4] = 28,
+}
+
+-- interact list overrides for races
+local InteractLists = {
+ ["Tauren"] = {
+ [3] = 6,
+ [2] = 7,
+ [4] = 25,
+ },
+ ["Scourge"] = {
+ [3] = 7,
+ [2] = 8,
+ [4] = 27,
+ },
+}
+
+local MeleeRange = 5
+
+-- list of friendly spells that have different ranges
+local FriendSpells = {}
+-- list of harmful spells that have different ranges
+local HarmSpells = {}
+
+FriendSpells["DEATHKNIGHT"] = {
+}
+HarmSpells["DEATHKNIGHT"] = {
+ 47541, -- ["Death Coil"], -- 30
+ 47476, -- ["Strangulate"], -- 30 (Glyph of Strangulate: +20)
+ 45477, -- ["Icy Touch"], -- 20 (Icy Reach: 25, 30)
+ 56222, -- ["Dark Command"], -- 20
+ 50842, -- ["Pestilence"], -- 5
+ 45902, -- ["Blood Strike"], -- 5, but requires weapon, use Pestilence if possible, so keep it after Pestilence in this list
+}
+
+FriendSpells["DRUID"] = {
+ 5185, -- ["Healing Touch"], -- 40
+ 467, -- ["Thorns"], -- 30 (Nature's Reach: 33, 36)
+ 1126, -- ["Mark of the Wild"], -- 30
+}
+HarmSpells["DRUID"] = {
+ 16979, -- ["Feral Charge"], -- 8-25
+ 5176, -- ["Wrath"], -- 30 (Nature's Reach: 33, 36)
+ 33786, -- ["Cyclone"], -- 20 (Nature's Reach: 22, 24; Gale Winds: +10/20%)
+ 6795, -- ["Growl"], -- 20
+ 5211, -- ["Bash"], -- 5
+}
+
+FriendSpells["HUNTER"] = {}
+HarmSpells["HUNTER"] = {
+ 1130, -- ["Hunter's Mark"] -- 100
+ 53351, -- ["Kill Shot"] -- 5-45 (Hawk Eye: 47, 49, 51)
+ 75, -- ["Auto Shot"], -- 5-35 (Hawk Eye: 37, 39, 41)
+ 2764, -- ["Throw"], -- 30
+ 19503, -- ["Scatter Shot"], -- 15 (Hawk Eye: 17, 19, 21; Glyph of Scatter Shot: +3)
+ 2974, -- ["Wing Clip"], -- 5
+}
+
+FriendSpells["MAGE"] = {
+ 475, -- ["Remove Curse"], -- 40 (Magic Attunement: 43, 46)
+ 1459, -- ["Arcane Intellect"], -- 30 (Magic Attunement: 33, 36)
+}
+HarmSpells["MAGE"] = {
+ 44614, -- ["Frostfire Bolt"], -- 40
+ 133, -- ["Fireball"], -- 35 (Flame Throwing: 38, 41)
+ 116, -- ["Frostbolt"], -- 30 (Arctic Reach: 33, 36)
+ 30455, -- ["Ice Lance"], -- 30 (Arctic Reach: 33, 36, Glyph of Ice Lance: +5)
+ 5143, -- ["Arcane Missiles"], -- 30 (Magic Attunement: 33, 36; Glyph of Arcane Missiles: +5)
+ 30451, -- ["Arcane Blast"], -- 30 (Magic Attunement: 33, 36)
+ 2948, -- ["Scorch"], -- 30 (Flame Throwing: 33, 36)
+ 5019, -- ["Shoot"], -- 30
+ 2136, -- ["Fire Blast"], -- 20 (Flame Throwing: 23, 26; Gladiator Gloves: +5)
+}
+
+FriendSpells["PALADIN"] = {
+ 635, -- ["Holy Light"], -- 40
+ 19740, -- ["Blessing of Might"], -- 30
+ 20473, -- ["Holy Shock"], -- 20
+}
+HarmSpells["PALADIN"] = {
+ 24275, -- ["Hammer of Wrath"], -- 30 (Glyph of Hammer of Wrath: +5)
+ 20473, -- ["Holy Shock"], -- 20
+ 20271, -- ["Judgement"], -- 10
+ 35395, -- ["Crusader Strike"], -- 5
+}
+
+FriendSpells["PRIEST"] = {
+ 2050, -- ["Lesser Heal"], -- 40
+ 1243, -- ["Power Word: Fortitude"], -- 30
+}
+HarmSpells["PRIEST"] = {
+ 585, -- ["Smite"], -- 30 (Holy Reach: 33, 36)
+ 589, -- ["Shadow Word: Pain"], -- 30 (Shadow Reach: 33, 36)
+ 5019, -- ["Shoot"], -- 30
+ 15407, -- ["Mind Flay"], -- 20 (Shadow Reach: 22, 24, Glyph of Mind Flay: +10)
+}
+
+FriendSpells["ROGUE"] = {}
+HarmSpells["ROGUE"] = {
+ 2764, -- ["Throw"], -- 30
+ 26679, -- ["Deadly Throw"], -- 30 (Glyph of Deadly Throw: +5)
+ 2094, -- ["Blind"], -- 10 (Dirty Tricks: 12, 15)
+ 2098, -- ["Eviscerate"], -- 5
+}
+
+FriendSpells["SHAMAN"] = {
+ 331, -- ["Healing Wave"], -- 40
+ 526, -- ["Cure Poison"], -- 30
+}
+HarmSpells["SHAMAN"] = {
+ 403, -- ["Lightning Bolt"], -- 30 (Storm Reach: 33, 36)
+ 370, -- ["Purge"], -- 30
+ 8050, -- ["Flame Shock"], -- 20 (Elemental Reach: 27, 35; Gladiator Gloves: +5)
+-- 8042, -- ["Earth Shock"], -- 20 (Storm, Earth and Fire: 21-25; Gladiator Gloves: +5)
+ 8056, -- ["Frost Shock"], -- 20 (Gladiator Gloves: +5)
+}
+
+FriendSpells["WARRIOR"] = {}
+HarmSpells["WARRIOR"] = {
+ 100, -- ["Charge"], -- 8-25 (Glyph of Charge: +5)
+ 3018, -- ["Shoot"], -- 30
+ 2764, -- ["Throw"], -- 30
+ 355, -- ["Taunt"], -- 30
+ 5246, -- ["Intimidating Shout"], -- 8
+ 772, -- ["Rend"], -- 5
+}
+
+FriendSpells["WARLOCK"] = {
+ 5697, -- ["Unending Breath"], -- 30 (demo)
+}
+HarmSpells["WARLOCK"] = {
+ 5019, -- ["Shoot"], -- 30
+ 348, -- ["Immolate"], -- 30 (Destructive Reach: 33, 36)
+ 172, -- ["Corruption"], -- 30 (Grim Reach: 33, 36)
+ 18223, -- ["Curse of Exhaustion"], -- 30 (Grim Reach: 33, 36, Glyph of Curse of Exhaustion: +5)
+ 5782, -- ["Fear"], -- 20 (Grim Reach: 22, 24)
+ 17877, -- ["Shadowburn"], -- 20 (Destructive Reach: 22, 24)
+}
+
+-- Items [Special thanks to Maldivia for the nice list]
+
+local FriendItems = {
+ [5] = {
+ 37727, -- Ruby Acorn
+ },
+ [8] = {
+ 34368, -- Attuned Crystal Cores
+ 33278, -- Burning Torch
+ },
+ [10] = {
+ 32321, -- Sparrowhawk Net
+ },
+ [15] = {
+ 1251, -- Linen Bandage
+ 2581, -- Heavy Linen Bandage
+ 3530, -- Wool Bandage
+ 3531, -- Heavy Wool Bandage
+ 6450, -- Silk Bandage
+ 6451, -- Heavy Silk Bandage
+ 8544, -- Mageweave Bandage
+ 8545, -- Heavy Mageweave Bandage
+ 14529, -- Runecloth Bandage
+ 14530, -- Heavy Runecloth Bandage
+ 21990, -- Netherweave Bandage
+ 21991, -- Heavy Netherweave Bandage
+ 34721, -- Frostweave Bandage
+ 34722, -- Heavy Frostweave Bandage
+-- 38643, -- Thick Frostweave Bandage
+-- 38640, -- Dense Frostweave Bandage
+ },
+ [20] = {
+ 21519, -- Mistletoe
+ },
+ [25] = {
+ 31463, -- Zezzak's Shard
+ },
+ [30] = {
+ 1180, -- Scroll of Stamina
+ 1478, -- Scroll of Protection II
+ 3012, -- Scroll of Agility
+ 1712, -- Scroll of Spirit II
+ 2290, -- Scroll of Intellect II
+ 1711, -- Scroll of Stamina II
+ 34191, -- Handful of Snowflakes
+ },
+ [35] = {
+ 18904, -- Zorbin's Ultra-Shrinker
+ },
+ [40] = {
+ 34471, -- Vial of the Sunwell
+ },
+ [45] = {
+ 32698, -- Wrangling Rope
+ },
+ [60] = {
+ 32825, -- Soul Cannon
+ 37887, -- Seeds of Nature's Wrath
+ },
+ [80] = {
+ 35278, -- Reinforced Net
+ },
+}
+
+local HarmItems = {
+ [5] = {
+ 37727, -- Ruby Acorn
+ },
+ [8] = {
+ 34368, -- Attuned Crystal Cores
+ 33278, -- Burning Torch
+ },
+ [10] = {
+ 32321, -- Sparrowhawk Net
+ },
+ [15] = {
+ 33069, -- Sturdy Rope
+ },
+ [20] = {
+ 10645, -- Gnomish Death Ray
+ },
+ [25] = {
+ 24268, -- Netherweave Net
+ 41509, -- Frostweave Net
+ 31463, -- Zezzak's Shard
+ },
+ [30] = {
+ 835, -- Large Rope Net
+ 7734, -- Six Demon Bag
+ 34191, -- Handful of Snowflakes
+ },
+ [35] = {
+ 24269, -- Heavy Netherweave Net
+ 18904, -- Zorbin's Ultra-Shrinker
+ },
+ [40] = {
+ 28767, -- The Decapitator
+ },
+ [45] = {
+ 32698, -- Wrangling Rope
+ },
+ [60] = {
+ 32825, -- Soul Cannon
+ 37887, -- Seeds of Nature's Wrath
+ },
+ [80] = {
+ 35278, -- Reinforced Net
+ },
+}
+
+-- This could've been done by checking player race as well and creating tables for those, but it's easier like this
+for k, v in pairs(FriendSpells) do
+ tinsert(v, 28880) -- ["Gift of the Naaru"]
+end
+for k, v in pairs(HarmSpells) do
+ tinsert(v, 28734) -- ["Mana Tap"]
+end
+
+-- >> END OF STATIC CONFIG
+
+-- cache
+
+local setmetatable = setmetatable
+local tonumber = tonumber
+local pairs = pairs
+local tostring = tostring
+local print = print
+local next = next
+local type = type
+local wipe = wipe
+local tinsert = tinsert
+local tremove = tremove
+local BOOKTYPE_SPELL = BOOKTYPE_SPELL
+local GetSpellInfo = GetSpellInfo
+local GetSpellName = GetSpellName
+local GetItemInfo = GetItemInfo
+local UnitCanAttack = UnitCanAttack
+local UnitCanAssist = UnitCanAssist
+local UnitExists = UnitExists
+local UnitIsDeadOrGhost = UnitIsDeadOrGhost
+local CheckInteractDistance = CheckInteractDistance
+local IsSpellInRange = IsSpellInRange
+local IsItemInRange = IsItemInRange
+local UnitClass = UnitClass
+local UnitRace = UnitRace
+local GetInventoryItemLink = GetInventoryItemLink
+local GetTime = GetTime
+local HandSlotId = GetInventorySlotInfo("HandsSlot")
+local TT = ItemRefTooltip
+local math_floor = math.floor
+
+-- temporary stuff
+
+local itemRequestTimeoutAt
+local foundNewItems
+local cacheAllItems
+local friendItemRequests
+local harmItemRequests
+local lastUpdate = 0
+
+-- minRangeCheck is a function to check if spells with minimum range are really out of range, or fail due to range < minRange. See :init() for its setup
+local minRangeCheck = function(unit) return CheckInteractDistance(unit, 2) end
+
+local checkers_Spell = setmetatable({}, {
+ __index = function(t, spellIdx)
+ local func = function(unit)
+ if IsSpellInRange(spellIdx, BOOKTYPE_SPELL, unit) == 1 then
+ return true
+ end
+ end
+ t[spellIdx] = func
+ return func
+ end
+})
+local checkers_SpellWithMin = setmetatable({}, {
+ __index = function(t, spellIdx)
+ local func = function(unit)
+ if IsSpellInRange(spellIdx, BOOKTYPE_SPELL, unit) == 1 then
+ return true
+ elseif minRangeCheck(unit) then
+ return true, true
+ end
+ end
+ t[spellIdx] = func
+ return func
+ end
+})
+local checkers_Item = setmetatable({}, {
+ __index = function(t, item)
+ local func = function(unit)
+ return (IsItemInRange(item, unit) == 1)
+ end
+ t[item] = func
+ return func
+ end
+})
+local checkers_Interact = setmetatable({}, {
+ __index = function(t, index)
+ local func = function(unit)
+ if CheckInteractDistance(unit, index) then
+ return true
+ end
+ end
+ t[index] = func
+ return func
+ end
+})
+
+-- helper functions
+
+local function copyTable(src, dst)
+ if type(dst) ~= "table" then dst = {} end
+ if type(src) == "table" then
+ for k, v in pairs(src) do
+ if type(v) == "table" then
+ v = copyTable(v, dst[k])
+ end
+ dst[k] = v
+ end
+ end
+ return dst
+end
+
+
+local function initItemRequests(cacheAll)
+ friendItemRequests = copyTable(FriendItems)
+ harmItemRequests = copyTable(HarmItems)
+ cacheAllItems = cacheAll
+ foundNewItems = nil
+end
+
+local function requestItemInfo(itemId)
+ if not itemId then return end
+ TT:SetHyperlink(string.format("item:%d", itemId))
+end
+
+-- return the spellIndex of the given spell by scanning the spellbook
+local function findSpellIdx(spellName)
+ local i = 1
+ while true do
+ local spell, rank = GetSpellName(i, BOOKTYPE_SPELL)
+ if not spell then return nil end
+ if spell == spellName then return i end
+ i = i + 1
+ end
+ return nil
+end
+
+-- minRange should be nil if there's no minRange, not 0
+local function addChecker(t, range, minRange, checker)
+ local rc = { ["range"] = range, ["minRange"] = minRange, ["checker"] = checker }
+ for i = 1, #t do
+ local v = t[i]
+ if rc.range == v.range then return end
+ if rc.range > v.range then
+ tinsert(t, i, rc)
+ return
+ end
+ end
+ tinsert(t, rc)
+end
+
+local function createCheckerList(spellList, itemList, interactList)
+ local res = {}
+ if spellList then
+ for i = 1, #spellList do
+ local sid = spellList[i]
+ local name, _, _, _, _, _, _, minRange, range = GetSpellInfo(sid)
+ local spellIdx = findSpellIdx(name)
+ if spellIdx and range then
+ minRange = math_floor(minRange + 0.5)
+ range = math_floor(range + 0.5)
+ -- print("### spell: " .. tostring(name) .. ", " .. tostring(minRange) .. " - " .. tostring(range))
+ if minRange == 0 then -- getRange() expects minRange to be nil in this case
+ minRange = nil
+ end
+ if range == 0 then
+ range = MeleeRange
+ end
+ if minRange then
+ addChecker(res, range, minRange, checkers_SpellWithMin[spellIdx])
+ else
+ addChecker(res, range, minRange, checkers_Spell[spellIdx])
+ end
+ end
+ end
+ end
+
+ if itemList then
+ for range, items in pairs(itemList) do
+ for i = 1, #items do
+ local item = items[i]
+ if GetItemInfo(item) then
+ addChecker(res, range, nil, checkers_Item[item])
+ break
+ end
+ end
+ end
+ end
+
+ if interactList and not next(res) then
+ for index, range in pairs(interactList) do
+ addChecker(res, range, nil, checkers_Interact[index])
+ end
+ end
+
+ return res
+end
+
+-- returns minRange, maxRange or nil
+local function getRange(unit, checkerList)
+ local min, max = 0, nil
+ for i = 1, #checkerList do
+ local rc = checkerList[i]
+ if not max or max > rc.range then
+ if rc.minRange then
+ local inRange, inMinRange = rc.checker(unit)
+ if inMinRange then
+ max = rc.minRange
+ elseif inRange then
+ min, max = rc.minRange, rc.range
+ elseif min > rc.range then
+ return min, max
+ else
+ return rc.range, max
+ end
+ elseif rc.checker(unit) then
+ max = rc.range
+ elseif min > rc.range then
+ return min, max
+ else
+ return rc.range, max
+ end
+ end
+ end
+ return min, max
+end
+
+local function updateCheckers(origList, newList)
+ if #origList ~= #newList then
+ wipe(origList)
+ copyTable(newList, origList)
+ return true
+ end
+ for i = 1, #origList do
+ if origList[i].range ~= newList[i].range or origList[i].checker ~= newList[i].checker then
+ wipe(origList)
+ copyTable(newList, origList)
+ return true
+ end
+ end
+end
+
+local function rcIterator(checkerList)
+ local curr = #checkerList
+ return function()
+ local rc = checkerList[curr]
+ if not rc then
+ return nil
+ end
+ curr = curr - 1
+ return rc.range, rc.checker
+ end
+end
+
+local function getMinChecker(checkerList, range)
+ local checker, checkerRange
+ for i = 1, #checkerList do
+ local rc = checkerList[i]
+ if rc.range < range then
+ return checker, checkerRange
+ end
+ checker, checkerRange = rc.checker, rc.range
+ end
+ return checker, checkerRange
+end
+
+local function getMaxChecker(checkerList, range)
+ for i = 1, #checkerList do
+ local rc = checkerList[i]
+ if rc.range <= range then
+ return rc.checker, rc.range
+ end
+ end
+end
+
+local function getChecker(checkerList, range)
+ for i = 1, #checkerList do
+ local rc = checkerList[i]
+ if rc.range == range then
+ return rc.checker
+ end
+ end
+end
+
+local function null()
+end
+
+local function createSmartChecker(friendChecker, harmChecker, miscChecker)
+ miscChecker = miscChecker or null
+ friendChecker = friendChecker or miscChecker
+ harmChecker = harmChecker or miscChecker
+ return function(unit)
+ if not UnitExists(unit) then
+ return nil
+ end
+ if UnitIsDeadOrGhost(unit) then
+ return miscChecker(unit)
+ end
+ if UnitCanAttack("player", unit) then
+ return harmChecker(unit)
+ elseif UnitCanAssist("player", unit) then
+ return friendChecker(unit)
+ else
+ return miscChecker(unit)
+ end
+ end
+end
+
+-- OK, here comes the actual lib
+
+-- pre-initialize the checkerLists here so that we can return some meaningful result even if
+-- someone manages to call us before we're properly initialized. miscRC should be independent of
+-- race/class/talents, so it's safe to initialize it here
+-- friendRC and harmRC will be properly initialized later when we have all the necessary data for them
+lib.checkerCache_Spell = lib.checkerCache_Spell or {}
+lib.checkerCache_Item = lib.checkerCache_Item or {}
+lib.miscRC = createCheckerList(nil, nil, DefaultInteractList)
+lib.friendRC = createCheckerList(nil, nil, DefaultInteractList)
+lib.harmRC = createCheckerList(nil, nil, DefaultInteractList)
+
+lib.failedItemRequests = {}
+
+-- << Public API
+
+
+--- The callback name that is fired when checkers are changed.
+-- @field
+lib.CHECKERS_CHANGED = "CHECKERS_CHANGED"
+-- "export" it, maybe someone will need it for formatting
+--- Constant for Melee range (5yd).
+-- @field
+lib.MeleeRange = MeleeRange
+
+function lib:findSpellIndex(spell)
+ if type(spell) == 'number' then
+ spell = GetSpellInfo(spell)
+ end
+ if not spell then return nil end
+ return findSpellIdx(spell)
+end
+
+-- returns the range estimate as a string
+-- deprecated, use :getRange(unit) instead and build your own strings
+-- (checkVisible is not used any more, kept for compatibility only)
+function lib:getRangeAsString(unit, checkVisible, showOutOfRange)
+ local minRange, maxRange = self:getRange(unit)
+ if not minRange then return nil end
+ if not maxRange then
+ return showOutOfRange and minRange .. " +" or nil
+ end
+ return minRange .. " - " .. maxRange
+end
+
+-- initialize RangeCheck if not yet initialized or if "forced"
+function lib:init(forced)
+ if self.initialized and (not forced) then
+ return
+ end
+ self.initialized = true
+ local _, playerClass = UnitClass("player")
+ local _, playerRace = UnitRace("player")
+
+ minRangeCheck = nil
+ -- first try to find a nice item we can use for minRangeCheck
+ if HarmItems[15] then
+ local items = HarmItems[15]
+ for i = 1, #items do
+ local item = items[i]
+ if GetItemInfo(item) then
+ minRangeCheck = function(unit)
+ return (IsItemInRange(item, unit) == 1)
+ end
+ break
+ end
+ end
+ end
+ if not minRangeCheck then
+ -- ok, then try to find some class specific spell
+ if playerClass == "WARRIOR" then
+ -- for warriors, use Intimidating Shout if available
+ local name = GetSpellInfo(5246) -- ["Intimidating Shout"]
+ local spellIdx = findSpellIdx(name)
+ if spellIdx then
+ minRangeCheck = function(unit)
+ return (IsSpellInRange(spellIdx, BOOKTYPE_SPELL, unit) == 1)
+ end
+ end
+ elseif playerClass == "ROGUE" then
+ -- for rogues, use Blind if available
+ local name = GetSpellInfo(2094) -- ["Blind"]
+ local spellIdx = findSpellIdx(name)
+ if spellIdx then
+ minRangeCheck = function(unit)
+ return (IsSpellInRange(spellIdx, BOOKTYPE_SPELL, unit) == 1)
+ end
+ end
+ end
+ end
+ if not minRangeCheck then
+ -- fall back to interact distance checks
+ if playerClass == "HUNTER" or playerRace == "Tauren" then
+ -- for hunters, use interact4 as it's safer
+ -- for Taurens interact4 is actually closer than 25yd and interact2 is closer than 8yd, so we can't use that
+ minRangeCheck = checkers_Interact[4]
+ else
+ minRangeCheck = checkers_Interact[2]
+ end
+ end
+
+ local interactList = InteractLists[playerRace] or DefaultInteractList
+ self.handSlotItem = GetInventoryItemLink("player", HandSlotId)
+ local changed = false
+ if updateCheckers(self.friendRC, createCheckerList(FriendSpells[playerClass], FriendItems, interactList)) then
+ changed = true
+ end
+ if updateCheckers(self.harmRC, createCheckerList(HarmSpells[playerClass], HarmItems, interactList)) then
+ changed = true
+ end
+ if updateCheckers(self.miscRC, createCheckerList(nil, nil, interactList)) then
+ changed = true
+ end
+ if changed and self.callbacks then
+ self.callbacks:Fire(self.CHECKERS_CHANGED)
+ end
+end
+
+--- Return an iterator for checkers usable on friendly units as (**range**, **checker**) pairs.
+function lib:GetFriendCheckers()
+ return rcIterator(self.friendRC)
+end
+
+--- Return an iterator for checkers usable on enemy units as (**range**, **checker**) pairs.
+function lib:GetHarmCheckers()
+ return rcIterator(self.harmRC)
+end
+
+--- Return an iterator for checkers usable on miscellaneous units as (**range**, **checker**) pairs. These units are neither enemy nor friendly, such as people in sanctuaries or corpses.
+function lib:GetMiscCheckers()
+ return rcIterator(self.miscRC)
+end
+
+--- Return a checker suitable for out-of-range checking on friendly units, that is, a checker whose range is equal or larger than the requested range.
+-- @param range the range to check for.
+-- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for.
+function lib:GetFriendMinChecker(range)
+ return getMinChecker(self.friendRC, range)
+end
+
+--- Return a checker suitable for out-of-range checking on enemy units, that is, a checker whose range is equal or larger than the requested range.
+-- @param range the range to check for.
+-- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for.
+function lib:GetHarmMinChecker(range)
+ return getMinChecker(self.harmRC, range)
+end
+
+--- Return a checker suitable for out-of-range checking on miscellaneous units, that is, a checker whose range is equal or larger than the requested range.
+-- @param range the range to check for.
+-- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for.
+function lib:GetMiscMinChecker(range)
+ return getMinChecker(self.miscRC, range)
+end
+
+--- Return a checker suitable for in-range checking on friendly units, that is, a checker whose range is equal or smaller than the requested range.
+-- @param range the range to check for.
+-- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for.
+function lib:GetFriendMaxChecker(range)
+ return getMaxChecker(self.friendRC, range)
+end
+
+--- Return a checker suitable for in-range checking on enemy units, that is, a checker whose range is equal or smaller than the requested range.
+-- @param range the range to check for.
+-- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for.
+function lib:GetHarmMaxChecker(range)
+ return getMaxChecker(self.harmRC, range)
+end
+
+--- Return a checker suitable for in-range checking on miscellaneous units, that is, a checker whose range is equal or smaller than the requested range.
+-- @param range the range to check for.
+-- @return **checker**, **range** pair or **nil** if no suitable checker is available. **range** is the actual range the returned **checker** checks for.
+function lib:GetMiscMaxChecker(range)
+ return getMaxChecker(self.miscRC, range)
+end
+
+--- Return a checker for the given range for friendly units.
+-- @param range the range to check for.
+-- @return **checker** function or **nil** if no suitable checker is available.
+function lib:GetFriendChecker(range)
+ return getChecker(self.friendRC, range)
+end
+
+--- Return a checker for the given range for enemy units.
+-- @param range the range to check for.
+-- @return **checker** function or **nil** if no suitable checker is available.
+function lib:GetHarmChecker(range)
+ return getChecker(self.harmRC, range)
+end
+
+--- Return a checker for the given range for miscellaneous units.
+-- @param range the range to check for.
+-- @return **checker** function or **nil** if no suitable checker is available.
+function lib:GetMiscChecker(range)
+ return getChecker(self.miscRC, range)
+end
+
+--- Return a checker suitable for out-of-range checking that checks the unit type and calls the appropriate checker (friend/harm/misc).
+-- @param range the range to check for.
+-- @return **checker** function.
+function lib:GetSmartMinChecker(range)
+ return createSmartChecker(
+ getMinChecker(self.friendRC, range),
+ getMinChecker(self.harmRC, range),
+ getMinChecker(self.miscRC, range))
+end
+
+--- Return a checker suitable for in-of-range checking that checks the unit type and calls the appropriate checker (friend/harm/misc).
+-- @param range the range to check for.
+-- @return **checker** function.
+function lib:GetSmartMaxChecker(range)
+ return createSmartChecker(
+ getMaxChecker(self.friendRC, range),
+ getMaxChecker(self.harmRC, range),
+ getMaxChecker(self.miscRC, range))
+end
+
+--- Return a checker for the given range that checks the unit type and calls the appropriate checker (friend/harm/misc).
+-- @param range the range to check for.
+-- @param fallback optional fallback function that gets called as fallback(unit) if a checker is not available for the given type (friend/harm/misc) at the requested range. The default fallback function return nil.
+-- @return **checker** function.
+function lib:GetSmartChecker(range, fallback)
+ return createSmartChecker(
+ getChecker(self.friendRC, range) or fallback,
+ getChecker(self.harmRC, range) or fallback,
+ getChecker(self.miscRC, range) or fallback)
+end
+
+--- Get a range estimate as **minRange**, **maxRange**.
+-- @param unit the target unit to check range to.
+-- @return **minRange**, **maxRange** pair if a range estimate could be determined, **nil** otherwise. **maxRange** is **nil** if **unit** is further away than the highest possible range we can check.
+-- Includes checks for unit validity and friendly/enemy status.
+-- @usage
+-- local rc = LibStub("LibRangeCheck-2.0")
+-- local minRange, maxRange = rc:GetRange('target')
+function lib:GetRange(unit)
+ if not UnitExists(unit) then
+ return nil
+ end
+ if UnitIsDeadOrGhost(unit) then
+ return getRange(unit, self.miscRC)
+ end
+ if UnitCanAttack("player", unit) then
+ return getRange(unit, self.harmRC)
+ elseif UnitCanAssist("player", unit) then
+ return getRange(unit, self.friendRC)
+ else
+ return getRange(unit, self.miscRC)
+ end
+end
+
+-- keep this for compatibility
+lib.getRange = lib.GetRange
+
+-- >> Public API
+
+function lib:OnEvent(event, ...)
+ if type(self[event]) == 'function' then
+ self[event](self, event, ...)
+ end
+end
+
+function lib:LEARNED_SPELL_IN_TAB()
+ self:scheduleInit()
+end
+
+function lib:CHARACTER_POINTS_CHANGED()
+ self:scheduleInit()
+end
+
+function lib:PLAYER_TALENT_UPDATE()
+ self:scheduleInit()
+end
+
+function lib:GLYPH_ADDED()
+ self:scheduleInit()
+end
+
+function lib:GLYPH_REMOVED()
+ self:scheduleInit()
+end
+
+function lib:GLYPH_UPDATED()
+ self:scheduleInit()
+end
+
+function lib:UNIT_INVENTORY_CHANGED(event, unit)
+ if self.initialized and unit == "player" and self.handSlotItem ~= GetInventoryItemLink("player", HandSlotId) then
+ self:scheduleInit()
+ end
+end
+
+function lib:processItemRequests(itemRequests)
+ while true do
+ local range, items = next(itemRequests)
+ if not range then return end
+ while true do
+ local i, item = next(items)
+ if not i then
+ itemRequests[range] = nil
+ break
+ elseif self.failedItemRequests[item] then
+ tremove(items, i)
+ elseif GetItemInfo(item) then
+ if itemRequestTimeoutAt then
+ foundNewItems = true
+ itemRequestTimeoutAt = nil
+ end
+ if not cacheAllItems then
+ itemRequests[range] = nil
+ break
+ end
+ tremove(items, i)
+ elseif not itemRequestTimeoutAt then
+ requestItemInfo(item)
+ itemRequestTimeoutAt = GetTime() + ItemRequestTimeout
+ return true
+ elseif GetTime() > itemRequestTimeoutAt then
+ if cacheAllItems then
+ print(MAJOR_VERSION .. ": timeout for item: " .. tostring(item))
+ end
+ self.failedItemRequests[item] = true
+ itemRequestTimeoutAt = nil
+ tremove(items, i)
+ else
+ return true -- still waiting for server response
+ end
+ end
+ end
+end
+
+function lib:initialOnUpdate()
+ self:init()
+ if friendItemRequests then
+ if self:processItemRequests(friendItemRequests) then return end
+ friendItemRequests = nil
+ end
+ if harmItemRequests then
+ if self:processItemRequests(harmItemRequests) then return end
+ harmItemRequests = nil
+ end
+ if foundNewItems then
+ self:init(true)
+ foundNewItems = nil
+ end
+ if cacheAllItems then
+ print(MAJOR_VERSION .. ": finished cache")
+ cacheAllItems = nil
+ end
+ self.frame:Hide()
+end
+
+function lib:scheduleInit()
+ self.initialized = nil
+ lastUpdate = 0
+ self.frame:Show()
+end
+
+
+-- << load-time initialization
+
+function lib:activate()
+ if not self.frame then
+ local frame = CreateFrame("Frame")
+ self.frame = frame
+ frame:RegisterEvent("LEARNED_SPELL_IN_TAB")
+ frame:RegisterEvent("CHARACTER_POINTS_CHANGED")
+ frame:RegisterEvent("PLAYER_TALENT_UPDATE")
+ frame:RegisterEvent("GLYPH_ADDED")
+ frame:RegisterEvent("GLYPH_REMOVED")
+ frame:RegisterEvent("GLYPH_UPDATED")
+ local _, playerClass = UnitClass("player")
+ if playerClass == "MAGE" or playerClass == "SHAMAN" then
+ -- Mage and Shaman gladiator gloves modify spell ranges
+ frame:RegisterEvent("UNIT_INVENTORY_CHANGED")
+ end
+ end
+ initItemRequests()
+ self.frame:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
+ self.frame:SetScript("OnUpdate", function(frame, elapsed)
+ lastUpdate = lastUpdate + elapsed
+ if lastUpdate < UpdateDelay then
+ return
+ end
+ lastUpdate = 0
+ self:initialOnUpdate()
+ end)
+ self:scheduleInit()
+end
+
+--- BEGIN CallbackHandler stuff
+
+do
+ local lib = lib -- to keep a ref even though later we nil lib
+ --- Register a callback to get called when checkers are updated
+ -- @class function
+ -- @name lib.RegisterCallback
+ -- @usage
+ -- rc.RegisterCallback(self, rc.CHECKERS_CHANGED, "myCallback")
+ -- -- or
+ -- rc.RegisterCallback(self, "CHECKERS_CHANGED", someCallbackFunction)
+ -- @see CallbackHandler-1.0 documentation for more details
+ lib.RegisterCallback = lib.RegisterCallback or function(...)
+ local CBH = LibStub("CallbackHandler-1.0")
+ lib.RegisterCallback = nil -- extra safety, we shouldn't get this far if CBH is not found, but better an error later than an infinite recursion now
+ lib.callbacks = CBH:New(lib)
+ -- ok, CBH hopefully injected or new shiny RegisterCallback
+ return lib.RegisterCallback(...)
+ end
+end
+
+--- END CallbackHandler stuff
+
+lib:activate()
+lib = nil
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Libraries/Load_Libraries.xml b/ElvUI_Enhanced/Libraries/Load_Libraries.xml
new file mode 100644
index 0000000..912a9ae
--- /dev/null
+++ b/ElvUI_Enhanced/Libraries/Load_Libraries.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Locales/Load_Locales.xml b/ElvUI_Enhanced/Locales/Load_Locales.xml
new file mode 100644
index 0000000..68ff9ba
--- /dev/null
+++ b/ElvUI_Enhanced/Locales/Load_Locales.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Locales/deDE.lua b/ElvUI_Enhanced/Locales/deDE.lua
new file mode 100644
index 0000000..73f44d3
--- /dev/null
+++ b/ElvUI_Enhanced/Locales/deDE.lua
@@ -0,0 +1,237 @@
+local E = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "deDE")
+
+-- DESC locales
+L["ENH_LOGIN_MSG"] = "Sie verwenden |cff1784d1ElvUI|r |cff1784d1Enhanced|r |cffff8000(WotLK)|r Version %s%s|r."
+L["DURABILITY_DESC"] = "Passen Sie die Einstellungen für die Haltbarkeit im Charakterfenster an."
+L["ITEMLEVEL_DESC"] = "Passen Sie die Einstellungen für die Anzeige von Gegenstandsstufen im Charakterfenster an."
+L["WATCHFRAME_DESC"] = "Passen Sie die Einstellungen des Watchframe (Questlog) nach ihren Wünschen an."
+
+-- Incompatibility
+L["GearScore '3.1.20b - Release' is not for WotLK. Download 3.1.7. Disable this version?"] = true
+
+-- AddOn List
+L["Enable All"] = "Alle aktivieren"
+L["Dependencies: "] = "Abhängigkeiten"
+L["Disable All"] = "Alle deaktivieren"
+L["Load AddOn"] = "Lade AddOn"
+L["Requires Reload"] = "Benötigt Reload"
+
+-- Chat
+L["Filter DPS meters Spam"] = "Spam von DPS-Metern filtern"
+L["Replaces reports from damage meters with a clickable hyperlink to reduce chat spam"] = true
+
+-- Datatext
+L["Ammo/Shard Counter"] = true
+L["Combat Indicator"] = "Kampfanzeige"
+L["Distance"] = "Entfernung"
+L["In Combat"] = "Im Kampf"
+L["New Mail"] = "Neue Post"
+L["No Mail"] = "Keine Post"
+L["Out of Combat"] = "Außerhalb des Kampfes"
+L["Reincarnation"] = "Wiederbelebung"
+L["Target Range"] = "Zielreichweite"
+
+-- Death Recap
+L["Death Recap Frame"] = true
+L["%s %s"] = true
+L["%s by %s"] = "%s durch %s"
+L["%s sec before death at %s%% health."] = "%s Sekunden vor Tod bei %s%% Gesundheit."
+L["(%d Absorbed)"] = "(%d Absorbiert)"
+L["(%d Blocked)"] = "(%d Geblockt)"
+L["(%d Overkill)"] = "(%d Über dem Tod)"
+L["(%d Resisted)"] = "(%d Widerstanden)"
+L["Death Recap unavailable."] = "Todesursache nicht verfügbar."
+L["Death Recap"] = "Todesursache"
+L["Killing blow at %s%% health."] = "Todesstoß bei %s%% Gesundheit."
+L["You died."] = "Du bist gestorben."
+
+-- Decline Duels
+L["Auto decline all duels"] = "Auto-Ablehnen von allen Duellen"
+L["Decline Duel"] = "Duell ablehnen"
+L["Declined duel request from "] = "Duellaufforderung abgelehnt von "
+
+-- Enhanced Character Frame / Paperdoll Backgrounds
+L["Character Background"] = true
+L["Enhanced Character Frame"] = true
+L["Enhanced Model Frames"] = true
+L["Inspect Background"] = true
+L["Paperdoll Backgrounds"] = true
+L["Pet Background"] = true
+
+-- Equipment
+L["Damaged Only"] = "Nur Beschädigte"
+L["Enable/Disable the display of durability information on the character screen."] = "Anzeige der Haltbarkeit im Charakterfenster."
+L["Enable/Disable the display of item levels on the character screen."] = "Anzeige von Gegenstandsstufen im Charakterfenster aktivieren / deaktivieren."
+L["Only show durabitlity information for items that are damaged."] = "Nur die Haltbarkeit für beschädigte Ausrüstungsteile anzeigen."
+L["Quality Color"] = "Qualitätsfarbe"
+
+-- General
+L["Add button to Dressing Room frame with ability to undress model."] = true
+L["Add button to Trainer frame with ability to train all available skills in one click."] = true
+L["Alt-Click Merchant"] = true
+L["Already Known"] = true
+L["Animated Achievement Bars"] = true
+L["Automatically change your watched faction on the reputation bar to the faction you got reputation points for."] = "Ändere automatisch die beobachtete Fraktion auf der Erfahrungsleiste zu der Fraktion für die Sie grade Rufpunkte erhalten haben."
+L["Automatically release body when killed inside a battleground."] = "Gibt automatisch Ihren Geist frei, wenn Sie auf dem Schlachtfeld getötet wurden."
+L["Automatically select the quest reward with the highest vendor sell value."] = "Wählt automatisch die Questbelohnung mit dem höchsten Wiederverkaufswert beim Händler"
+L["Change color of item icons which already known."] = true
+L["Changes the transparency of all the movers."] = "Ändere die Transparenz aller Ankerpukte"
+L["Display quest levels at Quest Log."] = "Questlevel im Questlog anzeigen."
+L["Hide Zone Text"] = "Zonentext verstecken"
+L["Holding Alt key while buying something from vendor will now buy an entire stack."] = true
+L["Mover Transparency"] = "Transparenz Ankerpunkte"
+L["PvP Autorelease"] = "Automatische Freigabe im PvP"
+L["Select Quest Reward"] = "Wähle Questbelohnung"
+L["Show Quest Level"] = "Zeige Questlevel"
+L["Track Reputation"] = "Ruf beobachten"
+L["Train All Button"] = true
+L["Undress Button"] = true
+L["Undress"] = "Ausziehen"
+
+-- HD Models Portrait Fix
+L["Debug"] = true
+L["List of models with broken portrait camera. Separete each model name with ';' simbol"] = true
+L["Models to fix"] = true
+L["Portrait HD Fix"] = true
+L["Print to chat model names of units with enabled 3D portraits."] = true
+
+-- Interrupt Tracker
+L["Interrupt Tracker"] = true
+
+-- Nameplates
+L["Cache Unit Class"] = true
+
+-- Minimap
+L["Above Minimap"] = "Oberhalb der Minimap"
+L["Combat Hide"] = true
+L["FadeIn Delay"] = "Einblendungsverzögerung"
+L["Hide minimap while in combat."] = "Ausblenden der Minimap während des Kampfes."
+L["Show Location Digits"] = "Koordinaten einblenden"
+L["Toggle Location Digits."] = "Koordinaten ein- oder ausblenden."
+L["Location Digits"] = "Koordinaten Nachkommastellen"
+L["Location Panel"] = "Standort-Panel"
+L["Number of digits for map location."] = "Anzahl der Nachkommastellen der Koordinaten."
+L["The time to wait before fading the minimap back in after combat hide. (0 = Disabled)"] = "Die Zeit vor dem wieder Einblenden der Minimap nach dem Kampf. (0 = deaktiviert)"
+L["Toggle Location Panel."] = "Umschalten des Standort-Panels"
+
+-- Timer Tracker
+L["Timer Tracker"] = true
+L["Hook DBM"] = true
+
+-- Tooltip
+L["Check Player"] = true
+L["Colorize the tooltip border based on item quality."] = "Färbe den Tooltip-Rahmen basierend auf der Gegenstandsqualität"
+L["Check achievement completion instead of boss kill stats.\nSome servers log incorrect boss kill statistics, this is an alternative way to get player progress."] = true
+L["Icecrown Citadel"] = true
+L["Item Border Color"] = "Gegenstandsrahmen-Farbe"
+L["Progress Info"] = true
+L["Ruby Sanctum"] = true
+L["Show/Hides an Icon for Achievements on the Tooltip."] = "Icon für Erfolge am Tooltip anzeigen oder ausblenden."
+L["Show/Hides an Icon for Items on the Tooltip."] = "Icon für Gegenstände am Tooltip anzeigen oder ausblenden."
+L["Show/Hides an Icon for Spells on the Tooltip."] = "Icon für Zauber am Tooltip anzeigen oder ausblenden."
+L["Show/Hides an Icon for Spells and Items on the Tooltip."] = "Icon für Zauber oder Gegenstände am Tooltip anzeigen oder ausblenden."
+L["Tiers"] = true
+L["Tooltip Icon"] = true
+L["Trial of the Crusader"] = true
+L["Ulduar"] = true
+
+-- Movers
+L["Loss Control"] = "Kontrollverlust"
+L["Player Portrait"] = "Spieler-Portrait"
+L["Target Portrait"] = "Ziel-Portrait"
+
+-- Loss Control
+L["CC"] = "CC"
+L["Disarm"] = "Entwaffnen"
+L["Lose Control"] = true
+L["PvE"] = "PvE"
+L["Root"] = "Wurzeln"
+L["Silence"] = "Stille"
+L["Snare"] = "Verlangsamung"
+
+-- Unitframes
+L["Class Icons"] = "Klassensymbole"
+L["Detached Height"] = "Höhe loslösen"
+L["Show class icon for units."] = "Zeige Klassensymbole für Einheiten"
+
+-- WatchFrame
+L["City (Resting)"] = "Stadt (erholend)"
+L["Collapsed"] = "Eingeklappt"
+L["Hidden"] = "Versteckt"
+L["Party"] = "Gruppe"
+L["PvP"] = "PvP"
+L["Raid"] = "Schlachtzug"
+
+--
+L["Drag"] = true
+L["Left-click on character and drag to rotate."] = true
+L["Mouse Wheel Down"] = true
+L["Mouse Wheel Up"] = true
+L["Reset Position"] = "Position zurücksetzen"
+L["Right-click on character and drag to move it within the window."] = true
+L["Rotate Left"] = true
+L["Rotate Right"] = true
+L["Zoom In"] = true
+L["Zoom Out"] = true
+
+--
+L["Character Stats"] = true
+L["Damage Per Second"] = "DPS"
+L["Equipment Manager"] = true
+L["Hide Character Information"] = true
+L["Hide Pet Information"] = true
+L["Item Level"] = "Itemlevel"
+L["New Set"] = true
+L["Resistance"] = true
+L["Show Character Information"] = true
+L["Show Pet Information"] = true
+L["Titles"] = true
+L["Total Companions"] = true
+L["Total Mounts"] = true
+
+L["ALL"] = "Alle"
+L["ALT_KEY"] = "ALT-Taste"
+
+L["%d mails\nShift-Click to remove empty mails."] = true
+L["Addon |cffFFD100%s|r was merged into |cffFFD100ElvUI_Enhanced|r.\nPlease remove it to avoid conflicts."] = true
+L["Cache Unit Guilds / NPC Titles"] = true
+L["Check Achievements"] = true
+L["Collected "] = true
+L["Collection completed."] = true
+L["Collection stopped, inventory is full."] = true
+L["Color based on reaction type."] = true
+L["Compact mode"] = true
+L["Companion Background"] = true
+L["Desaturate"] = true
+L["Detached Portrait"] = true
+L["Dressing Room"] = true
+L["Enhanced"] = true
+L["Equipment Info"] = true
+L["Error Frame"] = true
+L["Everywhere"] = true
+L["Fog of War"] = true
+L["Grow direction"] = true
+L["Guild"] = true
+L["Inside Minimap"] = true
+L["Key Press Animation"] = true
+L["Map"] = true
+L["Minimap Button Grabber"] = true
+L["NPC"] = "NSC"
+L["Overlay Color"] = true
+L["Reaction Color"] = true
+L["Reported by %s"] = true
+L["Rotation"] = true
+L["Separator"] = true
+L["Set the height of Error Frame. Higher frame can show more lines at once."] = true
+L["Set the width of Error Frame. Too narrow frame may cause messages to be split in several lines"] = true
+L["Show Everywhere"] = true
+L["Show on Arena."] = true
+L["Show on Battleground."] = true
+L["Smooth Animations"] = true
+L["Take All"] = true
+L["Take All Mail"] = true
+L["Take Cash"] = true
+L["This addon has been disabled. You should install an updated version."] = true
+L["Where to show"] = true
+L["seconds"] = true
diff --git a/ElvUI_Enhanced/Locales/enUS.lua b/ElvUI_Enhanced/Locales/enUS.lua
new file mode 100644
index 0000000..f71c75b
--- /dev/null
+++ b/ElvUI_Enhanced/Locales/enUS.lua
@@ -0,0 +1,237 @@
+local E = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "enUS", true)
+
+-- DESC locales
+L["ENH_LOGIN_MSG"] = "You are using |cff1784d1ElvUI Enhanced|r |cffff8000(WotLK)|r version %s%s|r."
+L["DURABILITY_DESC"] = "Adjust the settings for the durability information on the character screen."
+L["ITEMLEVEL_DESC"] = "Adjust the settings for the item level information on the character screen."
+L["WATCHFRAME_DESC"] = "Adjust the settings for the visibility of the watchframe (questlog) to your personal preference."
+
+-- Incompatibility
+L["GearScore '3.1.20b - Release' is not for WotLK. Download 3.1.7. Disable this version?"] = true
+
+-- AddOn List
+L["Enable All"] = true
+L["Dependencies: "] = true
+L["Disable All"] = true
+L["Load AddOn"] = true
+L["Requires Reload"] = true
+
+-- Chat
+L["Filter DPS meters Spam"] = true
+L["Replaces reports from damage meters with a clickable hyperlink to reduce chat spam"] = true
+
+-- Datatext
+L["Death Recap Frame"] = true
+L["Ammo/Shard Counter"] = true
+L["Combat Indicator"] = true
+L["Distance"] = true
+L["In Combat"] = true
+L["New Mail"] = true
+L["No Mail"] = true
+L["Out of Combat"] = true
+L["Reincarnation"] = true
+L["Target Range"] = true
+
+-- Death Recap
+L["%s %s"] = true
+L["%s by %s"] = true
+L["%s sec before death at %s%% health."] = true
+L["(%d Absorbed)"] = true
+L["(%d Blocked)"] = true
+L["(%d Overkill)"] = true
+L["(%d Resisted)"] = true
+L["Death Recap unavailable."] = true
+L["Death Recap"] = true
+L["Killing blow at %s%% health."] = true
+L["You died."] = true
+
+-- Decline Duels
+L["Auto decline all duels"] = true
+L["Decline Duel"] = true
+L["Declined duel request from "] = true
+
+-- Enhanced Character Frame / Paperdoll Backgrounds
+L["Character Background"] = true
+L["Enhanced Character Frame"] = true
+L["Inspect Background"] = true
+L["Enhanced Model Frames"] = true
+L["Paperdoll Backgrounds"] = true
+L["Pet Background"] = true
+
+-- Equipment
+L["Damaged Only"] = true
+L["Enable/Disable the display of durability information on the character screen."] = true
+L["Enable/Disable the display of item levels on the character screen."] = true
+L["Only show durabitlity information for items that are damaged."] = true
+L["Quality Color"] = true
+
+-- General
+L["Add button to Dressing Room frame with ability to undress model."] = true
+L["Add button to Trainer frame with ability to train all available skills in one click."] = true
+L["Alt-Click Merchant"] = true
+L["Already Known"] = true
+L["Animated Achievement Bars"] = true
+L["Automatically change your watched faction on the reputation bar to the faction you got reputation points for."] = true
+L["Automatically release body when killed inside a battleground."] = true
+L["Automatically select the quest reward with the highest vendor sell value."] = true
+L["Change color of item icons which already known."] = true
+L["Changes the transparency of all the movers."] = true
+L["Display quest levels at Quest Log."] = true
+L["Hide Zone Text"] = true
+L["Holding Alt key while buying something from vendor will now buy an entire stack."] = true
+L["Mover Transparency"] = true
+L["PvP Autorelease"] = true
+L["Select Quest Reward"] = true
+L["Show Quest Level"] = true
+L["Track Reputation"] = true
+L["Train All Button"] = true
+L["Undress Button"] = true
+L["Undress"] = true
+
+-- HD Models Portrait Fix
+L["Debug"] = true
+L["List of models with broken portrait camera. Separete each model name with ';' simbol"] = true
+L["Models to fix"] = true
+L["Portrait HD Fix"] = true
+L["Print to chat model names of units with enabled 3D portraits."] = true
+
+-- Interrupt Tracker
+L["Interrupt Tracker"] = true
+
+-- Nameplates
+L["Cache Unit Class"] = true
+
+-- Minimap
+L["Above Minimap"] = true
+L["Combat Hide"] = true
+L["FadeIn Delay"] = true
+L["Hide minimap while in combat."] = true
+L["Show Location Digits"] = true
+L["Toggle Location Digits."] = true
+L["Location Digits"] = true
+L["Location Panel"] = true
+L["Number of digits for map location."] = true
+L["The time to wait before fading the minimap back in after combat hide. (0 = Disabled)"] = true
+L["Toggle Location Panel."] = true
+
+-- Timer Tracker
+L["Timer Tracker"] = true
+L["Hook DBM"] = true
+
+-- Tooltip
+L["Check Player"] = true
+L["Check achievement completion instead of boss kill stats.\nSome servers log incorrect boss kill statistics, this is an alternative way to get player progress."] = true
+L["Colorize the tooltip border based on item quality."] = true
+L["Icecrown Citadel"] = true
+L["Item Border Color"] = true
+L["Progress Info"] = true
+L["Ruby Sanctum"] = true
+L["Show/Hides an Icon for Achievements on the Tooltip."] = true
+L["Show/Hides an Icon for Items on the Tooltip."] = true
+L["Show/Hides an Icon for Spells and Items on the Tooltip."] = true
+L["Show/Hides an Icon for Spells on the Tooltip."] = true
+L["Tiers"] = true
+L["Tooltip Icon"] = true
+L["Trial of the Crusader"] = true
+L["Ulduar"] = true
+
+-- Movers
+L["Loss Control"] = true
+L["Player Portrait"] = true
+L["Target Portrait"] = true
+
+-- Lose Control
+L["CC"] = true
+L["Disarm"] = true
+L["Lose Control"] = true
+L["PvE"] = true
+L["Root"] = true
+L["Silence"] = true
+L["Snare"] = true
+
+-- Unitframes
+L["Class Icons"] = true
+L["Detached Height"] = true
+L["Show class icon for units."] = true
+
+-- WatchFrame
+L["Hidden"] = true
+L["Collapsed"] = true
+L["City (Resting)"] = true
+L["PvP"] = true
+L["Party"] = true
+L["Raid"] = true
+
+--
+L["Drag"] = true
+L["Left-click on character and drag to rotate."] = true
+L["Mouse Wheel Down"] = true
+L["Mouse Wheel Up"] = true
+L["Reset Position"] = true
+L["Right-click on character and drag to move it within the window."] = true
+L["Rotate Left"] = true
+L["Rotate Right"] = true
+L["Zoom In"] = true
+L["Zoom Out"] = true
+
+--
+L["Character Stats"] = true
+L["Damage Per Second"] = "DPS"
+L["Equipment Manager"] = true
+L["Hide Character Information"] = true
+L["Hide Pet Information"] = true
+L["Item Level"] = true
+L["New Set"] = true
+L["Resistance"] = true
+L["Show Character Information"] = true
+L["Show Pet Information"] = true
+L["Titles"] = true
+L["Total Companions"] = true
+L["Total Mounts"] = true
+
+L["ALL"] = "All"
+L["ALT_KEY"] = "ALT key"
+
+L["%d mails\nShift-Click to remove empty mails."] = true
+L["Addon |cffFFD100%s|r was merged into |cffFFD100ElvUI_Enhanced|r.\nPlease remove it to avoid conflicts."] = true
+L["Cache Unit Guilds / NPC Titles"] = true
+L["Check Achievements"] = true
+L["Collected "] = true
+L["Collection completed."] = true
+L["Collection stopped, inventory is full."] = true
+L["Color based on reaction type."] = true
+L["Compact mode"] = true
+L["Companion Background"] = true
+L["Desaturate"] = true
+L["Detached Portrait"] = true
+L["Dressing Room"] = true
+L["Enhanced"] = true
+L["Equipment Info"] = true
+L["Error Frame"] = true
+L["Everywhere"] = true
+L["Fog of War"] = true
+L["Grow direction"] = true
+L["Guild"] = true
+L["Inside Minimap"] = true
+L["Key Press Animation"] = true
+L["Map"] = true
+L["Minimap Button Grabber"] = true
+L["NPC"] = true
+L["Overlay Color"] = true
+L["Reaction Color"] = true
+L["Reported by %s"] = true
+L["Rotation"] = true
+L["Separator"] = true
+L["Set the height of Error Frame. Higher frame can show more lines at once."] = true
+L["Set the width of Error Frame. Too narrow frame may cause messages to be split in several lines"] = true
+L["Show Everywhere"] = true
+L["Show on Arena."] = true
+L["Show on Battleground."] = true
+L["Smooth Animations"] = true
+L["Take All"] = true
+L["Take All Mail"] = true
+L["Take Cash"] = true
+L["This addon has been disabled. You should install an updated version."] = true
+L["Where to show"] = true
+L["seconds"] = true
diff --git a/ElvUI_Enhanced/Locales/esMX.lua b/ElvUI_Enhanced/Locales/esMX.lua
new file mode 100644
index 0000000..ad902cc
--- /dev/null
+++ b/ElvUI_Enhanced/Locales/esMX.lua
@@ -0,0 +1,237 @@
+local E = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "esMX")
+
+-- DESC locales
+L["ENH_LOGIN_MSG"] = "You are using |cff1784d1ElvUI Enhanced|r |cffff8000(WotLK)|r version %s%s|r."
+L["DURABILITY_DESC"] = "Adjust the settings for the durability information on the character screen."
+L["ITEMLEVEL_DESC"] = "Adjust the settings for the item level information on the character screen."
+L["WATCHFRAME_DESC"] = "Adjust the settings for the visibility of the watchframe (questlog) to your personal preference."
+
+-- Incompatibility
+L["GearScore '3.1.20b - Release' is not for WotLK. Download 3.1.7. Disable this version?"] = true
+
+-- AddOn List
+L["Enable All"] = true
+L["Dependencies: "] = true
+L["Disable All"] = true
+L["Load AddOn"] = true
+L["Requires Reload"] = true
+
+-- Chat
+L["Filter DPS meters Spam"] = true
+L["Replaces reports from damage meters with a clickable hyperlink to reduce chat spam"] = true
+
+-- Datatext
+L["Ammo/Shard Counter"] = true
+L["Combat Indicator"] = true
+L["Distance"] = true
+L["In Combat"] = true
+L["New Mail"] = true
+L["No Mail"] = true
+L["Out of Combat"] = true
+L["Reincarnation"] = true
+L["Target Range"] = true
+
+-- Death Recap
+L["Death Recap Frame"] = true
+L["%s %s"] = true
+L["%s by %s"] = true
+L["%s sec before death at %s%% health."] = true
+L["(%d Absorbed)"] = true
+L["(%d Blocked)"] = true
+L["(%d Overkill)"] = true
+L["(%d Resisted)"] = true
+L["Death Recap unavailable."] = true
+L["Death Recap"] = true
+L["Killing blow at %s%% health."] = true
+L["You died."] = true
+
+-- Decline Duels
+L["Auto decline all duels"] = true
+L["Decline Duel"] = true
+L["Declined duel request from "] = "Duelo rechazado de "
+
+-- Enhanced Character Frame / Paperdoll Backgrounds
+L["Character Background"] = true
+L["Enhanced Character Frame"] = true
+L["Enhanced Model Frames"] = true
+L["Inspect Background"] = true
+L["Paperdoll Backgrounds"] = true
+L["Pet Background"] = true
+
+-- Equipment
+L["Damaged Only"] = true
+L["Enable/Disable the display of durability information on the character screen."] = true
+L["Enable/Disable the display of item levels on the character screen."] = true
+L["Only show durabitlity information for items that are damaged."] = true
+L["Quality Color"] = true
+
+-- General
+L["Add button to Dressing Room frame with ability to undress model."] = true
+L["Add button to Trainer frame with ability to train all available skills in one click."] = true
+L["Alt-Click Merchant"] = true
+L["Already Known"] = true
+L["Animated Achievement Bars"] = true
+L["Automatically change your watched faction on the reputation bar to the faction you got reputation points for."] = true
+L["Automatically release body when killed inside a battleground."] = true
+L["Automatically select the quest reward with the highest vendor sell value."] = true
+L["Change color of item icons which already known."] = true
+L["Changes the transparency of all the movers."] = true
+L["Display quest levels at Quest Log."] = true
+L["Hide Zone Text"] = true
+L["Holding Alt key while buying something from vendor will now buy an entire stack."] = true
+L["Mover Transparency"] = true
+L["PvP Autorelease"] = true
+L["Select Quest Reward"] = true
+L["Show Quest Level"] = true
+L["Track Reputation"] = true
+L["Train All Button"] = true
+L["Undress Button"] = true
+L["Undress"] = true
+
+-- HD Models Portrait Fix
+L["Debug"] = true
+L["List of models with broken portrait camera. Separete each model name with ';' simbol"] = true
+L["Models to fix"] = true
+L["Portrait HD Fix"] = true
+L["Print to chat model names of units with enabled 3D portraits."] = true
+
+-- Interrupt Tracker
+L["Interrupt Tracker"] = true
+
+-- Nameplates
+L["Cache Unit Class"] = true
+
+-- Minimap
+L["Above Minimap"] = true
+L["Combat Hide"] = true
+L["FadeIn Delay"] = true
+L["Hide minimap while in combat."] = true
+L["Show Location Digits"] = true
+L["Toggle Location Digits."] = true
+L["Location Digits"] = true
+L["Location Panel"] = true
+L["Number of digits for map location."] = true
+L["The time to wait before fading the minimap back in after combat hide. (0 = Disabled)"] = true
+L["Toggle Location Panel."] = true
+
+-- Timer Tracker
+L["Timer Tracker"] = true
+L["Hook DBM"] = true
+
+-- Tooltip
+L["Check Player"] = true
+L["Check achievement completion instead of boss kill stats.\nSome servers log incorrect boss kill statistics, this is an alternative way to get player progress."] = true
+L["Colorize the tooltip border based on item quality."] = true
+L["Icecrown Citadel"] = true
+L["Item Border Color"] = true
+L["Progress Info"] = true
+L["Ruby Sanctum"] = true
+L["Show/Hides an Icon for Achievements on the Tooltip."] = true
+L["Show/Hides an Icon for Items on the Tooltip."] = true
+L["Show/Hides an Icon for Spells on the Tooltip."] = true
+L["Show/Hides an Icon for Spells and Items on the Tooltip."] = true
+L["Tiers"] = true
+L["Tooltip Icon"] = true
+L["Trial of the Crusader"] = true
+L["Ulduar"] = true
+
+-- Movers
+L["Loss Control"] = "Pérdida de Control"
+L["Player Portrait"] = true
+L["Target Portrait"] = true
+
+-- Loss Control
+L["CC"] = "CC"
+L["Disarm"] = "Desarme"
+L["Lose Control"] = true
+L["PvE"] = "PvE"
+L["Root"] = "Inmovilice"
+L["Silence"] = "Silencio"
+L["Snare"] = "Trampa"
+
+-- Unitframes
+L["Class Icons"] = true
+L["Detached Height"] = true
+L["Show class icon for units."] = true
+
+-- WatchFrame
+L["Hidden"] = true
+L["Collapsed"] = true
+L["City (Resting)"] = true
+L["PvP"] = true
+L["Party"] = true
+L["Raid"] = true
+
+--
+L["Drag"] = true
+L["Left-click on character and drag to rotate."] = true
+L["Mouse Wheel Down"] = true
+L["Mouse Wheel Up"] = true
+L["Reset Position"] = "Reestablecer Posición"
+L["Right-click on character and drag to move it within the window."] = true
+L["Rotate Left"] = true
+L["Rotate Right"] = true
+L["Zoom In"] = true
+L["Zoom Out"] = true
+
+--
+L["Character Stats"] = true
+L["Damage Per Second"] = "DPS"
+L["Equipment Manager"] = true
+L["Hide Character Information"] = true
+L["Hide Pet Information"] = true
+L["Item Level"] = true
+L["New Set"] = true
+L["Resistance"] = true
+L["Show Character Information"] = true
+L["Show Pet Information"] = true
+L["Titles"] = true
+L["Total Companions"] = true
+L["Total Mounts"] = true
+
+L["ALL"] = "Todo"
+L["ALT_KEY"] = "Alt"
+
+L["%d mails\nShift-Click to remove empty mails."] = true
+L["Addon |cffFFD100%s|r was merged into |cffFFD100ElvUI_Enhanced|r.\nPlease remove it to avoid conflicts."] = true
+L["Cache Unit Guilds / NPC Titles"] = true
+L["Check Achievements"] = true
+L["Collected "] = true
+L["Collection completed."] = true
+L["Collection stopped, inventory is full."] = true
+L["Color based on reaction type."] = true
+L["Compact mode"] = true
+L["Companion Background"] = true
+L["Desaturate"] = true
+L["Detached Portrait"] = true
+L["Dressing Room"] = true
+L["Enhanced"] = true
+L["Equipment Info"] = true
+L["Error Frame"] = true
+L["Everywhere"] = true
+L["Fog of War"] = true
+L["Grow direction"] = true
+L["Guild"] = true
+L["Inside Minimap"] = true
+L["Key Press Animation"] = true
+L["Map"] = true
+L["Minimap Button Grabber"] = true
+L["NPC"] = true
+L["Overlay Color"] = true
+L["Reaction Color"] = true
+L["Reported by %s"] = true
+L["Rotation"] = true
+L["Separator"] = true
+L["Set the height of Error Frame. Higher frame can show more lines at once."] = true
+L["Set the width of Error Frame. Too narrow frame may cause messages to be split in several lines"] = true
+L["Show Everywhere"] = true
+L["Show on Arena."] = true
+L["Show on Battleground."] = true
+L["Smooth Animations"] = true
+L["Take All"] = true
+L["Take All Mail"] = true
+L["Take Cash"] = true
+L["This addon has been disabled. You should install an updated version."] = true
+L["Where to show"] = true
+L["seconds"] = true
diff --git a/ElvUI_Enhanced/Locales/frFR.lua b/ElvUI_Enhanced/Locales/frFR.lua
new file mode 100644
index 0000000..9e4cb12
--- /dev/null
+++ b/ElvUI_Enhanced/Locales/frFR.lua
@@ -0,0 +1,237 @@
+local E = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "frFR")
+
+-- DESC locales
+L["ENH_LOGIN_MSG"] = "Vous utilisez |cff1784d1ElvUI|r |cff1784d1Enhanced|r |cffff8000(WotLK)|r version %s%s|r."
+L["DURABILITY_DESC"] = "Ajustez les réglages pour afficher la durabilité sur l'écran d'infos de personnage."
+L["ITEMLEVEL_DESC"] = "Réglez les paramètres pour afficher le niveau d'objet sur l'écran d'infos de personnage."
+L["WATCHFRAME_DESC"] = "Adjust the settings for the visibility of the watchframe (questlog) to your personal preference."
+
+-- Incompatibility
+L["GearScore '3.1.20b - Release' is not for WotLK. Download 3.1.7. Disable this version?"] = true
+
+-- AddOn List
+L["Enable All"] = true
+L["Dependencies: "] = true
+L["Disable All"] = true
+L["Load AddOn"] = true
+L["Requires Reload"] = true
+
+-- Chat
+L["Filter DPS meters Spam"] = true
+L["Replaces reports from damage meters with a clickable hyperlink to reduce chat spam"] = true
+
+-- Datatext
+L["Ammo/Shard Counter"] = true
+L["Combat Indicator"] = true
+L["Distance"] = true
+L["In Combat"] = true
+L["New Mail"] = true
+L["No Mail"] = true
+L["Out of Combat"] = true
+L["Reincarnation"] = true
+L["Target Range"] = true
+
+-- Death Recap
+L["Death Recap Frame"] = true
+L["%s %s"] = true
+L["%s by %s"] = true
+L["%s sec before death at %s%% health."] = true
+L["(%d Absorbed)"] = true
+L["(%d Blocked)"] = true
+L["(%d Overkill)"] = true
+L["(%d Resisted)"] = true
+L["Death Recap unavailable."] = true
+L["Death Recap"] = "Récapitulatif lors de la mort"
+L["Killing blow at %s%% health."] = true
+L["You died."] = true
+
+-- Decline Duels
+L["Auto decline all duels"] = true
+L["Decline Duel"] = true
+L["Declined duel request from "] = "Décliné les invites en duel de "
+
+-- Enhanced Character Frame / Paperdoll Backgrounds
+L["Character Background"] = true
+L["Enhanced Character Frame"] = true
+L["Enhanced Model Frames"] = true
+L["Inspect Background"] = true
+L["Paperdoll Backgrounds"] = true
+L["Pet Background"] = true
+
+-- Equipment
+L["Damaged Only"] = "Dégâts seulement"
+L["Enable/Disable the display of durability information on the character screen."] = "Activer / Désactiver l'affichage des informations de durabilité sur l'écran d'infos de personnage."
+L["Enable/Disable the display of item levels on the character screen."] = "Activer / Désactiver l'affichage des informations du niveau d'objet sur l'écran d'infos de personnage."
+L["Only show durabitlity information for items that are damaged."] = "Afficher la durabilité seulement quand l'équipement est endommagé."
+L["Quality Color"] = true
+
+-- General
+L["Add button to Dressing Room frame with ability to undress model."] = true
+L["Add button to Trainer frame with ability to train all available skills in one click."] = true
+L["Alt-Click Merchant"] = true
+L["Already Known"] = true
+L["Animated Achievement Bars"] = true
+L["Automatically change your watched faction on the reputation bar to the faction you got reputation points for."] = "Change automatiquement la réputation suivie sur la barre de réputation avec la faction que vous êtes en train de faire."
+L["Automatically release body when killed inside a battleground."] = "Libère automatiquement votre corps quand vous êtes tué en Champs de Bataille."
+L["Automatically select the quest reward with the highest vendor sell value."] = "Sélectionne automatiquement la récompense de quête qui vaut la plus chère chez le vendeur."
+L["Changes the transparency of all the movers."] = "Change la transparence des Ancres"
+L["Change color of item icons which already known."] = true
+L["Display quest levels at Quest Log."] = true
+L["Hide Zone Text"] = true
+L["Holding Alt key while buying something from vendor will now buy an entire stack."] = true
+L["Mover Transparency"] = "Transparence des Ancres"
+L["PvP Autorelease"] = "Libération automatique en PVP"
+L["Select Quest Reward"] = "Sélection de la récompense de quête"
+L["Show Quest Level"] = true
+L["Track Reputation"] = "Suivre la Réputation"
+L["Train All Button"] = true
+L["Undress Button"] = true
+L["Undress"] = "Déshabillé"
+
+-- HD Models Portrait Fix
+L["Debug"] = true
+L["List of models with broken portrait camera. Separete each model name with ';' simbol"] = true
+L["Models to fix"] = true
+L["Portrait HD Fix"] = true
+L["Print to chat model names of units with enabled 3D portraits."] = true
+
+-- Interrupt Tracker
+L["Interrupt Tracker"] = true
+
+-- Nameplates
+L["Cache Unit Class"] = true
+
+-- Minimap
+L["Above Minimap"] = "Sous la minicarte"
+L["Combat Hide"] = true
+L["FadeIn Delay"] = "Délais d'estompage"
+L["Hide minimap while in combat."] = "Cacher la minicarte quand vous êtes en combat"
+L["Show Location Digits"] = true
+L["Toggle Location Digits."] = true
+L["Location Digits"] = "Chiffres d'emplacement"
+L["Location Panel"] = true
+L["Number of digits for map location."] = "Nombre de chiffres pour l'emplacement."
+L["The time to wait before fading the minimap back in after combat hide. (0 = Disabled)"] = "Le temps à attendre avant que la minicarte s'estompe avec que le combat ait commencé. (0 = désactié)"
+L["Toggle Location Panel."] = true
+
+-- Timer Tracker
+L["Timer Tracker"] = true
+L["Hook DBM"] = true
+
+-- Tooltip
+L["Check Player"] = true
+L["Check achievement completion instead of boss kill stats.\nSome servers log incorrect boss kill statistics, this is an alternative way to get player progress."] = true
+L["Colorize the tooltip border based on item quality."] = true
+L["Icecrown Citadel"] = true
+L["Item Border Color"] = true
+L["Progress Info"] = true
+L["Ruby Sanctum"] = true
+L["Show/Hides an Icon for Achievements on the Tooltip."] = true
+L["Show/Hides an Icon for Items on the Tooltip."] = true
+L["Show/Hides an Icon for Spells on the Tooltip."] = true
+L["Show/Hides an Icon for Spells and Items on the Tooltip."] = true
+L["Tiers"] = true
+L["Tooltip Icon"] = true
+L["Trial of the Crusader"] = true
+L["Ulduar"] = true
+
+-- Movers
+L["Loss Control"] = "Perte de contrôle"
+L["Player Portrait"] = true
+L["Target Portrait"] = true
+
+-- Loss Control
+L["CC"] = "CC"
+L["Disarm"] = "Désarmement"
+L["Lose Control"] = true
+L["PvE"] = "PvE"
+L["Root"] = "Immobilisation"
+L["Silence"] = "Silence"
+L["Snare"] = "Ralentissement"
+
+-- Unitframes
+L["Class Icons"] = true
+L["Detached Height"] = true
+L["Show class icon for units."] = true
+
+-- WatchFrame
+L["Hidden"] = "Caché"
+L["Collapsed"] = "Replié"
+L["City (Resting)"] = "Ville (repos)"
+L["PvP"] = "PvP"
+L["Party"] = "Groupe"
+L["Raid"] = "Raid"
+
+--
+L["Drag"] = true
+L["Left-click on character and drag to rotate."] = true
+L["Mouse Wheel Down"] = true
+L["Mouse Wheel Up"] = true
+L["Reset Position"] = "Réinitialiser la position"
+L["Right-click on character and drag to move it within the window."] = true
+L["Rotate Left"] = true
+L["Rotate Right"] = true
+L["Zoom In"] = true
+L["Zoom Out"] = true
+
+--
+L["Character Stats"] = true
+L["Damage Per Second"] = "DPS"
+L["Equipment Manager"] = true
+L["Hide Character Information"] = true
+L["Hide Pet Information"] = true
+L["Item Level"] = "Niveau d'objet"
+L["New Set"] = true
+L["Resistance"] = true
+L["Show Character Information"] = true
+L["Show Pet Information"] = true
+L["Titles"] = true
+L["Total Companions"] = true
+L["Total Mounts"] = true
+
+L["ALL"] = "Tous"
+L["ALT_KEY"] = "Touche ALT"
+
+L["%d mails\nShift-Click to remove empty mails."] = true
+L["Addon |cffFFD100%s|r was merged into |cffFFD100ElvUI_Enhanced|r.\nPlease remove it to avoid conflicts."] = true
+L["Cache Unit Guilds / NPC Titles"] = true
+L["Check Achievements"] = true
+L["Collected "] = true
+L["Collection completed."] = true
+L["Collection stopped, inventory is full."] = true
+L["Color based on reaction type."] = true
+L["Compact mode"] = true
+L["Companion Background"] = true
+L["Desaturate"] = true
+L["Detached Portrait"] = true
+L["Dressing Room"] = true
+L["Enhanced"] = true
+L["Equipment Info"] = true
+L["Error Frame"] = true
+L["Everywhere"] = true
+L["Fog of War"] = true
+L["Grow direction"] = true
+L["Guild"] = true
+L["Inside Minimap"] = true
+L["Key Press Animation"] = true
+L["Map"] = true
+L["Minimap Button Grabber"] = true
+L["NPC"] = true
+L["Overlay Color"] = true
+L["Reaction Color"] = true
+L["Reported by %s"] = true
+L["Rotation"] = true
+L["Separator"] = true
+L["Set the height of Error Frame. Higher frame can show more lines at once."] = true
+L["Set the width of Error Frame. Too narrow frame may cause messages to be split in several lines"] = true
+L["Show Everywhere"] = true
+L["Show on Arena."] = true
+L["Show on Battleground."] = true
+L["Smooth Animations"] = true
+L["Take All"] = true
+L["Take All Mail"] = true
+L["Take Cash"] = true
+L["This addon has been disabled. You should install an updated version."] = true
+L["Where to show"] = true
+L["seconds"] = true
diff --git a/ElvUI_Enhanced/Locales/koKR.lua b/ElvUI_Enhanced/Locales/koKR.lua
new file mode 100644
index 0000000..e855aea
--- /dev/null
+++ b/ElvUI_Enhanced/Locales/koKR.lua
@@ -0,0 +1,237 @@
+local E = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "koKR")
+
+-- DESC locales
+L["ENH_LOGIN_MSG"] = "You are using |cff1784d1ElvUI Enhanced|r |cffff8000(WotLK)|r version %s%s|r."
+L["DURABILITY_DESC"] = "Adjust the settings for the durability information on the character screen."
+L["ITEMLEVEL_DESC"] = "Adjust the settings for the item level information on the character screen."
+L["WATCHFRAME_DESC"] = "Adjust the settings for the visibility of the watchframe (questlog) to your personal preference."
+
+-- Incompatibility
+L["GearScore '3.1.20b - Release' is not for WotLK. Download 3.1.7. Disable this version?"] = true
+
+-- AddOn List
+L["Enable All"] = true
+L["Dependencies: "] = true
+L["Disable All"] = true
+L["Load AddOn"] = true
+L["Requires Reload"] = true
+
+-- Chat
+L["Filter DPS meters Spam"] = true
+L["Replaces reports from damage meters with a clickable hyperlink to reduce chat spam"] = true
+
+-- Datatext
+L["Ammo/Shard Counter"] = true
+L["Combat Indicator"] = true
+L["Distance"] = true
+L["In Combat"] = true
+L["New Mail"] = true
+L["No Mail"] = true
+L["Out of Combat"] = true
+L["Reincarnation"] = true
+L["Target Range"] = true
+
+-- Death Recap
+L["Death Recap Frame"] = true
+L["%s %s"] = true
+L["%s by %s"] = true
+L["%s sec before death at %s%% health."] = true
+L["(%d Absorbed)"] = true
+L["(%d Blocked)"] = true
+L["(%d Overkill)"] = true
+L["(%d Resisted)"] = true
+L["Death Recap unavailable."] = true
+L["Death Recap"] = true
+L["Killing blow at %s%% health."] = true
+L["You died."] = true
+
+-- Decline Duels
+L["Auto decline all duels"] = true
+L["Decline Duel"] = true
+L["Declined duel request from "] = true
+
+-- Enhanced Character Frame / Paperdoll Backgrounds
+L["Character Background"] = true
+L["Enhanced Character Frame"] = true
+L["Enhanced Model Frames"] = true
+L["Inspect Background"] = true
+L["Paperdoll Backgrounds"] = true
+L["Pet Background"] = true
+
+-- Equipment
+L["Damaged Only"] = true
+L["Enable/Disable the display of durability information on the character screen."] = true
+L["Enable/Disable the display of item levels on the character screen."] = true
+L["Only show durabitlity information for items that are damaged."] = true
+L["Quality Color"] = true
+
+-- General
+L["Add button to Dressing Room frame with ability to undress model."] = true
+L["Add button to Trainer frame with ability to train all available skills in one click."] = true
+L["Alt-Click Merchant"] = true
+L["Already Known"] = true
+L["Animated Achievement Bars"] = true
+L["Automatically change your watched faction on the reputation bar to the faction you got reputation points for."] = true
+L["Automatically release body when killed inside a battleground."] = true
+L["Automatically select the quest reward with the highest vendor sell value."] = true
+L["Change color of item icons which already known."] = true
+L["Changes the transparency of all the movers."] = true
+L["Display quest levels at Quest Log."] = true
+L["Hide Zone Text"] = true
+L["Holding Alt key while buying something from vendor will now buy an entire stack."] = true
+L["Mover Transparency"] = true
+L["PvP Autorelease"] = true
+L["Select Quest Reward"] = true
+L["Show Quest Level"] = true
+L["Track Reputation"] = true
+L["Train All Button"] = true
+L["Undress Button"] = true
+L["Undress"] = true
+
+-- HD Models Portrait Fix
+L["Debug"] = true
+L["List of models with broken portrait camera. Separete each model name with ';' simbol"] = true
+L["Models to fix"] = true
+L["Portrait HD Fix"] = true
+L["Print to chat model names of units with enabled 3D portraits."] = true
+
+-- Interrupt Tracker
+L["Interrupt Tracker"] = true
+
+-- Nameplates
+L["Cache Unit Class"] = true
+
+-- Minimap
+L["Above Minimap"] = true
+L["Combat Hide"] = true
+L["FadeIn Delay"] = true
+L["Hide minimap while in combat."] = true
+L["Show Location Digits"] = true
+L["Toggle Location Digits."] = true
+L["Location Digits"] = true
+L["Location Panel"] = true
+L["Number of digits for map location."] = true
+L["The time to wait before fading the minimap back in after combat hide. (0 = Disabled)"] = true
+L["Toggle Location Panel."] = true
+
+-- Timer Tracker
+L["Timer Tracker"] = true
+L["Hook DBM"] = true
+
+-- Tooltip
+L["Check Player"] = true
+L["Check achievement completion instead of boss kill stats.\nSome servers log incorrect boss kill statistics, this is an alternative way to get player progress."] = true
+L["Colorize the tooltip border based on item quality."] = true
+L["Icecrown Citadel"] = true
+L["Item Border Color"] = true
+L["Progress Info"] = true
+L["Ruby Sanctum"] = true
+L["Show/Hides an Icon for Achievements on the Tooltip."] = true
+L["Show/Hides an Icon for Items on the Tooltip."] = true
+L["Show/Hides an Icon for Spells on the Tooltip."] = true
+L["Show/Hides an Icon for Spells and Items on the Tooltip."] = true
+L["Tiers"] = true
+L["Tooltip Icon"] = true
+L["Trial of the Crusader"] = true
+L["Ulduar"] = true
+
+-- Movers
+L["Loss Control"] = "제어손실 표시"
+L["Player Portrait"] = true
+L["Target Portrait"] = true
+
+-- Loss Control
+L["CC"] = "군중제어"
+L["Disarm"] = "무장 해제"
+L["Lose Control"] = true
+L["PvE"] = "PvE"
+L["Root"] = "뿌리묶기"
+L["Silence"] = "침묵"
+L["Snare"] = "덫"
+
+-- Unitframes
+L["Class Icons"] = true
+L["Detached Height"] = true
+L["Show class icon for units."] = true
+
+-- WatchFrame
+L["Hidden"] = true
+L["Collapsed"] = true
+L["City (Resting)"] = true
+L["PvP"] = true
+L["Party"] = true
+L["Raid"] = true
+
+--
+L["Drag"] = true
+L["Left-click on character and drag to rotate."] = true
+L["Mouse Wheel Down"] = true
+L["Mouse Wheel Up"] = true
+L["Reset Position"] = "위치 초기화"
+L["Right-click on character and drag to move it within the window."] = true
+L["Rotate Left"] = true
+L["Rotate Right"] = true
+L["Zoom In"] = true
+L["Zoom Out"] = true
+
+--
+L["Character Stats"] = true
+L["Damage Per Second"] = "DPS"
+L["Equipment Manager"] = true
+L["Hide Character Information"] = true
+L["Hide Pet Information"] = true
+L["Item Level"] = "아이템 레벨"
+L["New Set"] = true
+L["Resistance"] = true
+L["Show Character Information"] = true
+L["Show Pet Information"] = true
+L["Titles"] = true
+L["Total Companions"] = true
+L["Total Mounts"] = true
+
+L["ALL"] = "전체"
+L["ALT_KEY"] = "ALT 키"
+
+L["%d mails\nShift-Click to remove empty mails."] = true
+L["Addon |cffFFD100%s|r was merged into |cffFFD100ElvUI_Enhanced|r.\nPlease remove it to avoid conflicts."] = true
+L["Cache Unit Guilds / NPC Titles"] = true
+L["Check Achievements"] = true
+L["Collected "] = true
+L["Collection completed."] = true
+L["Collection stopped, inventory is full."] = true
+L["Color based on reaction type."] = true
+L["Compact mode"] = true
+L["Companion Background"] = true
+L["Desaturate"] = true
+L["Detached Portrait"] = true
+L["Dressing Room"] = true
+L["Enhanced"] = true
+L["Equipment Info"] = true
+L["Error Frame"] = true
+L["Everywhere"] = true
+L["Fog of War"] = true
+L["Grow direction"] = true
+L["Guild"] = true
+L["Inside Minimap"] = true
+L["Key Press Animation"] = true
+L["Map"] = true
+L["Minimap Button Grabber"] = true
+L["NPC"] = true
+L["Overlay Color"] = true
+L["Reaction Color"] = true
+L["Reported by %s"] = true
+L["Rotation"] = true
+L["Separator"] = true
+L["Set the height of Error Frame. Higher frame can show more lines at once."] = true
+L["Set the width of Error Frame. Too narrow frame may cause messages to be split in several lines"] = true
+L["Show Everywhere"] = true
+L["Show on Arena."] = true
+L["Show on Battleground."] = true
+L["Smooth Animations"] = true
+L["Take All"] = true
+L["Take All Mail"] = true
+L["Take Cash"] = true
+L["This addon has been disabled. You should install an updated version."] = true
+L["Where to show"] = true
+L["seconds"] = true
diff --git a/ElvUI_Enhanced/Locales/ptBR.lua b/ElvUI_Enhanced/Locales/ptBR.lua
new file mode 100644
index 0000000..cf481ab
--- /dev/null
+++ b/ElvUI_Enhanced/Locales/ptBR.lua
@@ -0,0 +1,237 @@
+local E = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "ptBR")
+
+-- DESC locales
+L["ENH_LOGIN_MSG"] = "Você está a usar |cff1784d1ElvUI|r |cff1784d1Enhanced|r |cffff8000(WotLK)|r versão %s%s|r."
+L["DURABILITY_DESC"] = "Ajuste as opções para a informação de durabilidade no ecrã de informação do personagem."
+L["ITEMLEVEL_DESC"] = "Adjust the settings for the item level information on the character screen."
+L["WATCHFRAME_DESC"] = "Adjust the settings for the visibility of the watchframe (questlog) to your personal preference."
+
+-- Incompatibility
+L["GearScore '3.1.20b - Release' is not for WotLK. Download 3.1.7. Disable this version?"] = true
+
+-- AddOn List
+L["Enable All"] = true
+L["Dependencies: "] = true
+L["Disable All"] = true
+L["Load AddOn"] = true
+L["Requires Reload"] = true
+
+-- Chat
+L["Filter DPS meters Spam"] = true
+L["Replaces reports from damage meters with a clickable hyperlink to reduce chat spam"] = true
+
+-- Datatext
+L["Ammo/Shard Counter"] = true
+L["Combat Indicator"] = true
+L["Distance"] = true
+L["In Combat"] = true
+L["New Mail"] = true
+L["No Mail"] = true
+L["Out of Combat"] = true
+L["Reincarnation"] = true
+L["Target Range"] = true
+
+-- Death Recap
+L["Death Recap Frame"] = true
+L["%s %s"] = true
+L["%s by %s"] = true
+L["%s sec before death at %s%% health."] = true
+L["(%d Absorbed)"] = true
+L["(%d Blocked)"] = true
+L["(%d Overkill)"] = true
+L["(%d Resisted)"] = true
+L["Death Recap unavailable."] = true
+L["Death Recap"] = true
+L["Killing blow at %s%% health."] = true
+L["You died."] = true
+
+-- Decline Duels
+L["Auto decline all duels"] = true
+L["Decline Duel"] = true
+L["Declined duel request from "] = true
+
+-- Enhanced Character Frame / Paperdoll Backgrounds
+L["Character Background"] = true
+L["Enhanced Character Frame"] = true
+L["Enhanced Model Frames"] = true
+L["Inspect Background"] = true
+L["Paperdoll Backgrounds"] = true
+L["Pet Background"] = true
+
+-- Equipment
+L["Damaged Only"] = "Só Danificados"
+L["Enable/Disable the display of durability information on the character screen."] = "Activar/desactivar a informação de durabilidade no ecrã de informação do personagem."
+L["Enable/Disable the display of item levels on the character screen."] = true
+L["Only show durabitlity information for items that are damaged."] = "Só mostrar informação de durabilidade para itens danificados."
+L["Quality Color"] = true
+
+-- General
+L["Add button to Dressing Room frame with ability to undress model."] = true
+L["Add button to Trainer frame with ability to train all available skills in one click."] = true
+L["Alt-Click Merchant"] = true
+L["Already Known"] = true
+L["Animated Achievement Bars"] = true
+L["Automatically change your watched faction on the reputation bar to the faction you got reputation points for."] = "Mudar automaticamente a facção controlada para a facção na qual acabou de ganhar pontos de reputação."
+L["Automatically release body when killed inside a battleground."] = "Automaticamente libertar o corpo quando morto num campo de batalha."
+L["Automatically select the quest reward with the highest vendor sell value."] = true
+L["Change color of item icons which already known."] = true
+L["Changes the transparency of all the movers."] = true
+L["Display quest levels at Quest Log."] = true
+L["Hide Zone Text"] = true
+L["Holding Alt key while buying something from vendor will now buy an entire stack."] = true
+L["Mover Transparency"] = true
+L["PvP Autorelease"] = "Auto-libertar em JxJ"
+L["Select Quest Reward"] = true
+L["Show Quest Level"] = true
+L["Track Reputation"] = "Controlar Reputação"
+L["Train All Button"] = true
+L["Undress Button"] = true
+L["Undress"] = true
+
+-- HD Models Portrait Fix
+L["Debug"] = true
+L["List of models with broken portrait camera. Separete each model name with ';' simbol"] = true
+L["Models to fix"] = true
+L["Portrait HD Fix"] = true
+L["Print to chat model names of units with enabled 3D portraits."] = true
+
+-- Interrupt Tracker
+L["Interrupt Tracker"] = true
+
+-- Nameplates
+L["Cache Unit Class"] = true
+
+-- Minimap
+L["Above Minimap"] = true
+L["Combat Hide"] = true
+L["FadeIn Delay"] = true
+L["Hide minimap while in combat."] = true
+L["Show Location Digits"] = true
+L["Toggle Location Digits."] = true
+L["Location Digits"] = true
+L["Location Panel"] = true
+L["Number of digits for map location."] = true
+L["The time to wait before fading the minimap back in after combat hide. (0 = Disabled)"] = true
+L["Toggle Location Panel."] = true
+
+-- Timer Tracker
+L["Timer Tracker"] = true
+L["Hook DBM"] = true
+
+-- Tooltip
+L["Check Player"] = true
+L["Check achievement completion instead of boss kill stats.\nSome servers log incorrect boss kill statistics, this is an alternative way to get player progress."] = true
+L["Colorize the tooltip border based on item quality."] = true
+L["Icecrown Citadel"] = true
+L["Item Border Color"] = true
+L["Progress Info"] = true
+L["Ruby Sanctum"] = true
+L["Show/Hides an Icon for Achievements on the Tooltip."] = true
+L["Show/Hides an Icon for Items on the Tooltip."] = true
+L["Show/Hides an Icon for Spells on the Tooltip."] = true
+L["Show/Hides an Icon for Spells and Items on the Tooltip."] = true
+L["Tiers"] = true
+L["Tooltip Icon"] = true
+L["Trial of the Crusader"] = true
+L["Ulduar"] = true
+
+-- Movers
+L["Loss Control"] = "Perda de Controle"
+L["Player Portrait"] = true
+L["Target Portrait"] = true
+
+-- Loss Control
+L["CC"] = true
+L["Disarm"] = true
+L["Lose Control"] = true
+L["PvE"] = true
+L["Root"] = true
+L["Silence"] = true
+L["Snare"] = true
+
+-- Unitframes
+L["Class Icons"] = true
+L["Detached Height"] = true
+L["Show class icon for units."] = true
+
+-- WatchFrame
+L["Hidden"] = true
+L["Collapsed"] = true
+L["City (Resting)"] = true
+L["PvP"] = true
+L["Party"] = true
+L["Raid"] = true
+
+--
+L["Drag"] = true
+L["Left-click on character and drag to rotate."] = true
+L["Mouse Wheel Down"] = true
+L["Mouse Wheel Up"] = true
+L["Reset Position"] = "Redefinir Posição"
+L["Right-click on character and drag to move it within the window."] = true
+L["Rotate Left"] = true
+L["Rotate Right"] = true
+L["Zoom In"] = true
+L["Zoom Out"] = true
+
+--
+L["Character Stats"] = true
+L["Damage Per Second"] = "DPS"
+L["Equipment Manager"] = true
+L["Hide Character Information"] = true
+L["Hide Pet Information"] = true
+L["Item Level"] = true
+L["New Set"] = true
+L["Resistance"] = true
+L["Show Character Information"] = true
+L["Show Pet Information"] = true
+L["Titles"] = true
+L["Total Companions"] = true
+L["Total Mounts"] = true
+
+L["ALL"] = "Tudo"
+L["ALT_KEY"] = "Tecla ALT"
+
+L["%d mails\nShift-Click to remove empty mails."] = true
+L["Addon |cffFFD100%s|r was merged into |cffFFD100ElvUI_Enhanced|r.\nPlease remove it to avoid conflicts."] = true
+L["Cache Unit Guilds / NPC Titles"] = true
+L["Check Achievements"] = true
+L["Collected "] = true
+L["Collection completed."] = true
+L["Collection stopped, inventory is full."] = true
+L["Color based on reaction type."] = true
+L["Compact mode"] = true
+L["Companion Background"] = true
+L["Desaturate"] = true
+L["Detached Portrait"] = true
+L["Dressing Room"] = true
+L["Enhanced"] = true
+L["Equipment Info"] = true
+L["Error Frame"] = true
+L["Everywhere"] = true
+L["Fog of War"] = true
+L["Grow direction"] = true
+L["Guild"] = true
+L["Inside Minimap"] = true
+L["Key Press Animation"] = true
+L["Map"] = true
+L["Minimap Button Grabber"] = true
+L["NPC"] = true
+L["Overlay Color"] = true
+L["Reaction Color"] = true
+L["Reported by %s"] = true
+L["Rotation"] = true
+L["Separator"] = true
+L["Set the height of Error Frame. Higher frame can show more lines at once."] = true
+L["Set the width of Error Frame. Too narrow frame may cause messages to be split in several lines"] = true
+L["Show Everywhere"] = true
+L["Show on Arena."] = true
+L["Show on Battleground."] = true
+L["Smooth Animations"] = true
+L["Take All"] = true
+L["Take All Mail"] = true
+L["Take Cash"] = true
+L["This addon has been disabled. You should install an updated version."] = true
+L["Where to show"] = true
+L["seconds"] = true
diff --git a/ElvUI_Enhanced/Locales/ruRU.lua b/ElvUI_Enhanced/Locales/ruRU.lua
new file mode 100644
index 0000000..7394139
--- /dev/null
+++ b/ElvUI_Enhanced/Locales/ruRU.lua
@@ -0,0 +1,237 @@
+local E = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "ruRU")
+
+-- DESC locales
+L["ENH_LOGIN_MSG"] = "Вы используете |cff1784d1ElvUI|r |cff1784d1Enhanced|r |cffff8000(WotLK)|r версии %s%s|r."
+L["DURABILITY_DESC"] = "Настройка параметров информации о прочности предметов в окне персонажа."
+L["ITEMLEVEL_DESC"] = "Настройка параметров информации об уровне предмета в окне персонажа."
+L["WATCHFRAME_DESC"] = "Настройте отображение списка заданий (квест лог) исходя из ваших личных предпочтений."
+
+-- Incompatibility
+L["GearScore '3.1.20b - Release' is not for WotLK. Download 3.1.7. Disable this version?"] = "GearScore '3.1.20b - Release' не для WotLK. Загрузите 3.1.7. Отключить эту версию?"
+
+-- AddOn List
+L["Enable All"] = true
+L["Dependencies: "] = true
+L["Disable All"] = true
+L["Load AddOn"] = true
+L["Requires Reload"] = true
+
+-- Chat
+L["Filter DPS meters Spam"] = true
+L["Replaces reports from damage meters with a clickable hyperlink to reduce chat spam"] = true
+
+-- Datatext
+L["Ammo/Shard Counter"] = true
+L["Combat Indicator"] = true
+L["Distance"] = true
+L["In Combat"] = true
+L["New Mail"] = "Новое письмо"
+L["No Mail"] = "Нет писем"
+L["Out of Combat"] = true
+L["Reincarnation"] = true
+L["Target Range"] = true
+
+-- Death Recap
+L["Death Recap Frame"] = true
+L["%s %s"] = "Урон: %s %s"
+L["%s by %s"] = "%s - %s"
+L["%s sec before death at %s%% health."] = "%s сек. до смерти при объеме здоровья %s%%"
+L["(%d Absorbed)"] = "Поглощено: %d ед. урона."
+L["(%d Blocked)"] = "Заблокировано: %d уд. урона."
+L["(%d Overkill)"] = "Избыточный урон: %d ед."
+L["(%d Resisted)"] = "Сопротивление %d еденицам урона."
+L["Death Recap unavailable."] = "Информация о смерти не доступна."
+L["Death Recap"] = "Информация о смерти"
+L["Killing blow at %s%% health."] = "Объем здоровья при получении смертельного удара: %s%%"
+L["You died."] = "Вы умерли."
+
+-- Decline Duels
+L["Auto decline all duels"] = "Автоматически отклонять все дуэли."
+L["Decline Duel"] = true
+L["Declined duel request from "] = "DДуэль отклонена от "
+
+-- Enhanced Character Frame / Paperdoll Backgrounds
+L["Character Background"] = true
+L["Enhanced Character Frame"] = true
+L["Enhanced Model Frames"] = true
+L["Inspect Background"] = true
+L["Paperdoll Backgrounds"] = true
+L["Pet Background"] = true
+
+-- Equipment
+L["Damaged Only"] = "Только поврежденные"
+L["Enable/Disable the display of durability information on the character screen."] = "Включить/Выключить отображение информации о прочности предметов в окне персонажа."
+L["Enable/Disable the display of item levels on the character screen."] = "Включить/Выключить отображение уровня предмета в окне персонажа."
+L["Only show durabitlity information for items that are damaged."] = "Показывать уровень прочности только на поврежденных предметах."
+L["Quality Color"] = true
+
+-- General
+L["Add button to Dressing Room frame with ability to undress model."] = true
+L["Add button to Trainer frame with ability to train all available skills in one click."] = true
+L["Alt-Click Merchant"] = true
+L["Already Known"] = true
+L["Animated Achievement Bars"] = true
+L["Automatically change your watched faction on the reputation bar to the faction you got reputation points for."] = "Автоматическое изменение фракции на панели репутации на ту, очки репутации которой вы получили."
+L["Automatically release body when killed inside a battleground."] = "Автоматически покидать тело после смерти на полях боя."
+L["Automatically select the quest reward with the highest vendor sell value."] = true
+L["Change color of item icons which already known."] = true
+L["Changes the transparency of all the movers."] = "Изменяет прозрачность фиксаторов"
+L["Display quest levels at Quest Log."] = true
+L["Hide Zone Text"] = true
+L["Holding Alt key while buying something from vendor will now buy an entire stack."] = true
+L["Mover Transparency"] = "Прозрачность фиксаторов"
+L["PvP Autorelease"] = "Автовыход из тела"
+L["Select Quest Reward"] = true
+L["Show Quest Level"] = true
+L["Track Reputation"] = "Отслеживание репутации"
+L["Train All Button"] = true
+L["Undress Button"] = true
+L["Undress"] = "Раздеть"
+
+-- HD Models Portrait Fix
+L["Debug"] = true
+L["List of models with broken portrait camera. Separete each model name with ';' simbol"] = true
+L["Models to fix"] = true
+L["Portrait HD Fix"] = true
+L["Print to chat model names of units with enabled 3D portraits."] = true
+
+-- Interrupt Tracker
+L["Interrupt Tracker"] = true
+
+-- Nameplates
+L["Cache Unit Class"] = true
+
+-- Minimap
+L["Above Minimap"] = "Над миникартой"
+L["Combat Hide"] = true
+L["FadeIn Delay"] = "Задержка появления"
+L["Hide minimap while in combat."] = "Скрывать миникарту во время боя."
+L["Show Location Digits"] = true
+L["Toggle Location Digits."] = true
+L["Location Digits"] = "Цифры координат"
+L["Location Panel"] = true
+L["Number of digits for map location."] = "Колличество цифр после запятой в координатах."
+L["The time to wait before fading the minimap back in after combat hide. (0 = Disabled)"] = "Время ожидания появления миникарты после выхода из боя. (0 = Выключено)"
+L["Toggle Location Panel."] = true
+
+-- Timer Tracker
+L["Timer Tracker"] = true
+L["Hook DBM"] = true
+
+-- Tooltip
+L["Check Player"] = true
+L["Check achievement completion instead of boss kill stats.\nSome servers log incorrect boss kill statistics, this is an alternative way to get player progress."] = true
+L["Colorize the tooltip border based on item quality."] = "Окрашивать бордюр тултипа в цвет качества предмета"
+L["Icecrown Citadel"] = true
+L["Item Border Color"] = "Цвет рамки предметов"
+L["Progress Info"] = "Прогресс"
+L["Ruby Sanctum"] = true
+L["Show/Hides an Icon for Achievements on the Tooltip."] = true
+L["Show/Hides an Icon for Items on the Tooltip."] = true
+L["Show/Hides an Icon for Spells on the Tooltip."] = true
+L["Show/Hides an Icon for Spells and Items on the Tooltip."] = true
+L["Tiers"] = true
+L["Tooltip Icon"] = true
+L["Trial of the Crusader"] = true
+L["Ulduar"] = true
+
+-- Movers
+L["Loss Control"] = "Потери контроля"
+L["Player Portrait"] = "Портрет игрока"
+L["Target Portrait"] = "Портрет цели"
+
+-- Loss Control
+L["CC"] = "Потеря контроля"
+L["Disarm"] = "Разоружение"
+L["Lose Control"] = "Иконка потери контроля"
+L["PvE"] = "Рейдовые"
+L["Root"] = "Удержание на месте"
+L["Silence"] = "Молчание"
+L["Snare"] = "Замедление"
+
+-- Unitframes
+L["Class Icons"] = true
+L["Detached Height"] = "Высота при откреплении"
+L["Show class icon for units."] = "Показывать иконку класса на цели."
+
+-- WatchFrame
+L["City (Resting)"] = "Город (отдых)"
+L["Collapsed"] = "Развернуть"
+L["Hidden"] = "Скрыть"
+L["Party"] = "Группа"
+L["PvP"] = "PvP"
+L["Raid"] = "Рейд"
+
+--
+L["Drag"] = "Перетащить"
+L["Left-click on character and drag to rotate."] = "Зажмите левую кнопку мыши и тащите курсор, чтобы вращать изображение."
+L["Mouse Wheel Down"] = "Прокрутка вниз"
+L["Mouse Wheel Up"] = "Прокрутка вверх"
+L["Reset Position"] = "Сбросить позицию"
+L["Right-click on character and drag to move it within the window."] = "Зажмите правую кнопку мыши и тащите курсор, чтобы переместить персонажа."
+L["Rotate Left"] = "Вращение влево"
+L["Rotate Right"] = "Вращение вправо"
+L["Zoom In"] = "Приблизить"
+L["Zoom Out"] = "Отдалить"
+
+--
+L["Character Stats"] = "Характеристики"
+L["Damage Per Second"] = "Урон в секунду"
+L["Equipment Manager"] = "Комплекты экипировки"
+L["Hide Character Information"] = "Скрыть информацию о персонаже"
+L["Hide Pet Information"] = "Скрыть информацию о питомце"
+L["Item Level"] = "Уровень предметов"
+L["New Set"] = "Новый комплект"
+L["Resistance"] = "Cопротивление"
+L["Show Character Information"] = "Показать информацию о персонаже"
+L["Show Pet Information"] = "Показать информацию о питомце"
+L["Titles"] = "Звания"
+L["Total Companions"] = "Всего питомцев"
+L["Total Mounts"] = "Всего"
+
+L["ALL"] = "Все"
+L["ALT_KEY"] = "ALT"
+
+L["%d mails\nShift-Click to remove empty mails."] = true
+L["Addon |cffFFD100%s|r was merged into |cffFFD100ElvUI_Enhanced|r.\nPlease remove it to avoid conflicts."] = true
+L["Cache Unit Guilds / NPC Titles"] = true
+L["Check Achievements"] = true
+L["Collected "] = true
+L["Collection completed."] = true
+L["Collection stopped, inventory is full."] = true
+L["Color based on reaction type."] = true
+L["Compact mode"] = true
+L["Companion Background"] = true
+L["Desaturate"] = true
+L["Detached Portrait"] = true
+L["Dressing Room"] = true
+L["Enhanced"] = true
+L["Equipment Info"] = true
+L["Error Frame"] = true
+L["Everywhere"] = true
+L["Fog of War"] = true
+L["Grow direction"] = true
+L["Guild"] = true
+L["Inside Minimap"] = true
+L["Key Press Animation"] = true
+L["Map"] = true
+L["Minimap Button Grabber"] = true
+L["NPC"] = "НИП"
+L["Overlay Color"] = true
+L["Reaction Color"] = true
+L["Reported by %s"] = true
+L["Rotation"] = true
+L["Separator"] = true
+L["Set the height of Error Frame. Higher frame can show more lines at once."] = true
+L["Set the width of Error Frame. Too narrow frame may cause messages to be split in several lines"] = true
+L["Show Everywhere"] = true
+L["Show on Arena."] = true
+L["Show on Battleground."] = true
+L["Smooth Animations"] = true
+L["Take All"] = true
+L["Take All Mail"] = true
+L["Take Cash"] = true
+L["This addon has been disabled. You should install an updated version."] = true
+L["Where to show"] = true
+L["seconds"] = true
diff --git a/ElvUI_Enhanced/Locales/zhCN.lua b/ElvUI_Enhanced/Locales/zhCN.lua
new file mode 100644
index 0000000..ea29253
--- /dev/null
+++ b/ElvUI_Enhanced/Locales/zhCN.lua
@@ -0,0 +1,237 @@
+local E = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "zhCN")
+
+-- DESC locales
+L["ENH_LOGIN_MSG"] = "你正在使用 |cff1784d1ElvUI|r |cff1784d1Enhanced|r |cffff8000(WotLK)|r version %s%s|r。"
+L["DURABILITY_DESC"] = "调整角色界面中装备耐久度信息的设置。"
+L["ITEMLEVEL_DESC"] = "调整角色界面中物品等级信息的设置。"
+L["WATCHFRAME_DESC"] = "根据个人喜好调整任务追踪框架的设置。"
+L["Enhanced"] = "功能增强"
+
+-- Incompatibility
+L["GearScore '3.1.20b - Release' is not for WotLK. Download 3.1.7. Disable this version?"] = "GearScore '3.1.20b - Release'并非是为WotLK设计的,请下载版本3.1.7。要禁用此插件吗?"
+
+-- AddOn List
+L["Enable All"] = "全部启用"
+L["Dependencies: "] = "依赖性:"
+L["Disable All"] = "全部禁用"
+L["Load AddOn"] = "加载插件"
+L["Requires Reload"] = "需要重载"
+
+-- Chat
+L["Filter DPS meters Spam"] = "过滤DPS统计的垃圾讯息"
+L["Replaces reports from damage meters with a clickable hyperlink to reduce chat spam"] = "用可点击的超链接替换DPS统计的长篇报告,以减少聊天中的垃圾讯息。"
+
+-- Datatext
+L["Ammo/Shard Counter"] = "弹药/碎片 计数"
+L["Combat Indicator"] = "战斗指示"
+L["Distance"] = "距离"
+L["In Combat"] = "战斗中"
+L["New Mail"] = "新邮件"
+L["No Mail"] = "无邮件"
+L["Out of Combat"] = "脱离战斗"
+L["Reincarnation"] = "灵魂状态"
+L["Target Range"] = "目标距离"
+
+-- Death Recap
+L["Death Recap Frame"] = "死亡回顾框架"
+L["%s %s"] = true
+L["%s by %s"] = "%s 来自于 %s"
+L["%s sec before death at %s%% health."] = "死亡前 %s 秒,血量 %s%% 。"
+L["(%d Absorbed)"] = "(%d 吸收)"
+L["(%d Blocked)"] = "(%d 格挡)"
+L["(%d Overkill)"] = "(%d 过量伤害)"
+L["(%d Resisted)"] = "(%d 抵抗)"
+L["Death Recap unavailable."] = "死因回顾不可用"
+L["Death Recap"] = "死因回顾"
+L["Killing blow at %s%% health."] = "血量 %s%% 时被一击致命。"
+L["You died."] = "你死了。"
+
+-- Decline Duels
+L["Auto decline all duels"] = "自动拒绝决斗请求"
+L["Decline Duel"] = "拒绝决斗"
+L["Declined duel request from "] = "已拒绝决斗请求,发起者"
+
+-- Enhanced Character Frame / Paperdoll Backgrounds
+L["Character Background"] = "角色界面背景"
+L["Companion Background"] = "小伙伴界面背景"
+L["Dressing Room"] = "试衣间"
+L["Enhanced Character Frame"] = "增强角色界面框架"
+L["Enhanced Model Frames"] = "增强模型框架"
+L["Error Frame"] = "错误信息框架"
+L["Inspect Background"] = "观察界面背景"
+L["Paperdoll Backgrounds"] = "纸娃娃系统背景"
+L["Pet Background"] = "宠物界面背景"
+L["Smooth Animations"] = "平滑动画"
+
+-- Equipment
+L["Damaged Only"] = "仅显示受损"
+L["Enable/Disable the display of durability information on the character screen."] = "开启/关闭 角色界面装备耐久度显示。"
+L["Enable/Disable the display of item levels on the character screen."] = "开启/关闭 角色界面物品等级显示。"
+L["Only show durabitlity information for items that are damaged."] = "只在装备受损时显示耐久度信息。"
+L["Quality Color"] = "品质颜色"
+
+-- General
+L["Add button to Dressing Room frame with ability to undress model."] = "在试衣间界面添加<裸体>按钮。"
+L["Add button to Trainer frame with ability to train all available skills in one click."] = "在训练师界面添加<学习全部>按钮,以便一键学习所有可用技能。"
+L["Alt-Click Merchant"] = "Alt-点击快速购买"
+L["Already Known"] = "已经学会"
+L["Animated Achievement Bars"] = "动成就画条"
+L["Automatically change your watched faction on the reputation bar to the faction you got reputation points for."] = "当你获得某个阵营的声望时,自动用声望条追踪此阵营的声望。"
+L["Automatically release body when killed inside a battleground."] = "在战场中死亡后自动释放灵魂。"
+L["Automatically select the quest reward with the highest vendor sell value."] = "自动选择任务奖励中售价最高的物品。"
+L["Change color of item icons which already known."] = "改变已经学会的物品图标颜色。"
+L["Changes the transparency of all the movers."] = "改变所有移动框架的透明度。"
+L["Display quest levels at Quest Log."] = "在任务日志中显示任务等级。"
+L["Hide Zone Text"] = "隐藏区域文字"
+L["Holding Alt key while buying something from vendor will now buy an entire stack."] = "按下Alt键可在商人处购买整组物品。"
+L["Mover Transparency"] = "移动框架透明度"
+L["PvP Autorelease"] = "PVP自动释放灵魂"
+L["Select Quest Reward"] = "选择任务奖励"
+L["Show Quest Level"] = "显示任务等级"
+L["Track Reputation"] = "声望追踪"
+L["Train All Button"] = "学习全部按钮"
+L["Undress Button"] = "裸体按钮"
+L["Undress"] = "裸体"
+
+-- HD Models Portrait Fix
+L["Debug"] = true
+L["List of models with broken portrait camera. Separete each model name with ';' simbol"] = "头像镜头破损的模型列表。每个模型名称之间使用 ';' 符号分隔。"
+L["Models to fix"] = "待修复的模型"
+L["Portrait HD Fix"] = "高清头像修复"
+L["Print to chat model names of units with enabled 3D portraits."] = "将可用3D头像的单位模型名称发布到聊天框中。"
+
+-- Interrupt Tracker
+L["Interrupt Tracker"] = "打断追踪"
+L["Everywhere"] = "任何区域"
+L["Where to show"] = "何处显示"
+
+-- Nameplates
+L["Cache Unit Class"] = "缓存单位职业"
+L["Cache Unit Guilds / NPC Titles"] = "缓存单位公会/NPC头衔"
+L["Guild"] = "公会"
+
+-- Minimap
+L["Above Minimap"] = "小地图之上"
+L["Combat Hide"] = "战斗隐藏"
+L["FadeIn Delay"] = "淡入延迟"
+L["Hide minimap while in combat."] = "战斗中隐藏小地图。"
+L["Show Location Digits"] = "显示坐标"
+L["Toggle Location Digits."] = "开关坐标"
+L["Location Digits"] = "坐标"
+L["Location Panel"] = "位置面板"
+L["Number of digits for map location."] = "地图位置的数字坐标。"
+L["The time to wait before fading the minimap back in after combat hide. (0 = Disabled)"] = "脱离战斗后小地图淡入的等待时间。(0 = 禁用)"
+L["Toggle Location Panel."] = "开关位置面板。"
+
+-- Timer Tracker
+L["Timer Tracker"] = "计时器"
+L["Hook DBM"] = "连接DBM"
+
+-- Tooltip
+L["Check Player"] = "检查玩家"
+L["Check achievement completion instead of boss kill stats.\nSome servers log incorrect boss kill statistics, this is an alternative way to get player progress."] = true
+L["Colorize the tooltip border based on item quality."] = "以物品品质着色鼠标提示边框。"
+L["Icecrown Citadel"] = "冰冠堡垒"
+L["Item Border Color"] = "物品边框颜色"
+L["Progress Info"] = "进度信息"
+L["Ruby Sanctum"] = "红玉圣殿"
+L["Show/Hides an Icon for Achievements on the Tooltip."] = "在鼠标提示中显示成就图标。"
+L["Show/Hides an Icon for Items on the Tooltip."] = "在鼠标提示中显示物品图标。"
+L["Show/Hides an Icon for Spells on the Tooltip."] = "在鼠标提示中显示技能图标。"
+L["Show/Hides an Icon for Spells and Items on the Tooltip."] = "在鼠标提示中显示技能和物品图标。"
+L["Tiers"] = "阶段"
+L["Tooltip Icon"] = "鼠标提示图标"
+L["Trial of the Crusader"] = "十字军的试炼"
+L["Ulduar"] = "奥杜尔"
+
+-- Movers
+L["Loss Control"] = "失控图标"
+L["Player Portrait"] = "玩家头像"
+L["Target Portrait"] = "目标头像"
+
+-- Lose Control
+L["CC"] = "控制类技能"
+L["Disarm"] = "缴械类技能"
+L["Lose Control"] = "失控"
+L["PvE"] = "PvE"
+L["Root"] = "定身类技能"
+L["Silence"] = "沉默类技能"
+L["Snare"] = "减速类技能"
+
+-- Unitframes
+L["Class Icons"] = "职业图标"
+L["Detached Height"] = "分离后的高度"
+L["Show class icon for units."] = "显示单位的职业图标。"
+
+-- WatchFrame
+L["Hidden"] = "隐藏"
+L["Collapsed"] = "折叠"
+L["City (Resting)"] = "城市 (休息)"
+L["PvP"] = true
+L["Party"] = "小队"
+L["Raid"] = "团队"
+
+--
+L["Drag"] = "拖动"
+L["Left-click on character and drag to rotate."] = "左键点击角色并拖动可以旋转模型。"
+L["Mouse Wheel Down"] = "鼠标滚轮向下"
+L["Mouse Wheel Up"] = "鼠标滚轮向上"
+L["Reset Position"] = "重置位置"
+L["Right-click on character and drag to move it within the window."] = "右键点击角色并拖动可以在窗口内移动模型。"
+L["Rotate Left"] = "向左旋转"
+L["Rotate Right"] = "向右旋转"
+L["Zoom In"] = "放大"
+L["Zoom Out"] = "缩小"
+
+--
+L["Character Stats"] = "角色属性"
+L["Damage Per Second"] = "DPS"
+L["Equipment Manager"] = "装备管理"
+L["Hide Character Information"] = "隐藏角色信息"
+L["Hide Pet Information"] = "隐藏宠物信息"
+L["Item Level"] = "物品等级"
+L["New Set"] = "新套装"
+L["Resistance"] = "抗性"
+L["Show Character Information"] = "显示角色信息"
+L["Show Pet Information"] = "显示宠物信息"
+L["Titles"] = "头衔"
+L["Total Companions"] = "所有小伙伴"
+L["Total Mounts"] = "所有坐骑"
+
+L["ALL"] = "全部"
+L["ALT_KEY"] = "ALT键"
+
+L["%d mails\nShift-Click to remove empty mails."] = true
+L["Addon |cffFFD100%s|r was merged into |cffFFD100ElvUI_Enhanced|r.\nPlease remove it to avoid conflicts."] = true
+L["Check Achievements"] = true
+L["Collected "] = true
+L["Collection completed."] = true
+L["Collection stopped, inventory is full."] = true
+L["Color based on reaction type."] = true
+L["Compact mode"] = true
+L["Desaturate"] = true
+L["Detached Portrait"] = true
+L["Equipment Info"] = true
+L["Fog of War"] = true
+L["Grow direction"] = true
+L["Inside Minimap"] = true
+L["Key Press Animation"] = true
+L["Map"] = true
+L["Minimap Button Grabber"] = true
+L["NPC"] = true
+L["Overlay Color"] = true
+L["Reaction Color"] = true
+L["Reported by %s"] = true
+L["Rotation"] = true
+L["Separator"] = true
+L["Set the height of Error Frame. Higher frame can show more lines at once."] = true
+L["Set the width of Error Frame. Too narrow frame may cause messages to be split in several lines"] = true
+L["Show Everywhere"] = true
+L["Show on Arena."] = true
+L["Show on Battleground."] = true
+L["Take All"] = true
+L["Take All Mail"] = true
+L["Take Cash"] = true
+L["This addon has been disabled. You should install an updated version."] = true
+L["seconds"] = true
diff --git a/ElvUI_Enhanced/Locales/zhTW.lua b/ElvUI_Enhanced/Locales/zhTW.lua
new file mode 100644
index 0000000..c6cd60e
--- /dev/null
+++ b/ElvUI_Enhanced/Locales/zhTW.lua
@@ -0,0 +1,237 @@
+local E = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "zhTW")
+
+-- DESC locales
+L["ENH_LOGIN_MSG"] = "您正在使用 |cff1784d1ElvUI|r |cff1784d1Enhanced|r |cffff8000(WotLK)|r version %s%s|r."
+L["DURABILITY_DESC"] = "調整設置人物窗口裝備耐久度顯示."
+L["ITEMLEVEL_DESC"] = "調整在角色資訊上顯示物品裝等的各種設定."
+L["WATCHFRAME_DESC"] = "Adjust the settings for the visibility of the watchframe (questlog) to your personal preference."
+
+-- Incompatibility
+L["GearScore '3.1.20b - Release' is not for WotLK. Download 3.1.7. Disable this version?"] = true
+
+-- AddOn List
+L["Enable All"] = true
+L["Dependencies: "] = true
+L["Disable All"] = true
+L["Load AddOn"] = true
+L["Requires Reload"] = true
+
+-- Chat
+L["Filter DPS meters Spam"] = true
+L["Replaces reports from damage meters with a clickable hyperlink to reduce chat spam"] = true
+
+-- Datatext
+L["Ammo/Shard Counter"] = true
+L["Combat Indicator"] = true
+L["Distance"] = true
+L["In Combat"] = true
+L["New Mail"] = true
+L["No Mail"] = true
+L["Out of Combat"] = true
+L["Reincarnation"] = true
+L["Target Range"] = true
+
+-- Death Recap
+L["Death Recap Frame"] = true
+L["%s %s"] = true
+L["%s by %s"] = true
+L["%s sec before death at %s%% health."] = true
+L["(%d Absorbed)"] = true
+L["(%d Blocked)"] = true
+L["(%d Overkill)"] = true
+L["(%d Resisted)"] = true
+L["Death Recap unavailable."] = true
+L["Death Recap"] = true
+L["Killing blow at %s%% health."] = true
+L["You died."] = true
+
+-- Decline Duels
+L["Auto decline all duels"] = "自動拒絕決鬥請求"
+L["Decline Duel"] = true
+L["Declined duel request from "] = "已拒絕決鬥請求自"
+
+-- Enhanced Character Frame / Paperdoll Backgrounds
+L["Character Background"] = true
+L["Enhanced Character Frame"] = true
+L["Enhanced Model Frames"] = true
+L["Inspect Background"] = true
+L["Paperdoll Backgrounds"] = true
+L["Pet Background"] = true
+
+-- Equipment
+L["Damaged Only"] = "受損顯示"
+L["Enable/Disable the display of durability information on the character screen."] = "開啓/關閉 人物窗口裝備耐久度顯示."
+L["Enable/Disable the display of item levels on the character screen."] = "在角色資訊上顯示各裝備裝等"
+L["Only show durabitlity information for items that are damaged."] = "只在裝備受損時顯示耐久度."
+L["Quality Color"] = true
+
+-- General
+L["Add button to Dressing Room frame with ability to undress model."] = true
+L["Add button to Trainer frame with ability to train all available skills in one click."] = true
+L["Alt-Click Merchant"] = true
+L["Already Known"] = true
+L["Animated Achievement Bars"] = true
+L["Automatically change your watched faction on the reputation bar to the faction you got reputation points for."] = "當你獲得某個陣營的聲望時, 將自動追蹤此陣營的聲望至經驗值欄位."
+L["Automatically release body when killed inside a battleground."] = "在戰場死亡後自動釋放靈魂."
+L["Automatically select the quest reward with the highest vendor sell value."] = "自動選取有最高賣價的任務獎勵物品"
+L["Change color of item icons which already known."] = true
+L["Changes the transparency of all the movers."] = "改變所有定位器的透明度"
+L["Display quest levels at Quest Log."] = true
+L["Hide Zone Text"] = true
+L["Holding Alt key while buying something from vendor will now buy an entire stack."] = true
+L["Mover Transparency"] = "定位器透明度"
+L["PvP Autorelease"] = "PVP自動釋放靈魂"
+L["Select Quest Reward"] = "自動選取任務獎勵"
+L["Show Quest Level"] = true
+L["Track Reputation"] = "聲望追蹤"
+L["Train All Button"] = true
+L["Undress Button"] = true
+L["Undress"] = "無裝備"
+
+-- HD Models Portrait Fix
+L["Debug"] = true
+L["List of models with broken portrait camera. Separete each model name with ';' simbol"] = true
+L["Models to fix"] = true
+L["Portrait HD Fix"] = true
+L["Print to chat model names of units with enabled 3D portraits."] = true
+
+-- Interrupt Tracker
+L["Interrupt Tracker"] = true
+
+-- Nameplates
+L["Cache Unit Class"] = true
+
+-- Minimap
+L["Above Minimap"] = "小地圖之上"
+L["Combat Hide"] = true
+L["FadeIn Delay"] = "隱藏延遲"
+L["Hide minimap while in combat."] = "戰鬥中隱藏小地圖"
+L["Show Location Digits"] = true
+L["Toggle Location Digits."] = true
+L["Location Digits"] = "坐標位數"
+L["Location Panel"] = true
+L["Number of digits for map location."] = "坐標顯示的小數位數"
+L["The time to wait before fading the minimap back in after combat hide. (0 = Disabled)"] = "戰鬥開始後隱藏小地圖前的延遲時間 (0=停用)"
+L["Toggle Location Panel."] = true
+
+-- Timer Tracker
+L["Timer Tracker"] = true
+L["Hook DBM"] = true
+
+-- Tooltip
+L["Check Player"] = true
+L["Check achievement completion instead of boss kill stats.\nSome servers log incorrect boss kill statistics, this is an alternative way to get player progress."] = true
+L["Colorize the tooltip border based on item quality."] = true
+L["Icecrown Citadel"] = true
+L["Item Border Color"] = true
+L["Progress Info"] = true
+L["Ruby Sanctum"] = true
+L["Show/Hides an Icon for Achievements on the Tooltip."] = true
+L["Show/Hides an Icon for Items on the Tooltip."] = true
+L["Show/Hides an Icon for Spells on the Tooltip."] = true
+L["Show/Hides an Icon for Spells and Items on the Tooltip."] = true
+L["Tiers"] = true
+L["Tooltip Icon"] = true
+L["Trial of the Crusader"] = true
+L["Ulduar"] = true
+
+-- Movers
+L["Loss Control"] = "失去控制圖示"
+L["Player Portrait"] = true
+L["Target Portrait"] = true
+
+-- Loss Control
+L["CC"] = "控制類技能"
+L["Disarm"] = "繳械類技能"
+L["Lose Control"] = true
+L["PvE"] = "PvE"
+L["Root"] = "定身類技能"
+L["Silence"] = "沉默類技能"
+L["Snare"] = "減速類技能"
+
+-- Unitframes
+L["Class Icons"] = true
+L["Detached Height"] = true
+L["Show class icon for units."] = "顯是職業圖標"
+
+-- WatchFrame
+L["City (Resting)"] = "城市 (休息)"
+L["Collapsed"] = "收起"
+L["Hidden"] = "隱藏"
+L["Party"] = "隊伍"
+L["PvP"] = true
+L["Raid"] = "團隊"
+
+--
+L["Drag"] = true
+L["Left-click on character and drag to rotate."] = true
+L["Mouse Wheel Down"] = true
+L["Mouse Wheel Up"] = true
+L["Reset Position"] = "重設位置"
+L["Right-click on character and drag to move it within the window."] = true
+L["Rotate Left"] = true
+L["Rotate Right"] = true
+L["Zoom In"] = true
+L["Zoom Out"] = true
+
+--
+L["Character Stats"] = true
+L["Damage Per Second"] = "DPS"
+L["Equipment Manager"] = true
+L["Hide Character Information"] = true
+L["Hide Pet Information"] = true
+L["Item Level"] = "物品等級"
+L["New Set"] = true
+L["Resistance"] = true
+L["Show Character Information"] = true
+L["Show Pet Information"] = true
+L["Titles"] = true
+L["Total Companions"] = true
+L["Total Mounts"] = true
+
+L["ALL"] = "全部"
+L["ALT_KEY"] = "ALT鍵"
+
+L["%d mails\nShift-Click to remove empty mails."] = true
+L["Addon |cffFFD100%s|r was merged into |cffFFD100ElvUI_Enhanced|r.\nPlease remove it to avoid conflicts."] = true
+L["Cache Unit Guilds / NPC Titles"] = true
+L["Check Achievements"] = true
+L["Collected "] = true
+L["Collection completed."] = true
+L["Collection stopped, inventory is full."] = true
+L["Color based on reaction type."] = true
+L["Compact mode"] = true
+L["Companion Background"] = true
+L["Desaturate"] = true
+L["Detached Portrait"] = true
+L["Dressing Room"] = true
+L["Enhanced"] = true
+L["Equipment Info"] = true
+L["Error Frame"] = true
+L["Everywhere"] = true
+L["Fog of War"] = true
+L["Grow direction"] = true
+L["Guild"] = true
+L["Inside Minimap"] = true
+L["Key Press Animation"] = true
+L["Map"] = true
+L["Minimap Button Grabber"] = true
+L["NPC"] = true
+L["Overlay Color"] = true
+L["Reaction Color"] = true
+L["Reported by %s"] = true
+L["Rotation"] = true
+L["Separator"] = true
+L["Set the height of Error Frame. Higher frame can show more lines at once."] = true
+L["Set the width of Error Frame. Too narrow frame may cause messages to be split in several lines"] = true
+L["Show Everywhere"] = true
+L["Show on Arena."] = true
+L["Show on Battleground."] = true
+L["Smooth Animations"] = true
+L["Take All"] = true
+L["Take All Mail"] = true
+L["Take Cash"] = true
+L["This addon has been disabled. You should install an updated version."] = true
+L["Where to show"] = true
+L["seconds"] = true
diff --git a/ElvUI_Enhanced/Media/Fonts/uf_font.ttf b/ElvUI_Enhanced/Media/Fonts/uf_font.ttf
new file mode 100644
index 0000000..3a7edaf
Binary files /dev/null and b/ElvUI_Enhanced/Media/Fonts/uf_font.ttf differ
diff --git a/ElvUI_Enhanced/Media/Load_Media.xml b/ElvUI_Enhanced/Media/Load_Media.xml
new file mode 100644
index 0000000..1b200e5
--- /dev/null
+++ b/ElvUI_Enhanced/Media/Load_Media.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Media/SharedMedia.lua b/ElvUI_Enhanced/Media/SharedMedia.lua
new file mode 100644
index 0000000..5bd3989
--- /dev/null
+++ b/ElvUI_Enhanced/Media/SharedMedia.lua
@@ -0,0 +1,5 @@
+local E = unpack(ElvUI)
+local LSM = E.Libs.LSM
+
+LSM:Register("font", "TukUI Unitframes", [[Interface\Addons\ElvUI_Enhanced\Media\fonts\uf_font.ttf]], LSM.LOCALE_BIT_ruRU + LSM.LOCALE_BIT_western)
+LSM:Register("statusbar", "BuiOnePixel", [[Interface\Addons\ElvUI_Enhanced\Media\Textures\BuiOnePixel.tga]])
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Media/Textures/AllianceGlow-Logo.blp b/ElvUI_Enhanced/Media/Textures/AllianceGlow-Logo.blp
new file mode 100644
index 0000000..29225fa
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/AllianceGlow-Logo.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/BigTimerNumbers.blp b/ElvUI_Enhanced/Media/Textures/BigTimerNumbers.blp
new file mode 100644
index 0000000..9a929c9
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/BigTimerNumbers.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/BigTimerNumbersGlow.blp b/ElvUI_Enhanced/Media/Textures/BigTimerNumbersGlow.blp
new file mode 100644
index 0000000..8589219
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/BigTimerNumbersGlow.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/BuiOnePixel.tga b/ElvUI_Enhanced/Media/Textures/BuiOnePixel.tga
new file mode 100644
index 0000000..6f04d3d
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/BuiOnePixel.tga differ
diff --git a/ElvUI_Enhanced/Media/Textures/Challenges-Logo.blp b/ElvUI_Enhanced/Media/Textures/Challenges-Logo.blp
new file mode 100644
index 0000000..7837f00
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/Challenges-Logo.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/ChallengesGlow-Logo.blp b/ElvUI_Enhanced/Media/Textures/ChallengesGlow-Logo.blp
new file mode 100644
index 0000000..cd28d9c
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/ChallengesGlow-Logo.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/DeathRecap.BLP b/ElvUI_Enhanced/Media/Textures/DeathRecap.BLP
new file mode 100644
index 0000000..b29d5dd
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/DeathRecap.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/HordeGlow-Logo.blp b/ElvUI_Enhanced/Media/Textures/HordeGlow-Logo.blp
new file mode 100644
index 0000000..af57e69
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/HordeGlow-Logo.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/PaperDollSidebarTabs.blp b/ElvUI_Enhanced/Media/Textures/PaperDollSidebarTabs.blp
new file mode 100644
index 0000000..5d56ed9
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/PaperDollSidebarTabs.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/PartyRaidBlips.blp b/ElvUI_Enhanced/Media/Textures/PartyRaidBlips.blp
new file mode 100644
index 0000000..becde6d
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/PartyRaidBlips.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/RainbowTest.tga b/ElvUI_Enhanced/Media/Textures/RainbowTest.tga
new file mode 100644
index 0000000..0b1c18d
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/RainbowTest.tga differ
diff --git a/ElvUI_Enhanced/Media/Textures/StatSortArrows.blp b/ElvUI_Enhanced/Media/Textures/StatSortArrows.blp
new file mode 100644
index 0000000..14c917f
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/StatSortArrows.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/UI-Cursor-Move.blp b/ElvUI_Enhanced/Media/Textures/UI-Cursor-Move.blp
new file mode 100644
index 0000000..d1135a9
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/UI-Cursor-Move.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/UI-FriendsFrame-HighlightBar-Blue.blp b/ElvUI_Enhanced/Media/Textures/UI-FriendsFrame-HighlightBar-Blue.blp
new file mode 100644
index 0000000..d099305
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/UI-FriendsFrame-HighlightBar-Blue.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/UI-ModelControlPanel.blp b/ElvUI_Enhanced/Media/Textures/UI-ModelControlPanel.blp
new file mode 100644
index 0000000..4a9a167
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/UI-ModelControlPanel.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomDeathKnight.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomDeathKnight.BLP
new file mode 100644
index 0000000..fa563c6
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomDeathKnight.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomDruid.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomDruid.BLP
new file mode 100644
index 0000000..17d3cf9
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomDruid.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomHunter.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomHunter.BLP
new file mode 100644
index 0000000..09a1a0f
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomHunter.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomMage.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomMage.BLP
new file mode 100644
index 0000000..40f818d
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomMage.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomPaladin.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomPaladin.BLP
new file mode 100644
index 0000000..2a5ec19
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomPaladin.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomPriest.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomPriest.BLP
new file mode 100644
index 0000000..04ae4fb
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomPriest.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomRogue.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomRogue.BLP
new file mode 100644
index 0000000..f09be2d
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomRogue.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomShaman.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomShaman.BLP
new file mode 100644
index 0000000..39e48e4
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomShaman.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomWarlock.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomWarlock.BLP
new file mode 100644
index 0000000..7e62ff2
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomWarlock.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomWarrior.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomWarrior.BLP
new file mode 100644
index 0000000..e405086
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/DressingRoomWarrior.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/MountJournal-BG.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/MountJournal-BG.blp
new file mode 100644
index 0000000..4eabc10
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/MountJournal-BG.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/bloodelf_1.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/bloodelf_1.blp
new file mode 100644
index 0000000..bb534b0
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/bloodelf_1.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/bloodelf_2.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/bloodelf_2.blp
new file mode 100644
index 0000000..351f2eb
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/bloodelf_2.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/bloodelf_3.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/bloodelf_3.blp
new file mode 100644
index 0000000..d20b7a2
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/bloodelf_3.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/bloodelf_4.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/bloodelf_4.blp
new file mode 100644
index 0000000..30e97ae
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/bloodelf_4.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/draenei_1.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/draenei_1.blp
new file mode 100644
index 0000000..4b5016a
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/draenei_1.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/draenei_2.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/draenei_2.blp
new file mode 100644
index 0000000..1ddbfe1
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/draenei_2.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/draenei_3.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/draenei_3.blp
new file mode 100644
index 0000000..0e18125
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/draenei_3.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/draenei_4.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/draenei_4.blp
new file mode 100644
index 0000000..23ec7c9
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/draenei_4.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/dwarf_1.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/dwarf_1.blp
new file mode 100644
index 0000000..bb81c73
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/dwarf_1.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/dwarf_2.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/dwarf_2.blp
new file mode 100644
index 0000000..f3cb5d0
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/dwarf_2.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/dwarf_3.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/dwarf_3.blp
new file mode 100644
index 0000000..fb1d4c3
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/dwarf_3.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/dwarf_4.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/dwarf_4.blp
new file mode 100644
index 0000000..ef1cacf
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/dwarf_4.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/gnome_1.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/gnome_1.BLP
new file mode 100644
index 0000000..036156f
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/gnome_1.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/gnome_2.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/gnome_2.BLP
new file mode 100644
index 0000000..f04e06e
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/gnome_2.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/gnome_3.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/gnome_3.BLP
new file mode 100644
index 0000000..292bd0c
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/gnome_3.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/gnome_4.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/gnome_4.blp
new file mode 100644
index 0000000..428f5bb
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/gnome_4.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/human_1.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/human_1.blp
new file mode 100644
index 0000000..a18d57b
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/human_1.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/human_2.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/human_2.blp
new file mode 100644
index 0000000..52b401c
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/human_2.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/human_3.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/human_3.blp
new file mode 100644
index 0000000..7a93b6e
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/human_3.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/human_4.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/human_4.blp
new file mode 100644
index 0000000..3b9dcdd
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/human_4.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/nightelf_1.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/nightelf_1.blp
new file mode 100644
index 0000000..bdb98ac
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/nightelf_1.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/nightelf_2.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/nightelf_2.blp
new file mode 100644
index 0000000..704a98f
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/nightelf_2.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/nightelf_3.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/nightelf_3.BLP
new file mode 100644
index 0000000..77c849b
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/nightelf_3.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/nightelf_4.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/nightelf_4.blp
new file mode 100644
index 0000000..5e62cc2
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/nightelf_4.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/orc_1.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/orc_1.blp
new file mode 100644
index 0000000..82624f0
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/orc_1.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/orc_2.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/orc_2.blp
new file mode 100644
index 0000000..098f8c6
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/orc_2.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/orc_3.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/orc_3.blp
new file mode 100644
index 0000000..77763b0
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/orc_3.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/orc_4.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/orc_4.blp
new file mode 100644
index 0000000..fabe176
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/orc_4.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/petDeathKnight.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/petDeathKnight.blp
new file mode 100644
index 0000000..2878e47
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/petDeathKnight.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/petHunter.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/petHunter.blp
new file mode 100644
index 0000000..9c97cb4
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/petHunter.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/petWarlock.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/petWarlock.blp
new file mode 100644
index 0000000..46535c2
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/petWarlock.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/scourge_1.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/scourge_1.blp
new file mode 100644
index 0000000..da4cb20
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/scourge_1.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/scourge_2.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/scourge_2.blp
new file mode 100644
index 0000000..3be87fb
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/scourge_2.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/scourge_3.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/scourge_3.blp
new file mode 100644
index 0000000..a751e14
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/scourge_3.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/scourge_4.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/scourge_4.blp
new file mode 100644
index 0000000..c779420
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/scourge_4.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/tauren_1.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/tauren_1.blp
new file mode 100644
index 0000000..db4d55a
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/tauren_1.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/tauren_2.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/tauren_2.blp
new file mode 100644
index 0000000..36e2446
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/tauren_2.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/tauren_3.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/tauren_3.blp
new file mode 100644
index 0000000..e75a1cf
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/tauren_3.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/tauren_4.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/tauren_4.blp
new file mode 100644
index 0000000..01eb524
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/tauren_4.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/troll_1.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/troll_1.BLP
new file mode 100644
index 0000000..2bee185
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/troll_1.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/troll_2.blp b/ElvUI_Enhanced/Media/Textures/backgrounds/troll_2.blp
new file mode 100644
index 0000000..3c18df7
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/troll_2.blp differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/troll_3.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/troll_3.BLP
new file mode 100644
index 0000000..7d54719
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/troll_3.BLP differ
diff --git a/ElvUI_Enhanced/Media/Textures/backgrounds/troll_4.BLP b/ElvUI_Enhanced/Media/Textures/backgrounds/troll_4.BLP
new file mode 100644
index 0000000..de04b49
Binary files /dev/null and b/ElvUI_Enhanced/Media/Textures/backgrounds/troll_4.BLP differ
diff --git a/ElvUI_Enhanced/Modules/Actionbars/KeyPressAnimation.lua b/ElvUI_Enhanced/Modules/Actionbars/KeyPressAnimation.lua
new file mode 100644
index 0000000..5658c92
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Actionbars/KeyPressAnimation.lua
@@ -0,0 +1,114 @@
+local E, L, V, P, G = unpack(ElvUI)
+local KPA = E:NewModule("Enhanced_KeyPressAnimation")
+local LAB = E.Libs.LAB
+
+local ipairs = ipairs
+local tinsert, tremove = table.insert, table.remove
+
+local CreateFrame = CreateFrame
+
+local framePool = {}
+
+local function OnFinished(self)
+ tinsert(framePool, self.parent)
+end
+
+local function CreateAnimationFrame()
+ local db = E.db.enhanced.actionbar.keyPressAnimation
+
+ local frame = CreateFrame("Frame", "Enhanced_KeyPressAnimation"..(#KPA.frames + 1), UIParent)
+
+ local texture = frame:CreateTexture()
+ texture:SetTexture([[Interface\Cooldown\star4]])
+ texture:SetAlpha(0)
+ texture:SetAllPoints()
+ texture:SetBlendMode("ADD")
+ texture:SetVertexColor(db.color.r, db.color.g, db.color.b)
+ frame.texture = texture
+
+ local animationGroup = texture:CreateAnimationGroup()
+ animationGroup:SetScript("OnFinished", OnFinished)
+ animationGroup.parent = frame
+ frame.animationGroup = animationGroup
+
+ local alpha1 = animationGroup:CreateAnimation("Alpha")
+ alpha1:SetChange(1)
+ alpha1:SetDuration(0)
+ alpha1:SetOrder(1)
+ frame.alpha1 = alpha1
+
+ local scale1 = animationGroup:CreateAnimation("Scale")
+ scale1:SetScale(1.0, 1.0)
+ scale1:SetDuration(0)
+ scale1:SetOrder(1)
+ frame.scale1 = scale1
+
+ local scale2 = animationGroup:CreateAnimation("Scale")
+ scale2:SetScale(db.scale, db.scale)
+ scale2:SetDuration(0.2)
+ scale2:SetOrder(2)
+ frame.scale2 = scale2
+
+ local rotation = animationGroup:CreateAnimation("Rotation")
+ rotation:SetDegrees(db.rotation)
+ rotation:SetDuration(0.2)
+ rotation:SetOrder(2)
+ frame.rotation = rotation
+
+ tinsert(KPA.frames, frame)
+
+ return frame
+end
+
+local function StartAnimation(button)
+ if not button:IsVisible() or button:GetParent():GetAlpha() == 0 then return end
+
+ local frame = KPA:GetFreeAnimationFrame()
+ local animationGroup = frame.animationGroup
+
+ frame:SetFrameStrata(button:GetFrameStrata())
+ frame:SetFrameLevel(button:GetFrameLevel() + 10)
+ frame:SetAllPoints(button)
+
+ frame.button = button
+
+ animationGroup:Play()
+end
+
+function KPA:GetFreeAnimationFrame()
+ return #framePool > 0 and tremove(framePool) or CreateAnimationFrame()
+end
+
+function KPA:UpdateSetting()
+ local db = E.db.enhanced.actionbar.keyPressAnimation
+
+ for _, frame in ipairs(self.frames) do
+ frame.texture:SetVertexColor(db.color.r, db.color.g, db.color.b)
+ frame.scale2:SetScale(db.scale, db.scale)
+ frame.rotation:SetDegrees(db.rotation)
+ end
+end
+
+function KPA:Initialize()
+ if not E.private.enhanced.actionbar.keyPressAnimation then return end
+
+ self.frames = {}
+
+ for i = 1, 3 do
+ tinsert(framePool, CreateAnimationFrame())
+ end
+
+ LAB.RegisterCallback(KPA, "OnButtonCreated", function(_, button)
+ button:HookScript("PreClick", StartAnimation)
+ end)
+
+ for button in pairs(LAB.buttonRegistry) do
+ button:HookScript("PreClick", StartAnimation)
+ end
+end
+
+local function InitializeCallback()
+ KPA:Initialize()
+end
+
+E:RegisterModule(KPA:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Actionbars/Load_Actionbars.xml b/ElvUI_Enhanced/Modules/Actionbars/Load_Actionbars.xml
new file mode 100644
index 0000000..b48fc90
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Actionbars/Load_Actionbars.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/AddonList.lua b/ElvUI_Enhanced/Modules/Blizzard/AddonList.lua
new file mode 100644
index 0000000..d16d82d
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/AddonList.lua
@@ -0,0 +1,426 @@
+local E, L, V, P, G = unpack(ElvUI)
+local mod = E:GetModule("Enhanced_Blizzard")
+
+local _G = _G
+local select = select
+local floor = math.floor
+local tconcat = table.concat
+
+local CreateFrame = CreateFrame
+local DisableAddOn = DisableAddOn
+local EnableAddOn = EnableAddOn
+local GetAddOnDependencies = GetAddOnDependencies
+local GetAddOnInfo = GetAddOnInfo
+local GetNumAddOns = GetNumAddOns
+local IsAddOnLoadOnDemand = IsAddOnLoadOnDemand
+local IsAddOnLoaded = IsAddOnLoaded
+local IsShiftKeyDown = IsShiftKeyDown
+local LoadAddOn = LoadAddOn
+local PlaySound = PlaySound
+
+local function AddonList_HasAnyChanged()
+ local status = ElvUI_AddonList.startStatus
+
+ for i = 1, GetNumAddOns() do
+ local _, _, _, enabled, _, reason = GetAddOnInfo(i)
+
+ if not ((enabled == status[i].enabled and not status[i].lod)
+ or reason == "DEP_DISABLED"
+ or status[i].reason == "DEP_DISABLED"
+ or (enabled and status[i].lod and not IsAddOnLoaded(i))
+ or (not enabled and status[i].lod and not IsAddOnLoaded(i)))
+ then
+ return true
+ end
+ end
+end
+
+local function AddonList_IsAddOnLoadOnDemand(index)
+ if IsAddOnLoadOnDemand(index) and not IsAddOnLoaded(index) then
+ return true
+ end
+end
+
+local function AddonList_IsDepsLoaded(...)
+ local depsCount = select("#", ...)
+ if depsCount == 0 then return end
+
+ for i = 1, depsCount do
+ if not IsAddOnLoaded(select(i, ...)) then
+ return
+ end
+ end
+
+ return true
+end
+
+local function AddonList_SetStatus(entry, load, status, reload)
+ if load then
+ entry.LoadButton:Show()
+ else
+ entry.LoadButton:Hide()
+ end
+
+ if status then
+ entry.Status:Show()
+ else
+ entry.Status:Hide()
+ end
+
+ if reload then
+ entry.Reload:Show()
+ else
+ entry.Reload:Hide()
+ end
+end
+
+local function AddonList_Update()
+ local numEntries = GetNumAddOns()
+ local addonIndex, entry, checkbox, status
+
+ for i = 1, 20 do
+ addonIndex = ElvUI_AddonList.offset + i
+ entry = _G["ElvUI_AddonListEntry"..i]
+
+ if addonIndex > numEntries then
+ entry:Hide()
+ else
+ local name, title, _, enabled, loadable, reason = GetAddOnInfo(addonIndex)
+
+ checkbox = _G["ElvUI_AddonListEntry"..i.."Enabled"]
+ checkbox:SetChecked(enabled)
+
+ status = _G["ElvUI_AddonListEntry"..i.."Title"]
+
+ if loadable or (enabled and (reason == "DEP_DEMAND_LOADED" or reason == "DEMAND_LOADED")) then
+ status:SetTextColor(1.0, 0.78, 0.0)
+ elseif enabled and reason ~= "DEP_DISABLED" then
+ status:SetTextColor(1.0, 0.1, 0.1)
+ else
+ status:SetTextColor(0.5, 0.5, 0.5)
+ end
+
+ if title then
+ status:SetText(title)
+ else
+ status:SetText(name)
+ end
+
+ status = _G["ElvUI_AddonListEntry"..i.."Status"]
+ if not loadable and reason then
+ status:SetText(_G["ADDON_"..reason])
+ else
+ status:SetText("")
+ end
+
+ if enabled ~= ElvUI_AddonList.startStatus[addonIndex].enabled and reason ~= "DEP_DISABLED" and ElvUI_AddonList.startStatus[addonIndex].reason ~= "DEP_DISABLED" then
+ if enabled then
+ if AddonList_IsAddOnLoadOnDemand(addonIndex) then
+ if AddonList_IsDepsLoaded(GetAddOnDependencies(addonIndex)) then
+ AddonList_SetStatus(entry, true)
+ else
+ AddonList_SetStatus(entry)
+ end
+ else
+ AddonList_SetStatus(entry, nil, nil, true)
+ end
+ elseif AddonList_IsAddOnLoadOnDemand(addonIndex) then
+ AddonList_SetStatus(entry, nil, true)
+ else
+ AddonList_SetStatus(entry, nil, nil, true)
+ end
+ else
+ AddonList_SetStatus(entry, nil, true)
+ end
+
+ entry.id = addonIndex
+ entry:Show()
+ end
+ end
+
+ FauxScrollFrame_Update(ElvUI_AddonListScrollFrame, numEntries, 20, 16, nil, nil, nil, nil, nil, nil, true)
+
+ if AddonList_HasAnyChanged() then
+ ElvUI_AddonListOkayButton:SetText(L["Reload UI"])
+ ElvUI_AddonList.shouldReload = true
+ else
+ ElvUI_AddonListOkayButton:SetText(OKAY)
+ ElvUI_AddonList.shouldReload = false
+ end
+end
+
+local function AddonList_Enable(index, enabled)
+ if enabled then
+ EnableAddOn(index)
+ else
+ DisableAddOn(index)
+ end
+
+ AddonList_Update()
+end
+
+local function AddonList_LoadAddOn(index)
+ if not AddonList_IsAddOnLoadOnDemand(index) then return end
+
+ LoadAddOn(index)
+
+ if IsAddOnLoaded(index) then
+ ElvUI_AddonList.startStatus[index].enabled = 1
+ ElvUI_AddonList.startStatus[index].lod = nil
+ end
+
+ AddonList_Update()
+end
+
+local function AddonTooltip_BuildDeps(...)
+ local depsCount = select("#", ...)
+ if depsCount == 0 then return end
+
+ local deps
+
+ if depsCount == 1 then
+ deps = ...
+ elseif depsCount > 1 then
+ deps = tconcat({...}, ", ")
+ end
+
+ return L["Dependencies: "] .. deps
+end
+
+local function AddonTooltip_Update(self)
+ local name, title, notes, _, _, security = GetAddOnInfo(self.id)
+ if not name then return end
+
+ GameTooltip:SetOwner(self)
+
+ if security == "BANNED" then
+ GameTooltip:SetText(L["This addon has been disabled. You should install an updated version."])
+ else
+ if title then
+ GameTooltip:AddLine(title)
+ else
+ GameTooltip:AddLine(name)
+ end
+
+ GameTooltip:AddLine(notes, 1.0, 1.0, 1.0)
+
+ local dependsStr = AddonTooltip_BuildDeps(GetAddOnDependencies(self.id))
+ if dependsStr then
+ GameTooltip:AddLine(AddonTooltip_BuildDeps(GetAddOnDependencies(self.id)))
+ end
+ end
+
+ GameTooltip:Show()
+end
+
+function mod:AddonList()
+ if IsAddOnLoaded("ACP") then return end
+
+ local S = E:GetModule("Skins")
+
+ local addonList = CreateFrame("Frame", "ElvUI_AddonList", UIParent)
+ addonList:SetFrameStrata("HIGH")
+ addonList:Size(520, 466)
+ addonList:Point("CENTER", 0, 0)
+ addonList:SetTemplate("Transparent")
+ addonList:SetClampedToScreen(true)
+ addonList:SetMovable(true)
+ addonList:EnableMouse(true)
+ addonList:RegisterForDrag("LeftButton")
+ addonList:Hide()
+ tinsert(UISpecialFrames, addonList:GetName())
+
+ addonList.offset = 0
+ addonList.startStatus = {}
+
+ for i = 1, GetNumAddOns() do
+ local _, _, _, enabled, _, reason = GetAddOnInfo(i)
+ addonList.startStatus[i] = {
+ enabled = enabled,
+ reason = reason,
+ lod = IsAddOnLoadOnDemand(i)
+ }
+ end
+
+ addonList:SetScript("OnDragStart", function(self)
+ if IsShiftKeyDown() then
+ self:StartMoving()
+ end
+ end)
+ addonList:SetScript("OnDragStop", function(self)
+ self:StopMovingOrSizing()
+ end)
+
+ local addonTitle = addonList:CreateFontString("$parentTitle", "BACKGROUND", "GameFontNormal")
+ addonTitle:Point("TOP", 0, -7)
+ addonTitle:SetText(ADDONS)
+
+ local cancelButton = CreateFrame("Button", "$parentCancelButton", addonList, "UIPanelButtonTemplate")
+ cancelButton:Size(80, 22)
+ cancelButton:Point("BOTTOMRIGHT", -8, 8)
+ cancelButton:SetText(CANCEL)
+ S:HandleButton(cancelButton)
+ cancelButton:SetScript("OnClick", function()
+ ElvUI_AddonList:Hide()
+ end)
+
+ local okayButton = CreateFrame("Button", "$parentOkayButton", addonList, "UIPanelButtonTemplate")
+ okayButton:Size(80, 22)
+ okayButton:Point("RIGHT", cancelButton, "LEFT", -7, 0)
+ okayButton:SetText(OKAY)
+ S:HandleButton(okayButton)
+ okayButton:SetScript("OnClick", function()
+ if ElvUI_AddonList.shouldReload then
+ ReloadUI()
+ else
+ ElvUI_AddonList:Hide()
+ end
+ end)
+
+ local enableAllButton = CreateFrame("Button", "$parentEnableAllButton", addonList, "UIPanelButtonTemplate")
+ enableAllButton:Size(120, 22)
+ enableAllButton:Point("BOTTOMLEFT", 8, 8)
+ enableAllButton:SetText(L["Enable All"])
+ S:HandleButton(enableAllButton)
+ enableAllButton:SetScript("OnClick", function()
+ EnableAllAddOns()
+ AddonList_Update()
+ end)
+
+ local disableAllButton = CreateFrame("Button", "$parentDisableAllButton", addonList, "UIPanelButtonTemplate")
+ disableAllButton:Size(120, 22)
+ disableAllButton:Point("LEFT", enableAllButton, "RIGHT", 7, 0)
+ disableAllButton:SetText(L["Disable All"])
+ S:HandleButton(disableAllButton)
+ disableAllButton:SetScript("OnClick", function()
+ DisableAllAddOns()
+ AddonList_Update()
+ end)
+
+ addonList:SetScript("OnShow", function()
+ AddonList_Update()
+ PlaySound("igMainMenuOption")
+ end)
+ addonList:SetScript("OnHide", function()
+ PlaySound("igMainMenuOptionCheckBoxOn")
+ end)
+
+ local scrollFrame = CreateFrame("ScrollFrame", "$parentScrollFrame", addonList, "FauxScrollFrameTemplate")
+ scrollFrame:SetTemplate("Transparent")
+ scrollFrame:Point("TOPLEFT", 8, -25)
+ scrollFrame:Point("BOTTOMRIGHT", -29, 37)
+ scrollFrame.scrollBar = _G[scrollFrame:GetName().."ScrollBar"]
+ S:HandleScrollBar(scrollFrame.scrollBar, 5)
+
+ scrollFrame.scrollBar:Point("TOPLEFT", scrollFrame, "TOPRIGHT", 4, -18)
+ scrollFrame.scrollBar:Point("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", 4, 18)
+
+ scrollFrame:SetScript("OnVerticalScroll", function(self, offset)
+ self.scrollBar:SetValue(offset)
+ addonList.offset = floor((offset / 16) + 0.5)
+ AddonList_Update()
+
+ if GameTooltip:IsShown() then
+ AddonTooltip_Update(GameTooltip:GetOwner())
+ end
+ end)
+
+ local function Enable_OnClick(self)
+ AddonList_Enable(self:GetParent().id, self:GetChecked())
+ PlaySound("igMainMenuOptionCheckBoxOn")
+ end
+
+ local function Load_OnClick(self)
+ AddonList_LoadAddOn(self:GetParent().id)
+ end
+
+ local addonListEntry = {}
+ for i = 1, 20 do
+ addonListEntry[i] = CreateFrame("Button", "ElvUI_AddonListEntry"..i, scrollFrame)
+ addonListEntry[i]:Size(scrollFrame:GetWidth() - 8, 16)
+ addonListEntry[i].id = i
+
+ if i == 1 then
+ addonListEntry[i]:Point("TOPLEFT", 4, -4)
+ else
+ addonListEntry[i]:Point("TOP", addonListEntry[i - 1], "BOTTOM", 0, -4)
+ end
+
+ local enabled = CreateFrame("CheckButton", "$parentEnabled", addonListEntry[i])
+ enabled:Size(24, 24)
+ enabled:Point("LEFT", -4, 0)
+ S:HandleCheckBox(enabled)
+
+ local title = addonListEntry[i]:CreateFontString("$parentTitle", "BACKGROUND", "GameFontNormal")
+ title:Size(220, 12)
+ title:Point("LEFT", 22, 0)
+ title:SetJustifyH("LEFT")
+
+ local status = addonListEntry[i]:CreateFontString("$parentStatus", "BACKGROUND", "GameFontNormalSmall")
+ status:Size(220, 12)
+ status:Point("RIGHT", -22, 0)
+ status:SetJustifyH("RIGHT")
+ addonListEntry[i].Status = status
+
+ local reload = addonListEntry[i]:CreateFontString("$parentReload", "BACKGROUND", "GameFontRed")
+ reload:Size(220, 12)
+ reload:Point("RIGHT", -22, 0)
+ reload:SetJustifyH("RIGHT")
+ reload:SetText(L["Requires Reload"])
+ addonListEntry[i].Reload = reload
+
+ local load = CreateFrame("Button", "$parentLoad", addonListEntry[i], "UIPanelButtonTemplate")
+ load:Size(100, 22)
+ load:Point("RIGHT", -21, 0)
+ load:SetText(L["Load AddOn"])
+ S:HandleButton(load)
+ addonListEntry[i].LoadButton = load
+
+ addonListEntry[i]:SetScript("OnEnter", AddonTooltip_Update)
+ addonListEntry[i]:SetScript("OnLeave", GameTooltip_Hide)
+
+ enabled:SetScript("OnClick", Enable_OnClick)
+ load:SetScript("OnClick", Load_OnClick)
+ end
+
+ local buttonAddons = CreateFrame("Button", "ElvUI_AddonListButton", GameMenuFrame, "GameMenuButtonTemplate")
+ buttonAddons:Point("TOP", GameMenuButtonMacros, "BOTTOM", 0, -1)
+ buttonAddons:SetText(ADDONS)
+ S:HandleButton(buttonAddons)
+ buttonAddons:SetScript("OnClick", function()
+ HideUIPanel(GameMenuFrame)
+ ElvUI_AddonList:Show()
+ end)
+
+ self:HookScript(GameMenuButtonRatings, "OnShow", function(self)
+ buttonAddons:Point("TOP", self, "BOTTOM", 0, -1)
+ end)
+
+ self:HookScript(GameMenuButtonRatings, "OnHide", function(self)
+ buttonAddons:Point("TOP", GameMenuButtonMacros, "BOTTOM", 0, -1)
+ end)
+
+ GameMenuButtonLogout:SetScript("OnShow", function(self)
+ self:Point("TOP", buttonAddons, "BOTTOM", 0, -16)
+
+ if not StaticPopup_Visible("CAMP") and not StaticPopup_Visible("QUIT") then
+ self:Enable()
+ else
+ self:Disable()
+ end
+ end)
+
+ if GetLocale() == "koKR" then
+ if IsMacClient() then
+ GameMenuFrame:Height(308)
+ else
+ GameMenuFrame:Height(282)
+ end
+ else
+ if IsMacClient() then
+ GameMenuFrame:Height(292)
+ else
+ GameMenuFrame:Height(266)
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/AnimatedAchievementsBars.lua b/ElvUI_Enhanced/Modules/Blizzard/AnimatedAchievementsBars.lua
new file mode 100644
index 0000000..71290f1
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/AnimatedAchievementsBars.lua
@@ -0,0 +1,114 @@
+local E, L, V, P, G = unpack(ElvUI)
+local S = E:GetModule("Skins")
+
+local _G = _G
+local band = bit.band
+
+local function LoadSkin()
+ if not E.private.enhanced.animatedAchievementBars then return end
+
+ local function AnimationStatusBar(bar, noNumber)
+ bar.anim = CreateAnimationGroup(bar)
+ bar.anim.progress = bar.anim:CreateAnimation("Progress")
+ bar.anim.progress:SetSmoothing("Out")
+ bar.anim.progress:SetDuration(1.7)
+
+ bar.anim.color = bar.anim:CreateAnimation("Color")
+ bar.anim.color:SetSmoothing("Out")
+ bar.anim.color:SetColorType("Statusbar")
+ bar.anim.color:SetDuration(1.7)
+ bar.anim.color.StartR, bar.anim.color.StartG, bar.anim.color.StartB = 1, 0, 0
+
+ if not noNumber then
+ bar.anim2 = CreateAnimationGroup(_G[bar:GetName() .. "Text"])
+ bar.anim2.number = bar.anim2:CreateAnimation("Number")
+ bar.anim2.number:SetDuration(1.7)
+ end
+ end
+
+ local function PlayAnimationStatusBar(bar, max, value, noNumber)
+ if bar.anim:IsPlaying() or (bar.anim2 and bar.anim2:IsPlaying()) then
+ bar.anim:Stop()
+ if not noNumber then
+ bar.anim2:Stop()
+ end
+ end
+ bar:SetValue(0)
+ bar.anim.progress:SetChange(value)
+
+ local r, g, b = E:ColorGradient(value / max, 1, 0, 0, 1, 1, 0, 0, 1, 0)
+ bar.anim.color:Reset()
+ bar.anim.color:SetChange(r, g, b)
+ bar.anim:Play()
+
+ if not noNumber then
+ bar.anim2.number:SetPostfix("/" .. max)
+ bar.anim2.number:SetChange(value)
+ bar.anim2:Play()
+ end
+ end
+
+ AnimationStatusBar(AchievementFrameSummaryCategoriesStatusBar)
+ AnimationStatusBar(AchievementFrameComparisonSummaryPlayerStatusBar)
+ AnimationStatusBar(AchievementFrameComparisonSummaryFriendStatusBar)
+
+ for i = 1, 8 do
+ local frame = _G["AchievementFrameSummaryCategoriesCategory" .. i]
+ AnimationStatusBar(frame)
+ end
+
+ hooksecurefunc("AchievementFrameCategory_StatusBarTooltip", function(self)
+ local index = GameTooltip.shownStatusBars
+ local name = GameTooltip:GetName() .. "StatusBar" .. index
+ local statusBar = _G[name]
+ if not statusBar then return end
+
+ if not statusBar.anim then
+ AnimationStatusBar(statusBar)
+ end
+
+ PlayAnimationStatusBar(statusBar, self.numAchievements, self.numCompleted)
+ end)
+
+ hooksecurefunc("AchievementFrameComparison_UpdateStatusBars", function(id)
+ local numAchievements, numCompleted = GetCategoryNumAchievements(id)
+ local statusBar = AchievementFrameComparisonSummaryPlayerStatusBar
+ PlayAnimationStatusBar(statusBar, numAchievements, numCompleted)
+
+ local friendCompleted = GetComparisonCategoryNumAchievements(id)
+ statusBar = AchievementFrameComparisonSummaryFriendStatusBar
+ PlayAnimationStatusBar(statusBar, numAchievements, friendCompleted)
+ end)
+
+ hooksecurefunc("AchievementFrameSummaryCategoriesStatusBar_Update", function()
+ local total, completed = GetNumCompletedAchievements()
+ PlayAnimationStatusBar(AchievementFrameSummaryCategoriesStatusBar, total, completed)
+ end)
+
+ hooksecurefunc("AchievementFrameSummaryCategory_OnShow", function(self)
+ local totalAchievements, totalCompleted = AchievementFrame_GetCategoryTotalNumAchievements(self:GetID(), true)
+ PlayAnimationStatusBar(self, totalAchievements, totalCompleted)
+ end)
+
+ hooksecurefunc("AchievementButton_GetProgressBar", function(index)
+ local frame = _G["AchievementFrameProgressBar" .. index]
+ if frame and not frame.anim then
+ AnimationStatusBar(frame, true)
+ end
+ end)
+
+ hooksecurefunc("AchievementObjectives_DisplayCriteria", function(objectivesFrame, id)
+ local numCriteria = GetAchievementNumCriteria(id)
+ local progressBars = 0
+ for i = 1, numCriteria do
+ local _, _, _, quantity, reqQuantity, _, flags = GetAchievementCriteriaInfo(id, i)
+ if band(flags, ACHIEVEMENT_CRITERIA_PROGRESS_BAR) == ACHIEVEMENT_CRITERIA_PROGRESS_BAR then
+ progressBars = progressBars + 1
+ local progressBar = AchievementButton_GetProgressBar(progressBars)
+ PlayAnimationStatusBar(progressBar, reqQuantity, quantity, true)
+ end
+ end
+ end)
+end
+
+S:AddCallbackForAddon("Blizzard_AchievementUI", "Enhanced_AchievementUI", LoadSkin)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/BetterSearchBox.lua b/ElvUI_Enhanced/Modules/Blizzard/BetterSearchBox.lua
new file mode 100644
index 0000000..aaee546
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/BetterSearchBox.lua
@@ -0,0 +1,74 @@
+local E, L, V, P, G = unpack(ElvUI)
+local S = E:GetModule("Skins")
+
+local function SearchBoxTemplate(frame)
+ frame:SetTextInsets(16, 20, 0, 0)
+
+ frame.Instructions = frame:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall")
+ frame.Instructions:SetText(SEARCH)
+ frame.Instructions:SetPoint("TOPLEFT", frame, "TOPLEFT", 16, 0)
+ frame.Instructions:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -20, 0)
+ frame.Instructions:SetTextColor(0.35, 0.35, 0.35)
+ frame.Instructions:SetJustifyH("LEFT")
+ frame.Instructions:SetJustifyV("MIDDLE")
+
+ frame.searchIcon = frame:CreateTexture(nil, "OVERLAY")
+ frame.searchIcon:SetTexture("Interface\\Common\\UI-Searchbox-Icon")
+ frame.searchIcon:SetVertexColor(0.6, 0.6, 0.6)
+ frame.searchIcon:Size(14)
+ frame.searchIcon:Point("LEFT", 0, -2)
+
+ frame.clearButton = CreateFrame("Button", nil, frame)
+ frame.clearButton:Size(14)
+ frame.clearButton:Point("RIGHT", -3, 0)
+
+ frame.clearButton.texture = frame.clearButton:CreateTexture()
+ frame.clearButton.texture:SetTexture("Interface\\FriendsFrame\\ClearBroadcastIcon")
+ frame.clearButton.texture:SetAlpha(0.5)
+ frame.clearButton.texture:Size(17)
+ frame.clearButton.texture:Point("CENTER", 0, 0)
+
+ frame.clearButton:SetScript("OnEnter", function(self) self.texture:SetAlpha(1.0) end)
+ frame.clearButton:SetScript("OnLeave", function(self) self.texture:SetAlpha(0.5) end)
+ frame.clearButton:SetScript("OnMouseDown", function(self) if self:IsEnabled() then self.texture:Point("CENTER", 1, -1) end end)
+ frame.clearButton:SetScript("OnMouseUp", function(self) self.texture:Point("CENTER") end)
+ frame.clearButton:SetScript("OnClick", function(self)
+ local editBox = self:GetParent()
+ editBox:SetText("")
+ editBox:ClearFocus()
+ end)
+
+ frame:SetScript("OnShow", nil)
+ frame:SetScript("OnEditFocusLost", function(self)
+ if self:GetText() == "" then
+ self.searchIcon:SetVertexColor(0.6, 0.6, 0.6)
+ self.clearButton:Hide()
+ end
+ end)
+ frame:SetScript("OnEditFocusGained", function(self)
+ self.searchIcon:SetVertexColor(1.0, 1.0, 1.0)
+ self.clearButton:Show()
+ end)
+ frame:HookScript("OnTextChanged", function(self)
+ if not self:HasFocus() and self:GetText() == "" then
+ self.searchIcon:SetVertexColor(0.6, 0.6, 0.6)
+ self.clearButton:Hide()
+ else
+ self.searchIcon:SetVertexColor(1.0, 1.0, 1.0)
+ self.clearButton:Show()
+ end
+ if self:GetText() == "" then
+ self.Instructions:Show()
+ else
+ self.Instructions:Hide()
+ end
+ end)
+end
+
+S:AddCallbackForAddon("Blizzard_AuctionUI", "Enhanced_AuctionUI", function()
+ SearchBoxTemplate(BrowseName)
+end)
+
+S:AddCallbackForAddon("Blizzard_TradeSkillUI", "Enhanced_TradeSkillUI", function()
+ SearchBoxTemplate(TradeSkillFrameEditBox)
+end)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/Blizzard.lua b/ElvUI_Enhanced/Modules/Blizzard/Blizzard.lua
new file mode 100644
index 0000000..1991754
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/Blizzard.lua
@@ -0,0 +1,15 @@
+local E, L, V, P, G = unpack(ElvUI)
+local mod = E:NewModule("Enhanced_Blizzard", "AceHook-3.0", "AceEvent-3.0")
+
+function mod:Initialize()
+ self:DeathRecap()
+ self:AddonList()
+ self:DressUpFrame()
+ self:ErrorFrameSize()
+end
+
+local function InitializeCallback()
+ mod:Initialize()
+end
+
+E:RegisterModule(mod:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/CharacterFrame.lua b/ElvUI_Enhanced/Modules/Blizzard/CharacterFrame.lua
new file mode 100644
index 0000000..48c3b28
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/CharacterFrame.lua
@@ -0,0 +1,3039 @@
+local E, L, V, P, G = unpack(ElvUI)
+local module = E:NewModule("Enhanced_CharacterFrame", "AceHook-3.0", "AceEvent-3.0")
+local S = E:GetModule("Skins")
+
+local _G = _G
+local select, next, ipairs, pairs, tonumber, getmetatable = select, next, ipairs, pairs, tonumber, getmetatable
+local abs, floor, max, min = math.abs, math.floor, math.max, math.min
+local find, format, gmatch, lower, sub, trim = string.find, string.format, string.gmatch, string.lower, string.sub, string.trim
+local tconcat, tinsert, tremove, sort, wipe = table.concat, table.insert, table.remove, table.sort, table.wipe
+
+local CreateFrame = CreateFrame
+local GetActiveTalentGroup = GetActiveTalentGroup
+local GetAttackPowerForStat = GetAttackPowerForStat
+local GetBlockChance = GetBlockChance
+local GetCombatRating = GetCombatRating
+local GetCombatRatingBonus = GetCombatRatingBonus
+local GetCompanionCooldown = GetCompanionCooldown
+local GetCompanionInfo = GetCompanionInfo
+local GetCritChance = GetCritChance
+local GetCritChanceFromAgility = GetCritChanceFromAgility
+local GetCurrentTitle = GetCurrentTitle
+local GetCursorPosition = GetCursorPosition
+local GetDodgeChance = GetDodgeChance
+local GetEquipmentSetInfo = GetEquipmentSetInfo
+local GetEquipmentSetInfoByName = GetEquipmentSetInfoByName
+local GetInventoryItemLink = GetInventoryItemLink
+local GetItemInfo = GetItemInfo
+local GetMaxCombatRatingBonus = GetMaxCombatRatingBonus
+local GetNumCompanions = GetNumCompanions
+local GetNumEquipmentSets = GetNumEquipmentSets
+local GetNumTitles = GetNumTitles
+local GetParryChance = GetParryChance
+local GetScreenHeightScale = GetScreenHeightScale
+local GetShieldBlock = GetShieldBlock
+local GetSpellCritChanceFromIntellect = GetSpellCritChanceFromIntellect
+local GetTitleName = GetTitleName
+local GetUnitHealthModifier = GetUnitHealthModifier
+local GetUnitHealthRegenRateFromSpirit = GetUnitHealthRegenRateFromSpirit
+local GetUnitManaRegenRateFromSpirit = GetUnitManaRegenRateFromSpirit
+local GetUnitMaxHealthModifier = GetUnitMaxHealthModifier
+local GetUnitPowerModifier = GetUnitPowerModifier
+local HasPetUI = HasPetUI
+local IsTitleKnown = IsTitleKnown
+local PlaySound = PlaySound
+local SetPortraitTexture = SetPortraitTexture
+local UnitAttackSpeed = UnitAttackSpeed
+local UnitClass = UnitClass
+local UnitDamage = UnitDamage
+local UnitHasMana = UnitHasMana
+local UnitHasRelicSlot = UnitHasRelicSlot
+local UnitLevel = UnitLevel
+local UnitRace = UnitRace
+local UnitResistance = UnitResistance
+local UnitStat = UnitStat
+
+local CharacterRangedDamageFrame_OnEnter = CharacterRangedDamageFrame_OnEnter
+local CharacterSpellCritChance_OnEnter = CharacterSpellCritChance_OnEnter
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local GameTooltip_Hide = GameTooltip_Hide
+local GearManagerDialogSaveSet_OnClick = GearManagerDialogSaveSet_OnClick
+local PaperDollFrameItemPopoutButton_HideAll = PaperDollFrameItemPopoutButton_HideAll
+local PaperDollFrameItemPopoutButton_ShowAll = PaperDollFrameItemPopoutButton_ShowAll
+local PaperDollFrame_ClearIgnoredSlots = PaperDollFrame_ClearIgnoredSlots
+local PaperDollFrame_SetArmor = PaperDollFrame_SetArmor
+local PaperDollFrame_SetAttackPower = PaperDollFrame_SetAttackPower
+local PaperDollFrame_SetAttackSpeed = PaperDollFrame_SetAttackSpeed
+local PaperDollFrame_SetDamage = PaperDollFrame_SetDamage
+local PaperDollFrame_SetDefense = PaperDollFrame_SetDefense
+local PaperDollFrame_SetExpertise = PaperDollFrame_SetExpertise
+local PaperDollFrame_SetManaRegen = PaperDollFrame_SetManaRegen
+local PaperDollFrame_SetRangedAttackPower = PaperDollFrame_SetRangedAttackPower
+local PaperDollFrame_SetRangedAttackSpeed = PaperDollFrame_SetRangedAttackSpeed
+local PaperDollFrame_SetRangedCritChance = PaperDollFrame_SetRangedCritChance
+local PaperDollFrame_SetRangedDamage = PaperDollFrame_SetRangedDamage
+local PaperDollFrame_SetRating = PaperDollFrame_SetRating
+local PaperDollFrame_SetSpellBonusDamage = PaperDollFrame_SetSpellBonusDamage
+local PaperDollFrame_SetSpellBonusHealing = PaperDollFrame_SetSpellBonusHealing
+local PaperDollFrame_SetSpellCritChance = PaperDollFrame_SetSpellCritChance
+local PaperDollFrame_SetSpellHaste = PaperDollFrame_SetSpellHaste
+local PetPaperDollFrameCompanionFrame = PetPaperDollFrameCompanionFrame
+local PetPaperDollFrame_FindCompanionIndex = PetPaperDollFrame_FindCompanionIndex
+
+local GearManagerDialog = GearManagerDialog
+
+local ARMOR_PER_AGILITY = ARMOR_PER_AGILITY
+local BLOCK_CHANCE = BLOCK_CHANCE
+local BLOCK_PER_STRENGTH = BLOCK_PER_STRENGTH
+local CR_BLOCK = CR_BLOCK
+local CR_BLOCK_TOOLTIP = CR_BLOCK_TOOLTIP
+local CR_CRIT_MELEE = CR_CRIT_MELEE
+local CR_CRIT_MELEE_TOOLTIP = CR_CRIT_MELEE_TOOLTIP
+local CR_CRIT_TAKEN_MELEE = CR_CRIT_TAKEN_MELEE
+local CR_CRIT_TAKEN_RANGED = CR_CRIT_TAKEN_RANGED
+local CR_CRIT_TAKEN_SPELL = CR_CRIT_TAKEN_SPELL
+local CR_DODGE = CR_DODGE
+local CR_DODGE_TOOLTIP = CR_DODGE_TOOLTIP
+local CR_HIT_MELEE = CR_HIT_MELEE
+local CR_HIT_RANGED = CR_HIT_RANGED
+local CR_HIT_SPELL = CR_HIT_SPELL
+local CR_PARRY = CR_PARRY
+local CR_PARRY_TOOLTIP = CR_PARRY_TOOLTIP
+local DAMAGE_PER_SECOND = DAMAGE_PER_SECOND
+local DEFENSE = DEFENSE
+local DODGE_CHANCE = DODGE_CHANCE
+local FONT_COLOR_CODE_CLOSE = FONT_COLOR_CODE_CLOSE
+local GREEN_FONT_COLOR = GREEN_FONT_COLOR
+local GREEN_FONT_COLOR_CODE = GREEN_FONT_COLOR_CODE
+local HEALTH_PER_STAMINA = HEALTH_PER_STAMINA
+local HIGHLIGHT_FONT_COLOR_CODE = HIGHLIGHT_FONT_COLOR_CODE
+local INVSLOT_BODY = INVSLOT_BODY
+local INVSLOT_MAINHAND = INVSLOT_MAINHAND
+local MANA_PER_INTELLECT = MANA_PER_INTELLECT
+local MANA_REGEN_FROM_SPIRIT = MANA_REGEN_FROM_SPIRIT
+local MAX_EQUIPMENT_SETS_PER_PLAYER = MAX_EQUIPMENT_SETS_PER_PLAYER
+local MELEE_CRIT_CHANCE = MELEE_CRIT_CHANCE
+local NONE = NONE
+local NORMAL_FONT_COLOR = NORMAL_FONT_COLOR
+local PAPERDOLLFRAME_TOOLTIP_FORMAT = PAPERDOLLFRAME_TOOLTIP_FORMAT
+local PARRY_CHANCE = PARRY_CHANCE
+local PET_BONUS_TOOLTIP_INTELLECT = PET_BONUS_TOOLTIP_INTELLECT
+local PET_BONUS_TOOLTIP_RESISTANCE = PET_BONUS_TOOLTIP_RESISTANCE
+local PET_BONUS_TOOLTIP_STAMINA = PET_BONUS_TOOLTIP_STAMINA
+local RAID_CLASS_COLORS = RAID_CLASS_COLORS
+local RED_FONT_COLOR_CODE = RED_FONT_COLOR_CODE
+local RESILIENCE_CRIT_CHANCE_TO_CONSTANT_DAMAGE_REDUCTION_MULTIPLIER = RESILIENCE_CRIT_CHANCE_TO_CONSTANT_DAMAGE_REDUCTION_MULTIPLIER
+local RESILIENCE_CRIT_CHANCE_TO_DAMAGE_REDUCTION_MULTIPLIER = RESILIENCE_CRIT_CHANCE_TO_DAMAGE_REDUCTION_MULTIPLIER
+local RESILIENCE_TOOLTIP = RESILIENCE_TOOLTIP
+local RESISTANCE_EXCELLENT = RESISTANCE_EXCELLENT
+local RESISTANCE_FAIR = RESISTANCE_FAIR
+local RESISTANCE_GOOD = RESISTANCE_GOOD
+local RESISTANCE_NONE = RESISTANCE_NONE
+local RESISTANCE_POOR = RESISTANCE_POOR
+local RESISTANCE_TOOLTIP_SUBTEXT = RESISTANCE_TOOLTIP_SUBTEXT
+local RESISTANCE_VERYGOOD = RESISTANCE_VERYGOOD
+local STAT_ATTACK_POWER = STAT_ATTACK_POWER
+local STAT_BLOCK = STAT_BLOCK
+local STAT_BLOCK_TOOLTIP = STAT_BLOCK_TOOLTIP
+local STAT_DODGE = STAT_DODGE
+local STAT_FORMAT = STAT_FORMAT
+local STAT_PARRY = STAT_PARRY
+local STAT_RESILIENCE = STAT_RESILIENCE
+
+-- GLOBALS: CharacterAmmoSlot, CharacterAttributesFrame, CharacterDamageFrame_OnEnter, CharacterFrame, CharacterFrameCloseButton, CharacterFrameExpandButton, CharacterFrameTab2
+-- GLOBALS: CharacterLevelText, CharacterMicroButton, CharacterModelFrame, CharacterNameFrame, CharacterNameText, CharacterResistanceFrame, CharacterSpellBonusDamage_OnEnter
+-- GLOBALS: CharacterStatsPane, CharacterStatsPaneScrollBar, CharacterStatsPaneScrollBarScrollDownButton, CharacterStatsPaneScrollBarScrollUpButton, CharacterStatsPaneScrollChild
+-- GLOBALS: CompanionModelFrame, CompanionModelFrameRotateLeftButton, CompanionNextPageButton, CompanionPageNumber, CompanionPrevPageButton, CompanionSelectedName
+-- GLOBALS: CompanionSummonButton, ComputePetBonus, CreateAnimationGroup, EquipmentManager_EquipSet, GS_Data, GameTooltip, GearManagerDialogPopup, GearManagerToggleButton
+-- GLOBALS: GearScore2, GearScore_GetQuality, GearScore_GetScore, HybridScrollFrame_CreateButtons, HybridScrollFrame_GetOffset, HybridScrollFrame_OnLoad, HybridScrollFrame_Update
+-- GLOBALS: InspectFrame, InspectModelFrame, PaperDollEquipmentManagerPane, PaperDollEquipmentManagerPaneEquipSet, PaperDollEquipmentManagerPaneSaveSet, PaperDollFormatStat
+-- GLOBALS: PaperDollFrame, PaperDollSidebarTab1, PaperDollSidebarTabs, PaperDollStatTooltip, PaperDollTitlesPane, PersonalGearScore, PetAttributesFrame, PetExpBar_Update
+-- GLOBALS: PetLevelText, PetModelFrame, PetModelFrameRotateLeftButton, PetNameText, PetPaperDollCloseButton, PetPaperDollCompanionPane, PetPaperDollFrame, PetPaperDollFrameExpBar
+-- GLOBALS: PetPaperDollFramePetFrame, PetPaperDollFrame_Update, PetPaperDollFrame_UpdateCompanionCooldowns, PetPaperDollFrame_UpdateTabs, PetResistanceFrame, PlayerTitleFrame
+-- GLOBALS: PlayerTitlePickerFrame, SetButtonPulse, SetCVar, StaticPopup_Hide, UIFrameFadeIn, UIFrameFadeOut, hooksecurefunc, table
+-- GLOBALS: EQUIPSET_EQUIP, SAVE
+
+local CHARACTERFRAME_EXPANDED_WIDTH = 197
+
+local STATCATEGORY_MOVING_INDENT = 4
+local MOVING_STAT_CATEGORY
+
+local PAPERDOLL_SIDEBARS = {
+ {
+ name = L["Character Stats"],
+ frame = "CharacterStatsPane",
+ icon = nil,
+ texCoords = {0.109375, 0.890625, 0.09375, 0.90625}
+ },
+ {
+ name = L["Titles"],
+ frame = "PaperDollTitlesPane",
+ icon = "Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\PaperDollSidebarTabs",
+ texCoords = {0.01562500, 0.53125000, 0.32421875, 0.46093750}
+ },
+ {
+ name = L["Equipment Manager"],
+ frame = "PaperDollEquipmentManagerPane",
+ icon = "Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\PaperDollSidebarTabs",
+ texCoords = {0.01562500, 0.53125000, 0.46875000, 0.60546875}
+ },
+ {
+ name = "Mystic Enchants",
+ frame = "PaperDollMysticEnchantPane",
+ icon = "Interface\\Icons\\inv_custom_ReforgeToken",
+ texCoords = {0.1, 0.9, 0.1, 0.9}
+ }
+}
+
+local PAPERDOLL_STATINFO = {
+ ["ITEM_LEVEL"] = {
+ updateFunc = function(statFrame, unit) module:ItemLevel(statFrame, unit) end
+ },
+
+ ["PRIMARY_STAT"] = {
+ updateFunc = function(statFrame, unit) module:PrimaryStat(statFrame, unit) end
+ },
+
+ ["FEL_COMM"] = {
+ updateFunc = function(statFrame, unit) module:FelComm(statFrame, unit) end
+ },
+
+ ["STRENGTH"] = {
+ updateFunc = function(statFrame, unit) module:SetStat(statFrame, unit, 1) end
+ },
+ ["AGILITY"] = {
+ updateFunc = function(statFrame, unit) module:SetStat(statFrame, unit, 2) end
+ },
+ ["STAMINA"] = {
+ updateFunc = function(statFrame, unit) module:SetStat(statFrame, unit, 3) end
+ },
+ ["INTELLECT"] = {
+ updateFunc = function(statFrame, unit) module:SetStat(statFrame, unit, 4) end
+ },
+ ["SPIRIT"] = {
+ updateFunc = function(statFrame, unit) module:SetStat(statFrame, unit, 5) end
+ },
+
+ ["MELEE_DAMAGE"] = {
+ updateFunc = function(statFrame, unit) PaperDollFrame_SetDamage(statFrame, unit) end,
+ updateFunc2 = function(statFrame) CharacterDamageFrame_OnEnter(statFrame) end
+ },
+ ["MELEE_DPS"] = {
+ updateFunc = function(statFrame, unit) module:SetMeleeDPS(statFrame, unit) end
+ },
+ ["MELEE_AP"] = {
+ updateFunc = function(statFrame, unit) PaperDollFrame_SetAttackPower(statFrame, unit) end
+ },
+ ["MELEE_ATTACKSPEED"] = {
+ updateFunc = function(statFrame, unit) PaperDollFrame_SetAttackSpeed(statFrame, unit) end
+ },
+ ["HITCHANCE"] = {
+ updateFunc = function(statFrame, unit) if unit ~= "player" then statFrame:Hide() return end PaperDollFrame_SetRating(statFrame, CR_HIT_MELEE) end
+ },
+ ["CRITCHANCE"] = {
+ updateFunc = function(statFrame, unit) module:SetMeleeCritChance(statFrame, unit) end
+ },
+ ["EXPERTISE"] = {
+ updateFunc = function(statFrame, unit) if unit ~= "player" then statFrame:Hide() return end PaperDollFrame_SetExpertise(statFrame, unit) end
+ },
+
+ ["RANGED_COMBAT1"] = {
+ updateFunc = function(statFrame, unit) PaperDollFrame_SetRangedDamage(statFrame, unit) end,
+ updateFunc2 = function(statFrame) CharacterRangedDamageFrame_OnEnter(statFrame) end
+ },
+ ["RANGED_COMBAT2"] = {
+ updateFunc = function(statFrame, unit) PaperDollFrame_SetRangedAttackSpeed(statFrame, unit) end
+ },
+ ["RANGED_COMBAT3"] = {
+ updateFunc = function(statFrame, unit) PaperDollFrame_SetRangedAttackPower(statFrame, unit) end
+ },
+ ["RANGED_COMBAT4"] = {
+ updateFunc = function(statFrame) PaperDollFrame_SetRating(statFrame, CR_HIT_RANGED) end
+ },
+ ["RANGED_COMBAT5"] = {
+ updateFunc = function(statFrame, unit) PaperDollFrame_SetRangedCritChance(statFrame, unit) end
+ },
+
+ ["SPELL_COMBAT1"] = {
+ updateFunc = function(statFrame, unit) PaperDollFrame_SetSpellBonusDamage(statFrame, unit) end,
+ updateFunc2 = function(statFrame) CharacterSpellBonusDamage_OnEnter(statFrame) end
+ },
+ ["SPELL_COMBAT2"] = {
+ updateFunc = function(statFrame, unit) if unit ~= "player" then statFrame:Hide() return end PaperDollFrame_SetSpellBonusHealing(statFrame, unit) end
+ },
+ ["SPELL_COMBAT3"] = {
+ updateFunc = function(statFrame, unit) if unit ~= "player" then statFrame:Hide() return end PaperDollFrame_SetRating(statFrame, CR_HIT_SPELL) end
+ },
+ ["SPELL_COMBAT4"] = {
+ updateFunc = function(statFrame, unit) PaperDollFrame_SetSpellCritChance(statFrame, unit) end,
+ updateFunc2 = function(statFrame) CharacterSpellCritChance_OnEnter(statFrame) end
+ },
+ ["SPELL_COMBAT5"] = {
+ updateFunc = function(statFrame, unit) if unit ~= "player" then statFrame:Hide() return end PaperDollFrame_SetSpellHaste(statFrame, unit) end
+ },
+ ["SPELL_COMBAT6"] = {
+ updateFunc = function(statFrame, unit) if unit ~= "player" then statFrame:Hide() return end PaperDollFrame_SetManaRegen(statFrame, unit) end
+ },
+
+ ["DEFENSES1"] = {
+ updateFunc = function(statFrame, unit) PaperDollFrame_SetArmor(statFrame, unit) end
+ },
+ ["DEFENSES2"] = {
+ updateFunc = function(statFrame, unit) if unit ~= "player" then statFrame:Hide() return end PaperDollFrame_SetDefense(statFrame, unit) end
+ },
+ ["DEFENSES3"] = {
+ updateFunc = function(statFrame, unit) module:SetDodge(statFrame, unit) end
+ },
+ ["DEFENSES4"] = {
+ updateFunc = function(statFrame, unit) module:SetParry(statFrame, unit) end
+ },
+ ["DEFENSES5"] = {
+ updateFunc = function(statFrame, unit) module:SetBlock(statFrame, unit) end
+ },
+ ["DEFENSES6"] = {
+ updateFunc = function(statFrame, unit) module:SetResilience(statFrame, unit) end
+ },
+
+ ["ARCANE"] = {
+ updateFunc = function(statFrame, unit) module:SetResistance(statFrame, unit, 6) end
+ },
+ ["FIRE"] = {
+ updateFunc = function(statFrame, unit) module:SetResistance(statFrame, unit, 2) end
+ },
+ ["FROST"] = {
+ updateFunc = function(statFrame, unit) module:SetResistance(statFrame, unit, 4) end
+ },
+ ["NATURE"] = {
+ updateFunc = function(statFrame, unit) module:SetResistance(statFrame, unit, 3) end
+ },
+ ["SHADOW"] = {
+ updateFunc = function(statFrame, unit) module:SetResistance(statFrame, unit, 5) end
+ }
+}
+
+local PAPERDOLL_STATCATEGORIES = {
+ ["ITEM_LEVEL"] = {
+ id = 1,
+ stats = {
+ "ITEM_LEVEL"
+ }
+ },
+ ["PRIMARY_STAT"] = {
+ id = 2,
+ stats = {
+ "PRIMARY_STAT"
+ }
+ },
+ ["FEL_COMM"] = {
+ id = 3,
+ stats = {
+ "FEL_COMM"
+ }
+ },
+ ["BASE_STATS"] = {
+ id = 4,
+ stats = {
+ "STRENGTH",
+ "AGILITY",
+ "STAMINA",
+ "INTELLECT",
+ "SPIRIT"
+ }
+ },
+ ["MELEE_COMBAT"] = {
+ id = 5,
+ stats = {
+ "MELEE_DAMAGE",
+ "MELEE_DPS",
+ "MELEE_AP",
+ "MELEE_ATTACKSPEED",
+ "HITCHANCE",
+ "CRITCHANCE",
+ "EXPERTISE"
+ }
+ },
+ ["RANGED_COMBAT"] = {
+ id = 6,
+ stats = {
+ "RANGED_COMBAT1",
+ "RANGED_COMBAT2",
+ "RANGED_COMBAT3",
+ "RANGED_COMBAT4",
+ "RANGED_COMBAT5"
+ }
+ },
+ ["SPELL_COMBAT"] = {
+ id = 7,
+ stats = {
+ "SPELL_COMBAT1",
+ "SPELL_COMBAT2",
+ "SPELL_COMBAT3",
+ "SPELL_COMBAT4",
+ "SPELL_COMBAT5",
+ "SPELL_COMBAT6"
+ }
+ },
+ ["DEFENSES"] = {
+ id = 8,
+ stats = {
+ "DEFENSES1",
+ "DEFENSES2",
+ "DEFENSES3",
+ "DEFENSES4",
+ "DEFENSES5",
+ "DEFENSES6"
+ }
+ },
+ ["RESISTANCE"] = {
+ id = 9,
+ stats = {
+ "ARCANE",
+ "FIRE",
+ "FROST",
+ "NATURE",
+ "SHADOW"
+ }
+ }
+}
+
+local PAPERDOLL_STATCATEGORY_DEFAULTORDER = {
+ "ITEM_LEVEL",
+ "PRIMARY_STAT",
+ "FEL_COMM",
+ "BASE_STATS",
+ "MELEE_COMBAT",
+ "RANGED_COMBAT",
+ "SPELL_COMBAT",
+ "DEFENSES",
+ "RESISTANCE"
+}
+
+local PETPAPERDOLL_STATCATEGORY_DEFAULTORDER = {
+ "BASE_STATS",
+ "MELEE_COMBAT",
+-- "RANGED_COMBAT",
+ "SPELL_COMBAT",
+ "DEFENSES",
+ "RESISTANCE"
+}
+
+local _PLAYER_LEVEL, _PLAYER_LEVEL_NO_SPEC
+
+do
+ local locale = GetLocale()
+
+ if locale == "deDE" then
+ _PLAYER_LEVEL = "Stufe %s, |c%s%s-%s|r"
+ _PLAYER_LEVEL_NO_SPEC = "Stufe %s, |c%s%s|r"
+ elseif locale == "esES" or locale == "esMX" then
+ _PLAYER_LEVEL = "|c%2$s%4$s %3$s|r de nivel %1$s"
+ _PLAYER_LEVEL_NO_SPEC = "|c%2$s%3$s|r de nivel %1$s"
+ elseif locale == "frFR" then
+ _PLAYER_LEVEL = "|c%2$s%4$s %3$s|r de niveau %1$s"
+ _PLAYER_LEVEL_NO_SPEC = "|c%2$s%3$s|r de niveau %1$s"
+ elseif locale == "koKR" then
+ _PLAYER_LEVEL = "%s 레벨 |c%s%s %s|r"
+ _PLAYER_LEVEL_NO_SPEC = "%s 레벨 |c%s%s|r"
+ elseif locale == "ruRU" then
+ _PLAYER_LEVEL = "|c%2$s%4$s (%3$s)|r %1$s-го уровня"
+ _PLAYER_LEVEL_NO_SPEC = "|c%2$s%3$s|r %1$s-го уровня"
+ elseif locale == "zhCN" then
+ _PLAYER_LEVEL = "等级%s |c%s%s %s|r"
+ _PLAYER_LEVEL_NO_SPEC = "等级%s |c%s%s|r"
+ elseif locale == "zhTW" then
+ _PLAYER_LEVEL = "等級%s|c%s%s%s|r"
+ _PLAYER_LEVEL_NO_SPEC = "等級%s|c%s%s|r"
+ else
+ _PLAYER_LEVEL = "Level %s |c%s%s %s|r"
+ _PLAYER_LEVEL_NO_SPEC = "Level %s |c%s%s|r"
+ end
+end
+
+function module:PaperDollFrame_SetLevel()
+ local specName = NONE
+ local classColor = RAID_CLASS_COLORS[E.myclass]
+ local classColorString = format("FF%02x%02x%02x", classColor.r*255, classColor.g*255, classColor.b*255)
+
+ if specName == NONE then
+ CharacterLevelText:SetFormattedText(_PLAYER_LEVEL_NO_SPEC, E.mylevel, classColorString, E.myLocalizedClass)
+ else
+ CharacterLevelText:SetFormattedText(_PLAYER_LEVEL, E.mylevel, classColorString, specName, E.myLocalizedClass)
+ end
+
+ if CharacterLevelText:GetWidth() > 205 then
+ if PaperDollSidebarTab1:IsVisible() then
+ CharacterLevelText:Point("TOP", CharacterNameText, "BOTTOM", -10, -6)
+ else
+ CharacterLevelText:Point("TOP", CharacterNameText, "BOTTOM", 10, -6)
+ end
+ else
+ CharacterLevelText:Point("TOP", CharacterNameText, "BOTTOM", 0, -6)
+ end
+end
+
+function module:PaperDollSidebarTab(button)
+ button:Size(33, 35)
+ button:SetTemplate("Default")
+
+ button.Icon = button:CreateTexture(nil, "ARTWORK")
+ button.Icon:SetInside()
+ button.Icon:SetTexture(PAPERDOLL_SIDEBARS[button:GetID()].icon)
+ local tcoords = PAPERDOLL_SIDEBARS[button:GetID()].texCoords
+ button.Icon:SetTexCoord(tcoords[1], tcoords[2], tcoords[3], tcoords[4])
+
+ button.Hider = button:CreateTexture(nil, "OVERLAY")
+ button.Hider:SetTexture(0, 0, 0, 0.8)
+ button.Hider:SetInside()
+
+ button.Highlight = button:CreateTexture(nil, "HIGHLIGHT")
+ button.Highlight:SetTexture(1, 1, 1, 0.3)
+ button.Highlight:SetInside()
+
+ button:SetScript("OnClick", function(self)
+ module:PaperDollFrame_SetSidebar(self, self:GetID())
+ PlaySound("igMainMenuOption")
+ end)
+
+ button:SetScript("OnEnter", function(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
+ GameTooltip:SetText(PAPERDOLL_SIDEBARS[self:GetID()].name, 1, 1, 1)
+ end)
+
+ button:SetScript("OnLeave", function(self)
+ GameTooltip:Hide()
+ end)
+end
+
+function module:CharacterFrame_Collapse(sizeOnly)
+ if self.skinEnabled then
+ CharacterFrame.backdrop:Width(341)
+
+ S:SetBackdropHitRect(PaperDollFrame, CharacterFrame.backdrop)
+ S:SetBackdropHitRect(PetPaperDollFrame, CharacterFrame.backdrop)
+ else
+ CharacterFrame:Width(384)
+
+ S:SetBackdropHitRect(PaperDollFrame)
+ S:SetBackdropHitRect(PetPaperDollFrame)
+ end
+
+ S:SetUIPanelWindowInfo(CharacterFrame, "width")
+
+ if sizeOnly then return end
+
+ CharacterFrame.Expanded = false
+
+ S:SetNextPrevButtonDirection(CharacterFrameExpandButton, "right")
+
+ for i = 1, #PAPERDOLL_SIDEBARS do
+ _G[PAPERDOLL_SIDEBARS[i].frame]:Hide()
+ end
+
+ PaperDollSidebarTabs:Hide()
+end
+
+function module:CharacterFrame_Expand(sizeOnly)
+ if self.skinEnabled then
+ CharacterFrame.backdrop:Width(341 + CHARACTERFRAME_EXPANDED_WIDTH)
+
+ S:SetBackdropHitRect(PaperDollFrame, CharacterFrame.backdrop)
+ S:SetBackdropHitRect(PetPaperDollFrame, CharacterFrame.backdrop)
+ else
+ CharacterFrame:Width(352 + CHARACTERFRAME_EXPANDED_WIDTH)
+
+ S:SetBackdropHitRect(PaperDollFrame)
+ S:SetBackdropHitRect(PetPaperDollFrame)
+ end
+
+ S:SetUIPanelWindowInfo(CharacterFrame, "width")
+
+ if sizeOnly then return end
+
+ CharacterFrame.Expanded = true
+
+ S:SetNextPrevButtonDirection(CharacterFrameExpandButton, "left")
+
+ if PaperDollFrame:IsShown() and PaperDollFrame.currentSideBar then
+ CharacterStatsPane:Hide()
+ PaperDollFrame.currentSideBar:Show()
+ else
+ CharacterStatsPane:Show()
+ end
+
+ self:PaperDollFrame_UpdateSidebarTabs()
+ PaperDollSidebarTabs:Show()
+end
+
+local StatCategoryFrames = {}
+
+local titanGrip
+local qualityColors = {}
+
+do
+ for i = 0, 7 do
+ qualityColors[i] = {GetItemQualityColor(i)}
+ end
+
+ if E.myclass == "WARRIOR" then
+ local GetTalentInfo = GetTalentInfo
+
+ local titanGripCheck = CreateFrame("Frame")
+ titanGripCheck:RegisterEvent("PLAYER_ENTERING_WORLD")
+ titanGripCheck:RegisterEvent("SPELL_UPDATE_USABLE")
+ titanGripCheck:RegisterEvent("CHARACTER_POINTS_CHANGED")
+ titanGripCheck:SetScript("OnEvent", function(self, event, ...)
+ titanGrip = CA_IsSpellKnown(46917)
+
+ if event == "PLAYER_ENTERING_WORLD" or event == "SPELL_UPDATE_USABLE" then
+ self:UnregisterEvent(event)
+ end
+ end)
+ end
+end
+
+--[[
+local function OnEvent(event, bagID, slotID)
+ if event == "ITEM_UNLOCKED" then
+ if not slotID then
+ -- equiped item removed
+ else
+ -- bag item removed
+ end
+ end
+end
+
+local slots = {
+ ["HeadSlot"] = "INVTYPE_HEAD",
+ ["NeckSlot"] = "INVTYPE_NECK",
+ ["ShoulderSlot"] = "INVTYPE_SHOULDER",
+ ["BackSlot"] = "INVTYPE_CLOAK",
+ ["ChestSlot"] = "INVTYPE_ROBE",
+ ["WristSlot"] = "INVTYPE_WRIST",
+ ["HandsSlot"] = "INVTYPE_HAND",
+ ["WaistSlot"] = "INVTYPE_WAIST",
+ ["LegsSlot"] = "INVTYPE_LEGS",
+ ["FeetSlot"] = "INVTYPE_FEET",
+ ["Finger0Slot"] = "INVTYPE_FINGER",
+ ["Finger1Slot"] = "INVTYPE_FINGER",
+ ["Trinket0Slot"] = "INVTYPE_TRINKET",
+ ["Trinket1Slot"] = "INVTYPE_TRINKET",
+ ["MainHandSlot"] = {"INVTYPE_WEAPONMAINHAND", "INVTYPE_2HWEAPON", "INVTYPE_WEAPON"},
+ ["SecondaryHandSlot"] = {"INVTYPE_WEAPONOFFHAND", "INVTYPE_SHIELD", "INVTYPE_HOLDABLE", "INVTYPE_WEAPON"},
+ ["RangedSlot"] = {"INVTYPE_RANGED", "INVTYPE_RANGEDRIGHT", "INVTYPE_THROWN", "INVTYPE_RELIC"}
+}
+
+local bagsTable = {}
+
+local function sortItemLevel(a, b)
+ return a > b
+end
+
+local function GetAverageItemLevel()
+ local _, itemLink, itemLevel, itemEquipLoc, slotID
+ local totalItemLevel, totalEquippedItemLevel = 0, 0
+ local items = 16
+
+ for bag = 0, 4 do
+ for slot = 1, GetContainerNumSlots(bag) do
+ itemLink = GetContainerItemLink(bag, slot)
+ if itemLink then
+ _, _, _, itemLevel, _, _, _, _, itemEquipLoc = GetItemInfo(itemLink)
+ if itemEquipLoc and itemEquipLoc ~= "" then
+ if itemEquipLoc == "INVTYPE_WEAPON" or (titanGrip and itemEquipLoc == "INVTYPE_2HWEAPON") then
+ if not bagsTable[itemEquipLoc] then
+ bagsTable[itemEquipLoc] = {itemLevel}
+ elseif #bagsTable[itemEquipLoc] == 1 then
+ bagsTable[itemEquipLoc][2] = itemLevel
+ sort(bagsTable[itemEquipLoc], sortItemLevel)
+ elseif itemLevel > bagsTable[itemEquipLoc][1] then
+ bagsTable[itemEquipLoc][2] = bagsTable[itemEquipLoc][1]
+ bagsTable[itemEquipLoc][1] = itemLevel
+ elseif itemLevel > bagsTable[itemEquipLoc][2] then
+ bagsTable[itemEquipLoc][2] = itemLevel
+ end
+ else
+ if not bagsTable[itemEquipLoc] then
+ bagsTable[itemEquipLoc] = itemLevel
+ elseif itemLevel > bagsTable[itemEquipLoc] then
+ bagsTable[itemEquipLoc] = itemLevel
+ end
+ end
+ end
+ end
+ end
+ end
+
+ local hasMainHandBag, maxBagItemLevel, countBagOffhand
+ local hasTwoHandBag = bagsTable["INVTYPE_2HWEAPON"]
+
+ for slotName, itemLoc in pairs(slots) do
+ slotID = GetInventorySlotInfo(slotName)
+ itemLink = GetInventoryItemLink("player", slotID)
+
+ if itemLink then
+ _, _, _, itemLevel, _, _, _, _, itemEquipLoc = GetItemInfo(itemLink)
+
+ if itemLevel and itemLevel > 0 then
+ if type(itemLoc) == "table" then
+ local maxLocItemLevel = 0
+ for _, bagItemLoc in ipairs(itemLoc) do
+ maxBagItemLevel = bagsTable[bagItemLoc]
+
+ if maxBagItemLevel and maxBagItemLevel > maxLocItemLevel then
+ maxLocItemLevel = maxBagItemLevel
+ end
+ end
+
+ maxBagItemLevel = maxLocItemLevel ~= 0 and maxLocItemLevel
+ else
+ maxBagItemLevel = bagsTable[itemEquipLoc]
+ end
+
+ if maxBagItemLevel and maxBagItemLevel > itemLevel then
+ totalItemLevel = totalItemLevel + maxBagItemLevel
+ else
+ totalItemLevel = totalItemLevel + itemLevel
+ end
+
+ totalEquippedItemLevel = totalEquippedItemLevel + itemLevel
+
+ if slotName == "MainHandSlot" and (itemEquipLoc ~= "INVTYPE_2HWEAPON" or titanGrip) then
+ items = 17
+ countBagOffhand = true
+ end
+ end
+ else
+ if type(itemLoc) == "table" then
+ local maxLocItemLevel = 0
+
+ if slotName == "SecondaryHandSlot" then
+ if titanGrip then
+ maxLocItemLevel = bagsTable["INVTYPE_2HWEAPON"]
+ end
+
+ if not titanGrip or maxLocItemLevel < bagsTable["INVTYPE_WEAPON"] then
+ maxLocItemLevel = bagsTable["INVTYPE_WEAPON"]
+ end
+ end
+
+ for _, bagItemLoc in ipairs(itemLoc) do
+ maxBagItemLevel = bagsTable[bagItemLoc]
+
+ if maxBagItemLevel and maxBagItemLevel > maxLocItemLevel then
+ maxLocItemLevel = maxBagItemLevel
+ end
+ end
+
+ maxBagItemLevel = maxLocItemLevel ~= 0 and maxLocItemLevel
+ else
+ maxBagItemLevel = bagsTable[itemLoc]
+ end
+
+ if maxBagItemLevel and (slotName ~= "SecondaryHandSlot" or countBagOffhand) then
+ totalItemLevel = totalItemLevel + maxBagItemLevel
+ end
+
+ if slotName == "MainHandSlot" then
+ if hasTwoHandBag then
+ if maxBagItemLevel then
+ if hasTwoHandBag > maxBagItemLevel then
+ hasMainHandBag = hasTwoHandBag
+ end
+ else
+ hasMainHandBag = hasTwoHandBag
+ end
+ end
+ end
+ end
+ end
+
+ wipe(bagsTable)
+
+ if hasMainHandBag then
+ totalItemLevel = totalItemLevel + hasMainHandBag
+ end
+
+ return (totalItemLevel / 17), (totalEquippedItemLevel / items)
+end
+
+local function GetItemLevelColor(unit)
+ if not unit then unit = "player" end
+
+ local i = 0
+ local sumR, sumG, sumB = 0, 0, 0
+ for slotName in pairs(slots) do
+ local slotID = GetInventorySlotInfo(slotName)
+ if GetInventoryItemTexture(unit, slotID) then
+ local itemLink = GetInventoryItemLink(unit, slotID)
+ if itemLink then
+ local quality = select(3, GetItemInfo(itemLink))
+ if quality then
+ i = i + 1
+ local r, g, b = GetItemQualityColor(quality)
+ sumR = sumR + r
+ sumG = sumG + g
+ sumB = sumB + b
+ end
+ end
+ end
+ end
+
+ if i > 0 then
+ return (sumR / i), (sumG / i), (sumB / i)
+ else
+ return 1, 1, 1
+ end
+end
+]]
+
+local function GetAverageItemLevel()
+ local items = 16
+ local ilvl = 0
+ local colorCount, sumR, sumG, sumB = 0, 0, 0, 0
+
+ for slotID = 1, 18 do
+ if slotID ~= INVSLOT_BODY then
+ local itemLink = GetInventoryItemLink("player", slotID)
+
+ if itemLink then
+ local _, _, quality, itemLevel, _, _, _, _, itemEquipLoc = GetItemInfo(itemLink)
+
+ if itemLevel then
+ ilvl = ilvl + itemLevel
+
+ colorCount = colorCount + 1
+ sumR = sumR + qualityColors[quality][1]
+ sumG = sumG + qualityColors[quality][2]
+ sumB = sumB + qualityColors[quality][3]
+
+ if slotID == INVSLOT_MAINHAND and (itemEquipLoc ~= "INVTYPE_2HWEAPON" or titanGrip) then
+ items = 17
+ end
+ end
+ end
+ end
+ end
+
+ if colorCount == 0 then
+ return ilvl / items, 1, 1, 1
+ else
+ return ilvl / items, (sumR / colorCount), (sumG / colorCount), (sumB / colorCount)
+ end
+end
+
+function module:SetLabelAndText(statFrame, label, text, isPercentage)
+ statFrame.Label:SetFormattedText(STAT_FORMAT, label)
+ if isPercentage then
+ statFrame.Value:SetFormattedText("%.2F%%", text)
+ else
+ statFrame.Value:SetText(text)
+ end
+end
+
+function module:ItemLevel(statFrame, unit)
+ if not self.Initialized then return end
+
+ if GearScore_GetScore then
+ if not self.gearScore or not GS_PlayerIsInCombat then
+ local gearScore = GearScore_GetScore(E.myname, "player")
+
+ if not gearScore then
+ if GS_Data and GS_Data[E.myrealm] then
+ gearScore = GS_Data[E.myrealm].Players[E.myname].GearScore
+ end
+ end
+
+ if gearScore then
+ local r, b, g = GearScore_GetQuality(gearScore)
+
+ self.gearScore = gearScore
+ self.gearScoreR = r
+ self.gearScoreG = g
+ self.gearScoreB = b
+
+ statFrame.Label:SetText(gearScore)
+ statFrame.Label:SetTextColor(r, g, b)
+
+ return
+ end
+ else
+ statFrame.Label:SetText(self.gearScore)
+ statFrame.Label:SetTextColor(self.gearScoreR, self.gearScoreG, self.gearScoreB)
+ return
+ end
+ end
+
+-- local avgItemLevel, avgItemLevelEquipped = GetAverageItemLevel()
+-- if avgItemLevelEquipped == avgItemLevel then
+-- statFrame.Label:SetFormattedText("%.2f", avgItemLevelEquipped)
+-- else
+-- statFrame.Label:SetFormattedText("%.2f / %.2f", avgItemLevelEquipped, avgItemLevel)
+-- end
+-- statFrame.Label:SetTextColor(GetItemLevelColor())
+
+ local avgItemLevel, r, g, b = GetAverageItemLevel()
+ statFrame.Label:SetFormattedText("%.1f", avgItemLevel)
+ statFrame.Label:SetTextColor(r, g, b)
+end
+
+local felCommText = AscensionUI.CharacterFrame.Extension.StatPanel.FelCommutation.Content.CostText
+function module:FelComm(statFrame, unit)
+ if not self.Initialized then return end
+
+ if felCommText:GetText() then
+ statFrame.Label:SetText(felCommText:GetText())
+ else
+ statFrame.Label:SetText(GetMoneyString(0))
+ end
+ statFrame.tooltip = "Fel Commutation"
+ statFrame.tooltip2 = "Maximum gold lost on death.\n|cffFF8888Only applies in High Risk|r"
+end
+
+function module:PrimaryStat(statFrame, unit)
+ if not self.Initialized then return end
+ local statID = C_PrimaryStat:GetActivePrimaryStat()
+
+ if not statID then
+ statFrame.Label:SetFormattedText("No Primary Stat")
+ statFrame.Label:SetTextColor(0.5, 0.5, 0.5)
+ statFrame.tooltip = nil
+ return
+ end
+
+ local _, _, _, name, tooltip = C_PrimaryStat:GetPrimaryStatInfo(statID)
+
+ statFrame.Label:SetFormattedText(name)
+ statFrame.Label:SetTextColor(STAT_COLORS[statID]:GetRGBA())
+ statFrame.tooltip = name
+ statFrame.tooltip2 = tooltip
+end
+
+function module:SetStat(statFrame, unit, statIndex)
+ local stat, effectiveStat, posBuff, negBuff = UnitStat(unit, statIndex)
+ local statName = _G["SPELL_STAT"..statIndex.."_NAME"]
+ statFrame.Label:SetFormattedText(STAT_FORMAT, statName)
+
+ local tooltipText = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, statName).." "
+ if posBuff == 0 and negBuff == 0 then
+ statFrame.Value:SetText(effectiveStat)
+ statFrame.tooltip = tooltipText..effectiveStat..FONT_COLOR_CODE_CLOSE
+ else
+ tooltipText = tooltipText..effectiveStat
+ if posBuff > 0 or negBuff < 0 then
+ tooltipText = tooltipText.." ("..(stat - posBuff - negBuff)..FONT_COLOR_CODE_CLOSE
+ end
+ if posBuff > 0 then
+ tooltipText = tooltipText..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..posBuff..FONT_COLOR_CODE_CLOSE
+ end
+ if negBuff < 0 then
+ tooltipText = tooltipText..RED_FONT_COLOR_CODE.." "..negBuff..FONT_COLOR_CODE_CLOSE
+ end
+ if posBuff > 0 or negBuff < 0 then
+ tooltipText = tooltipText..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE
+ end
+ statFrame.tooltip = tooltipText
+
+ if negBuff < 0 then
+ statFrame.Value:SetText(RED_FONT_COLOR_CODE..effectiveStat..FONT_COLOR_CODE_CLOSE)
+ else
+ statFrame.Value:SetText(GREEN_FONT_COLOR_CODE..effectiveStat..FONT_COLOR_CODE_CLOSE)
+ end
+ end
+ statFrame.tooltip2 = _G["DEFAULT_STAT"..statIndex.."_TOOLTIP"]
+
+ if unit == "player" then
+ local _, unitClass = UnitClass("player")
+ if statIndex == 1 then
+ local attackPower = GetAttackPowerForStat(statIndex, effectiveStat)
+ statFrame.tooltip2 = format(statFrame.tooltip2, attackPower)
+
+ if unitClass == "WARRIOR" or unitClass == "SHAMAN" or unitClass == "PALADIN" then
+ statFrame.tooltip2 = statFrame.tooltip2.."\n"..format(STAT_BLOCK_TOOLTIP, max(0, effectiveStat * BLOCK_PER_STRENGTH - 10))
+ end
+ elseif statIndex == 3 then
+ local baseStam = min(20, effectiveStat)
+ local moreStam = effectiveStat - baseStam
+ statFrame.tooltip2 = format(statFrame.tooltip2, (baseStam + (moreStam * HEALTH_PER_STAMINA)) * GetUnitMaxHealthModifier("player"))
+ local petStam = ComputePetBonus("PET_BONUS_STAM", effectiveStat)
+
+ if petStam > 0 then
+ statFrame.tooltip2 = statFrame.tooltip2.."\n"..format(PET_BONUS_TOOLTIP_STAMINA, petStam)
+ end
+ elseif statIndex == 2 then
+ local attackPower = GetAttackPowerForStat(statIndex, effectiveStat)
+
+ if attackPower > 0 then
+ statFrame.tooltip2 = format(STAT_ATTACK_POWER, attackPower)..format(statFrame.tooltip2, GetCritChanceFromAgility("player"), effectiveStat * ARMOR_PER_AGILITY)
+ else
+ statFrame.tooltip2 = format(statFrame.tooltip2, GetCritChanceFromAgility("player"), effectiveStat * ARMOR_PER_AGILITY)
+ end
+ elseif statIndex == 4 then
+ local baseInt = min(20, effectiveStat)
+ local moreInt = effectiveStat - baseInt
+
+ if UnitHasMana("player") then
+ statFrame.tooltip2 = format(statFrame.tooltip2, baseInt + moreInt * MANA_PER_INTELLECT, GetSpellCritChanceFromIntellect("player"))
+ else
+ statFrame.tooltip2 = nil
+ end
+
+ local petInt = ComputePetBonus("PET_BONUS_INT", effectiveStat)
+ if petInt > 0 then
+ if not statFrame.tooltip2 then
+ statFrame.tooltip2 = ""
+ end
+
+ statFrame.tooltip2 = statFrame.tooltip2.."\n"..format(PET_BONUS_TOOLTIP_INTELLECT, petInt)
+ end
+ elseif statIndex == 5 then
+ statFrame.tooltip2 = format(statFrame.tooltip2, GetUnitHealthRegenRateFromSpirit("player"))
+
+ if UnitHasMana("player") then
+ local regen = GetUnitManaRegenRateFromSpirit("player")
+ regen = floor(regen * 5.0)
+ statFrame.tooltip2 = statFrame.tooltip2.."\n"..format(MANA_REGEN_FROM_SPIRIT, regen)
+ end
+ end
+ elseif unit == "pet" then
+ if statIndex == 1 then
+ local attackPower = effectiveStat - 20
+ statFrame.tooltip2 = format(statFrame.tooltip2, attackPower)
+ elseif statIndex == 2 then
+ local newLineIndex = find(statFrame.tooltip2, "|n") + 1
+ statFrame.tooltip2 = sub(statFrame.tooltip2, 1, newLineIndex)
+ statFrame.tooltip2 = format(statFrame.tooltip2, GetCritChanceFromAgility("pet"))
+ elseif statIndex == 3 then
+ local expectedHealthGain = (((stat - posBuff - negBuff) - 20) * 10 + 20) * GetUnitHealthModifier("pet")
+ local realHealthGain = ((effectiveStat - 20) * 10 + 20) * GetUnitHealthModifier("pet")
+ local healthGain = (realHealthGain - expectedHealthGain) * GetUnitMaxHealthModifier("pet")
+ statFrame.tooltip2 = format(statFrame.tooltip2, healthGain)
+ elseif statIndex == 4 then
+ if UnitHasMana("pet") then
+ local manaGain = ((effectiveStat - 20) * 15 + 20) * GetUnitPowerModifier("pet")
+ statFrame.tooltip2 = format(statFrame.tooltip2, manaGain, GetSpellCritChanceFromIntellect("pet"))
+ else
+ local newLineIndex = find(statFrame.tooltip2, "|n") + 2
+ statFrame.tooltip2 = sub(statFrame.tooltip2, newLineIndex)
+ statFrame.tooltip2 = format(statFrame.tooltip2, GetSpellCritChanceFromIntellect("pet"))
+ end
+ elseif statIndex == 5 then
+ statFrame.tooltip2 = format(statFrame.tooltip2, GetUnitHealthRegenRateFromSpirit("pet"))
+ if UnitHasMana("pet") then
+ statFrame.tooltip2 = statFrame.tooltip2.."\n"..format(MANA_REGEN_FROM_SPIRIT, GetUnitManaRegenRateFromSpirit("pet"))
+ end
+ end
+ end
+ statFrame:Show()
+end
+
+function module:SetResistance(statFrame, unit, resistanceIndex)
+ local base, resistance, positive, negative = UnitResistance(unit, resistanceIndex)
+ local petBonus = ComputePetBonus("PET_BONUS_RES", resistance)
+ local resistanceNameShort = _G["SPELL_SCHOOL"..resistanceIndex.."_CAP"]
+ local resistanceName = _G["RESISTANCE"..resistanceIndex.."_NAME"]
+ local resistanceIconCode = "|TInterface\\PaperDollInfoFrame\\SpellSchoolIcon"..(resistanceIndex + 1)..":14:14:2:2:16:16:2:14:2:14|t"
+ statFrame.Label:SetText(resistanceIconCode.." "..format(STAT_FORMAT, resistanceNameShort))
+ local text = _G[statFrame:GetName().."StatText"]
+ PaperDollFormatStat(resistanceName, base, positive, negative, statFrame, text)
+ statFrame.tooltip = resistanceIconCode.." "..HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, resistanceName).." "..resistance..FONT_COLOR_CODE_CLOSE
+
+ if positive ~= 0 or negative ~= 0 then
+ statFrame.tooltip = statFrame.tooltip.." ( "..HIGHLIGHT_FONT_COLOR_CODE..base
+ if positive > 0 then
+ statFrame.tooltip = statFrame.tooltip..GREEN_FONT_COLOR_CODE.." +"..positive
+ end
+ if negative < 0 then
+ statFrame.tooltip = statFrame.tooltip.." "..RED_FONT_COLOR_CODE..negative
+ end
+ statFrame.tooltip = statFrame.tooltip..FONT_COLOR_CODE_CLOSE.." )"
+ end
+
+ local resistanceLevel
+ local unitLevel = UnitLevel(unit)
+ unitLevel = max(unitLevel, 20)
+
+ local magicResistanceNumber = resistance / unitLevel
+ if magicResistanceNumber > 5 then
+ resistanceLevel = RESISTANCE_EXCELLENT
+ elseif magicResistanceNumber > 3.75 then
+ resistanceLevel = RESISTANCE_VERYGOOD
+ elseif magicResistanceNumber > 2.5 then
+ resistanceLevel = RESISTANCE_GOOD
+ elseif magicResistanceNumber > 1.25 then
+ resistanceLevel = RESISTANCE_FAIR
+ elseif magicResistanceNumber > 0 then
+ resistanceLevel = RESISTANCE_POOR
+ else
+ resistanceLevel = RESISTANCE_NONE
+ end
+ statFrame.tooltip2 = format(RESISTANCE_TOOLTIP_SUBTEXT, _G["RESISTANCE_TYPE"..resistanceIndex], unitLevel, resistanceLevel)
+
+ if petBonus > 0 then
+ statFrame.tooltip2 = statFrame.tooltip2.."\n"..format(PET_BONUS_TOOLTIP_RESISTANCE, petBonus)
+ end
+end
+
+function module:SetDodge(statFrame, unit)
+ if unit ~= "player" then
+ statFrame:Hide()
+ return
+ end
+
+ local chance = GetDodgeChance()
+ module:SetLabelAndText(statFrame, STAT_DODGE, chance, 1)
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, DODGE_CHANCE).." "..format("%.02f", chance).."%"..FONT_COLOR_CODE_CLOSE
+ statFrame.tooltip2 = format(CR_DODGE_TOOLTIP, GetCombatRating(CR_DODGE), GetCombatRatingBonus(CR_DODGE))
+ statFrame:Show()
+end
+
+function module:SetBlock(statFrame, unit)
+ if unit ~= "player" then
+ statFrame:Hide()
+ return
+ end
+
+ local chance = GetBlockChance()
+ module:SetLabelAndText(statFrame, STAT_BLOCK, chance, 1)
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, BLOCK_CHANCE).." "..format("%.02f", chance).."%"..FONT_COLOR_CODE_CLOSE
+ statFrame.tooltip2 = format(CR_BLOCK_TOOLTIP, GetCombatRating(CR_BLOCK), GetCombatRatingBonus(CR_BLOCK), GetShieldBlock())
+ statFrame:Show()
+end
+
+function module:SetParry(statFrame, unit)
+ if unit ~= "player" then
+ statFrame:Hide()
+ return
+ end
+
+ local chance = GetParryChance()
+ module:SetLabelAndText(statFrame, STAT_PARRY, chance, 1)
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, PARRY_CHANCE).." "..format("%.02f", chance).."%"..FONT_COLOR_CODE_CLOSE
+ statFrame.tooltip2 = format(CR_PARRY_TOOLTIP, GetCombatRating(CR_PARRY), GetCombatRatingBonus(CR_PARRY))
+ statFrame:Show()
+end
+
+function module:SetResilience(statFrame, unit)
+ if unit ~= "player" then
+ statFrame:Hide()
+ return
+ end
+
+ local melee = GetCombatRating(CR_CRIT_TAKEN_MELEE)
+ local ranged = GetCombatRating(CR_CRIT_TAKEN_RANGED)
+ local spell = GetCombatRating(CR_CRIT_TAKEN_SPELL)
+
+ local minResilience = min(melee, ranged)
+ minResilience = min(minResilience, spell)
+
+ local lowestRating
+ if melee == minResilience then
+ lowestRating = CR_CRIT_TAKEN_MELEE
+ elseif ranged == minResilience then
+ lowestRating = CR_CRIT_TAKEN_RANGED
+ else
+ lowestRating = CR_CRIT_TAKEN_SPELL
+ end
+
+ local maxRatingBonus = GetMaxCombatRatingBonus(lowestRating)
+ local lowestRatingBonus = GetCombatRatingBonus(lowestRating)
+
+ module:SetLabelAndText(statFrame, STAT_RESILIENCE, minResilience)
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_RESILIENCE).." "..minResilience..FONT_COLOR_CODE_CLOSE
+ statFrame.tooltip2 = format(RESILIENCE_TOOLTIP, lowestRatingBonus, min(lowestRatingBonus * RESILIENCE_CRIT_CHANCE_TO_DAMAGE_REDUCTION_MULTIPLIER, maxRatingBonus), lowestRatingBonus * RESILIENCE_CRIT_CHANCE_TO_CONSTANT_DAMAGE_REDUCTION_MULTIPLIER)
+ statFrame:Show()
+end
+
+function module:SetMeleeDPS(statFrame, unit)
+ statFrame.Label:SetFormattedText(STAT_FORMAT, L["Damage Per Second"])
+ local speed, offhandSpeed = UnitAttackSpeed(unit)
+ local minDamage, maxDamage, minOffHandDamage, maxOffHandDamage, physicalBonusPos, physicalBonusNeg, percent = UnitDamage(unit)
+
+ minDamage = (minDamage / percent) - physicalBonusPos - physicalBonusNeg
+ maxDamage = (maxDamage / percent) - physicalBonusPos - physicalBonusNeg
+
+ local baseDamage = (minDamage + maxDamage) * 0.5
+ local fullDamage = (baseDamage + physicalBonusPos + physicalBonusNeg) * percent
+ local totalBonus = (fullDamage - baseDamage)
+ local damagePerSecond = (max(fullDamage, 1) / speed)
+
+ local colorPos = "|cff20ff20"
+ local colorNeg = "|cffff2020"
+ local text
+
+ if totalBonus < 0.1 and totalBonus > -0.1 then
+ totalBonus = 0.0
+ end
+
+ if totalBonus == 0 then
+ text = format("%.1F", damagePerSecond)
+ else
+ local color
+ if totalBonus > 0 then
+ color = colorPos
+ else
+ color = colorNeg
+ end
+ text = color..format("%.1F", damagePerSecond).."|r"
+ end
+
+ if offhandSpeed then
+ minOffHandDamage = (minOffHandDamage / percent) - physicalBonusPos - physicalBonusNeg
+ maxOffHandDamage = (maxOffHandDamage / percent) - physicalBonusPos - physicalBonusNeg
+
+ local offhandBaseDamage = (minOffHandDamage + maxOffHandDamage) * 0.5
+ local offhandFullDamage = (offhandBaseDamage + physicalBonusPos + physicalBonusNeg) * percent
+ local offhandDamagePerSecond = (max(offhandFullDamage, 1) / offhandSpeed)
+ local offhandTotalBonus = (offhandFullDamage - offhandBaseDamage)
+
+ if offhandTotalBonus < 0.1 and offhandTotalBonus > -0.1 then
+ offhandTotalBonus = 0.0
+ end
+ local separator = " / "
+ if damagePerSecond > 1000 and offhandDamagePerSecond > 1000 then
+ separator = "/"
+ end
+ if offhandTotalBonus == 0 then
+ text = text..separator..format("%.1F", offhandDamagePerSecond)
+ else
+ local color
+ if offhandTotalBonus > 0 then
+ color = colorPos
+ else
+ color = colorNeg
+ end
+ text = text..separator..color..format("%.1F", offhandDamagePerSecond).."|r"
+ end
+ end
+
+ statFrame.Value:SetText(text)
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..DAMAGE_PER_SECOND..FONT_COLOR_CODE_CLOSE
+ statFrame:Show()
+end
+
+function module:SetMeleeCritChance(statFrame, unit)
+ if unit ~= "player" then
+ statFrame:Hide()
+ return
+ end
+
+ statFrame.Label:SetFormattedText(STAT_FORMAT, MELEE_CRIT_CHANCE)
+ local critChance = GetCritChance()
+ statFrame.Value:SetFormattedText("%.2F%%", critChance)
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, MELEE_CRIT_CHANCE).." "..format("%.2F%%", critChance)..FONT_COLOR_CODE_CLOSE
+ statFrame.tooltip2 = format(CR_CRIT_MELEE_TOOLTIP, GetCombatRating(CR_CRIT_MELEE), GetCombatRatingBonus(CR_CRIT_MELEE))
+end
+
+local function PaperDollFrame_CollapseStatCategory(categoryFrame)
+ if not categoryFrame.collapsed then
+ categoryFrame.collapsed = true
+ --categoryFrame.Toolbar:SetTemplate("NoBackdrop")
+ categoryFrame.Toolbar:SetAlpha(0.4)
+ local index = 1
+ while categoryFrame.Stats[index] do
+ categoryFrame.Stats[index]:Hide()
+ index = index + 1
+ end
+ categoryFrame:Height(18)
+ module:PaperDollFrame_UpdateStatScrollChildHeight()
+ end
+end
+
+local function PaperDollFrame_ExpandStatCategory(categoryFrame)
+ if categoryFrame.collapsed then
+ categoryFrame.collapsed = false
+ --categoryFrame.Toolbar:SetTemplate("Default", true)
+ categoryFrame.Toolbar:SetAlpha(1)
+ module:PaperDollFrame_UpdateStatCategory(categoryFrame)
+ module:PaperDollFrame_UpdateStatScrollChildHeight()
+ end
+end
+
+local function PaperDollFrame_QueuedUpdate(self)
+ module:PaperDollFrame_UpdateStats()
+ self:SetScript("OnUpdate", nil)
+end
+
+local function PetPaperDollFrame_QueuedUpdate(self)
+ PetPaperDollFrame_Update()
+ self:SetScript("OnUpdate", nil)
+end
+
+function module:PaperDollFrame_UpdateStatCategory(categoryFrame)
+ if not categoryFrame.Category then categoryFrame:Hide() return end
+
+ local category = categoryFrame.Category
+ local categoryInfo = PAPERDOLL_STATCATEGORIES[category]
+
+ if category == "ITEM_LEVEL" then
+ if PersonalGearScore then
+ categoryFrame.NameText:SetText("Gear Score")
+ else
+ categoryFrame.NameText:SetText(L["Item Level"])
+ end
+ elseif category == "PRIMARY_STAT" then
+ categoryFrame.NameText:SetText("Primary Stat")
+ elseif category == "FEL_COMM" then
+ categoryFrame.NameText:SetText("Fel Comm Cost")
+ elseif category == "RESISTANCE" then
+ categoryFrame.NameText:SetText(L["Resistance"])
+ elseif category == "DEFENSES" then
+ categoryFrame.NameText:SetText(DEFENSE)
+ else
+ categoryFrame.NameText:SetText(_G["PLAYERSTAT_"..category])
+ end
+
+ if categoryFrame.collapsed then return end
+
+ local totalHeight = categoryFrame.NameText:GetHeight() + 10
+ local numVisible = 0
+ if categoryInfo then
+ local prevStatFrame = nil
+ for _, stat in next, categoryInfo.stats do
+ local statInfo = PAPERDOLL_STATINFO[stat]
+ if statInfo then
+ local statFrame = categoryFrame.Stats[numVisible + 1]
+ if not statFrame then
+ statFrame = CreateFrame("Frame", "$parentStat"..numVisible + 1, categoryFrame, "CharacterStatFrameTemplate")
+ if prevStatFrame then
+ statFrame:SetPoint("TOPLEFT", prevStatFrame, "BOTTOMLEFT")
+ statFrame:SetPoint("TOPRIGHT", prevStatFrame, "BOTTOMRIGHT")
+ end
+ categoryFrame.Stats[numVisible + 1] = statFrame
+ end
+ statFrame:Show()
+
+ if stat == "ITEM_LEVEL" then
+ statFrame:Height(30)
+ local label = statFrame.Label
+ label:Width(187)
+ label:ClearAllPoints()
+ label:SetPoint("CENTER")
+ label:FontTemplate(nil, 20, "NONE")
+ label:SetJustifyH("CENTER")
+ statFrame.Value:SetText("")
+
+ if statFrame.leftGrad then
+ statFrame.leftGrad:Show()
+ statFrame.rightGrad:Show()
+ end
+ elseif stat == "FEL_COMM" or stat == "PRIMARY_STAT" then
+ statFrame:Height(30)
+ local label = statFrame.Label
+ label:Width(187)
+ label:ClearAllPoints()
+ label:SetPoint("CENTER")
+ label:FontTemplate(nil, 16, "NONE")
+ label:SetJustifyH("CENTER")
+ statFrame.Value:SetText("")
+
+ if statFrame.leftGrad then
+ statFrame.leftGrad:Show()
+ statFrame.rightGrad:Show()
+ end
+ elseif statFrame:GetHeight() > 22 then
+ statFrame:Height(15)
+ local label = statFrame.Label
+ label:Width(122)
+ label:ClearAllPoints()
+ label:Point("LEFT", 7, 0)
+ label:FontTemplate(nil, nil, "NONE")
+ label:SetJustifyH("LEFT")
+ label:SetTextColor(1, 0.82, 0)
+
+ if statFrame.leftGrad then
+ statFrame.leftGrad:Hide()
+ statFrame.rightGrad:Hide()
+ end
+ end
+
+ if statInfo.updateFunc2 then
+ statFrame:SetScript("OnEnter", PaperDollStatTooltip)
+ statFrame:SetScript("OnEnter", statInfo.updateFunc2)
+ else
+ statFrame:SetScript("OnEnter", PaperDollStatTooltip)
+ end
+
+ statFrame.tooltip = nil
+ statFrame.tooltip2 = nil
+ statFrame.UpdateTooltip = nil
+ statFrame:SetScript("OnUpdate", nil)
+ statInfo.updateFunc(statFrame, CharacterStatsPane.unit)
+
+ if statFrame:IsShown() then
+ numVisible = numVisible + 1
+ totalHeight = totalHeight + statFrame:GetHeight()
+ prevStatFrame = statFrame
+
+ if GameTooltip:GetOwner() == statFrame then
+ statFrame:GetScript("OnEnter")(statFrame)
+ end
+ end
+ end
+ end
+ end
+
+ for index = 1, numVisible do
+ local isSpecial = categoryInfo == PAPERDOLL_STATCATEGORIES["ITEM_LEVEL"] or
+ categoryInfo == PAPERDOLL_STATCATEGORIES["PRIMARY_STAT"]
+ if index % 2 == 0 or isSpecial then
+ local statFrame = categoryFrame.Stats[index]
+ if not statFrame.leftGrad then
+ statFrame.leftGrad = statFrame:CreateTexture(nil, "BACKGROUND")
+ statFrame.leftGrad:Size(80, statFrame:GetHeight())
+ statFrame.leftGrad:SetPoint("LEFT", statFrame, "CENTER")
+ statFrame.leftGrad:SetTexture(E.media.blankTex)
+ statFrame.leftGrad:SetGradientAlpha("Horizontal", 0.8,0.8,0.8,0.35, 0.8,0.8,0.8,0)
+
+ statFrame.rightGrad = statFrame:CreateTexture(nil, "BACKGROUND")
+ statFrame.rightGrad:Size(80, statFrame:GetHeight())
+ statFrame.rightGrad:SetPoint("RIGHT", statFrame, "CENTER")
+ statFrame.rightGrad:SetTexture(E.media.blankTex)
+ statFrame.rightGrad:SetGradientAlpha("Horizontal", 0.8,0.8,0.8,0, 0.8,0.8,0.8,0.35)
+ end
+ end
+ end
+
+ local index = numVisible + 1
+ while categoryFrame.Stats[index] do
+ categoryFrame.Stats[index]:Hide()
+ index = index + 1
+ end
+
+ categoryFrame:Height(totalHeight)
+end
+
+function module:PaperDollFrame_UpdateStats()
+ local index = 1
+ while CharacterStatsPane.Categories[index] do
+ self:PaperDollFrame_UpdateStatCategory(CharacterStatsPane.Categories[index])
+ index = index + 1
+ end
+ self:PaperDollFrame_UpdateStatScrollChildHeight()
+end
+
+function module:PaperDollFrame_UpdateStatScrollChildHeight()
+ local index = 1
+ local totalHeight = 0
+ while CharacterStatsPane.Categories[index] do
+ if CharacterStatsPane.Categories[index]:IsShown() then
+ totalHeight = totalHeight + CharacterStatsPane.Categories[index]:GetHeight() + 4
+ end
+ index = index + 1
+ end
+ CharacterStatsPaneScrollChild:Height(totalHeight + 10 -(CharacterStatsPane.initialOffsetY or 0))
+end
+
+local function FindCategoryById(id)
+ for categoryName, category in pairs(PAPERDOLL_STATCATEGORIES) do
+ if category.id == id then
+ return categoryName
+ end
+ end
+end
+
+function module:PaperDoll_InitStatCategories(defaultOrder, orderData, collapsedData, unit)
+ local order = defaultOrder
+
+ local orderString = orderData
+ local savedOrder = {}
+ if orderString and orderString ~= "" then
+ for i in gmatch(orderString, "(%d+),?") do
+ i = tonumber(i)
+ if i then
+ local categoryName = FindCategoryById(i)
+ if categoryName then
+ tinsert(savedOrder, categoryName)
+ end
+ end
+ end
+
+ local valid = true
+ if #savedOrder == #defaultOrder then
+ for _, category1 in ipairs(defaultOrder) do
+ local found = false
+ for _, category2 in ipairs(savedOrder) do
+ if category1 == category2 then
+ found = true
+ break
+ end
+ end
+ if not found then
+ valid = false
+ break
+ end
+ end
+ else
+ valid = false
+ end
+
+ if valid then
+ order = savedOrder
+ else
+ orderData = ""
+ end
+ end
+
+ wipe(StatCategoryFrames)
+ for index = 1, #order do
+ local frame = CharacterStatsPane.Categories[index]
+ tinsert(StatCategoryFrames, frame)
+ frame.Category = order[index]
+ frame:Show()
+
+ local categoryInfo = PAPERDOLL_STATCATEGORIES[frame.Category]
+ if categoryInfo and collapsedData[frame.Category] then
+ PaperDollFrame_CollapseStatCategory(frame)
+ else
+ PaperDollFrame_ExpandStatCategory(frame)
+ end
+ end
+
+ local index = #order + 1
+ while CharacterStatsPane.Categories[index] do
+ CharacterStatsPane.Categories[index]:Hide()
+ CharacterStatsPane.Categories[index].Category = nil
+ index = index + 1
+ end
+
+ CharacterStatsPane.defaultOrder = defaultOrder
+ CharacterStatsPane.orderData = orderData
+ CharacterStatsPane.collapsedData = collapsedData
+ CharacterStatsPane.unit = unit
+
+ self:PaperDoll_UpdateCategoryPositions()
+ self:PaperDollFrame_UpdateStats()
+end
+
+local function PaperDoll_SaveStatCategoryOrder()
+ if CharacterStatsPane.defaultOrder and #CharacterStatsPane.defaultOrder == #StatCategoryFrames then
+ local same = true
+ for index = 1, #StatCategoryFrames do
+ if StatCategoryFrames[index].Category ~= CharacterStatsPane.defaultOrder[index] then
+ same = false
+ break
+ end
+ end
+ if same then
+ E.private.enhanced.character[CharacterStatsPane.unit].orderName = ""
+ return
+ end
+ end
+
+ local order = {}
+
+ for index = 1, #StatCategoryFrames do
+ order[index] = PAPERDOLL_STATCATEGORIES[StatCategoryFrames[index].Category].id
+ end
+
+ E.private.enhanced.character[CharacterStatsPane.unit].orderName = tconcat(order, ",")
+end
+
+function module:PaperDoll_UpdateCategoryPositions()
+ local prevFrame
+
+ for index = 1, #StatCategoryFrames do
+ local frame = StatCategoryFrames[index]
+
+ local xOffset = 0
+ if frame == MOVING_STAT_CATEGORY then
+ xOffset = STATCATEGORY_MOVING_INDENT
+ elseif prevFrame and prevFrame == MOVING_STAT_CATEGORY then
+ xOffset = -STATCATEGORY_MOVING_INDENT
+ end
+
+ frame:ClearAllPoints()
+ if prevFrame then
+ frame:Point("TOPLEFT", prevFrame, "BOTTOMLEFT", 0 + xOffset, -4)
+ else
+ frame:Point("TOPLEFT", 1 + xOffset, -4 + (CharacterStatsPane.initialOffsetY or 0))
+ end
+ prevFrame = frame
+ end
+end
+
+local function StatCategory_OnDragUpdate(self)
+ local _, cursorY = GetCursorPosition()
+ cursorY = cursorY * GetScreenHeightScale()
+
+ local myIndex, insertIndex, closestPos
+
+ for index = 1, #StatCategoryFrames + 1 do
+ if StatCategoryFrames[index] == self then
+ myIndex = index
+ end
+
+ local frameY
+ if index <= #StatCategoryFrames then
+ frameY = StatCategoryFrames[index]:GetTop()
+ else
+ frameY = StatCategoryFrames[#StatCategoryFrames]:GetBottom()
+ end
+ frameY = frameY - 8
+ if myIndex and index > myIndex then
+ frameY = frameY + self:GetHeight()
+ end
+ if not closestPos or abs(cursorY - frameY) < closestPos then
+ insertIndex = index
+ closestPos = abs(cursorY - frameY)
+ end
+ end
+
+ if insertIndex > myIndex then
+ insertIndex = insertIndex - 1
+ end
+
+ if myIndex ~= insertIndex then
+ tremove(StatCategoryFrames, myIndex)
+ tinsert(StatCategoryFrames, insertIndex, self)
+ module:PaperDoll_UpdateCategoryPositions()
+ end
+end
+
+local function PaperDollStatCategory_OnDragStart(self)
+ MOVING_STAT_CATEGORY = self
+ module:PaperDoll_UpdateCategoryPositions()
+ GameTooltip:Hide()
+ self:SetScript("OnUpdate", StatCategory_OnDragUpdate)
+
+ for i, frame in next, StatCategoryFrames do
+ if frame ~= self then
+ if E.db.enhanced.character.animations then
+ UIFrameFadeIn(frame, 0.2, 1, 0.6)
+ else
+ frame:SetAlpha(0.6)
+ end
+ end
+ end
+end
+
+local function PaperDollStatCategory_OnDragStop(self)
+ MOVING_STAT_CATEGORY = nil
+ module:PaperDoll_UpdateCategoryPositions()
+ self:SetScript("OnUpdate", nil)
+
+ for i, frame in next, StatCategoryFrames do
+ if frame ~= self then
+ if E.db.enhanced.character.animations then
+ UIFrameFadeOut(frame, 0.2, 0.6, 1)
+ else
+ frame:SetAlpha(1)
+ end
+ end
+ end
+ PaperDoll_SaveStatCategoryOrder()
+end
+
+function module:PaperDollFrame_UpdateSidebarTabs()
+ for i = 1, #PAPERDOLL_SIDEBARS do
+ local tab = _G["PaperDollSidebarTab"..i]
+ if _G[PAPERDOLL_SIDEBARS[i].frame]:IsShown() then
+ tab.Hider:Hide()
+ tab.Highlight:Hide()
+ else
+ tab.Hider:Show()
+ tab.Highlight:Show()
+ end
+ end
+end
+
+function module:PaperDollFrame_SetSidebar(button, index)
+ if not _G[PAPERDOLL_SIDEBARS[index].frame]:IsShown() then
+ for i = 1, #PAPERDOLL_SIDEBARS do
+ if _G[PAPERDOLL_SIDEBARS[i].frame]:IsShown() then
+ if E.db.enhanced.character.animations then
+ UIFrameFadeOut(_G[PAPERDOLL_SIDEBARS[i].frame], 0.2, 1, 0)
+
+ _G[PAPERDOLL_SIDEBARS[i].frame].fadeInfo.finishedFunc = function()
+ _G[PAPERDOLL_SIDEBARS[i].frame]:Hide()
+ end
+ else
+ _G[PAPERDOLL_SIDEBARS[i].frame]:Hide()
+ end
+
+ _G["PaperDollSidebarTab"..i].Hider:Show()
+ _G["PaperDollSidebarTab"..i].Highlight:Show()
+ end
+ end
+
+ _G[PAPERDOLL_SIDEBARS[index].frame]:Show()
+ if E.db.enhanced.character.animations then
+ UIFrameFadeIn(_G[PAPERDOLL_SIDEBARS[index].frame], 0.2, 0, 1)
+ end
+ PaperDollFrame.currentSideBar = _G[PAPERDOLL_SIDEBARS[index].frame]
+ PaperDollFrame.currentSideBarID = index
+
+ _G["PaperDollSidebarTab"..index].Hider:Hide()
+ _G["PaperDollSidebarTab"..index].Highlight:Hide()
+ end
+end
+
+function module:PaperDollTitlesPane_UpdateScrollFrame()
+ local buttons = PaperDollTitlesPane.buttons
+ local playerTitles = PaperDollTitlesPane.titles
+ local numButtons = #buttons
+ local scrollOffset = HybridScrollFrame_GetOffset(PaperDollTitlesPane)
+ local button, playerTitle
+
+ for i = 1, numButtons do
+ button = buttons[i]
+ playerTitle = playerTitles[i + scrollOffset]
+
+ if playerTitle then
+ button:Show()
+ button.text:SetText(playerTitle.name)
+ button.titleId = playerTitle.id
+
+ local highlight = button:GetHighlightTexture()
+ highlight:SetTexture(E.Media.Textures.Highlight)
+ highlight:SetInside()
+ highlight:SetVertexColor(1, 1, 1, 0.35)
+
+ if PaperDollTitlesPane.selected == playerTitle.id then
+ button.Check:SetAlpha(1)
+ button.SelectedBar:SetTexture(E.Media.Textures.Highlight)
+ button.SelectedBar:SetVertexColor(1, 0.80, 0.10, 0.3)
+ button.SelectedBar:SetInside()
+ button.SelectedBar:Show()
+ else
+ button.Check:SetAlpha(0)
+ button.SelectedBar:Hide()
+ end
+
+ if (i + scrollOffset) % 2 == 0 then
+ button.Stripe:SetTexture(0.9, 0.9, 1, 0.1)
+ button.Stripe:Show()
+ else
+ button.Stripe:Hide()
+ end
+ else
+ button:Hide()
+ end
+ end
+end
+
+local function PlayerTitleSort(a, b) return a.name < b.name end
+
+function module:PaperDollTitlesPane_Update()
+ local playerTitles = {}
+ local currentTitle = GetCurrentTitle()
+ local titleCount = 1
+ local buttons = PaperDollTitlesPane.buttons
+ local fontstringText = buttons[1].text
+
+ PaperDollTitlesPane.selected = -1
+ playerTitles[1] = {}
+ playerTitles[1].name = " "
+ playerTitles[1].id = -1
+
+ for i = 1, GetNumTitles() do
+ if IsTitleKnown(i) ~= 0 then
+ titleCount = titleCount + 1
+ playerTitles[titleCount] = playerTitles[titleCount] or {}
+ playerTitles[titleCount].name = trim(GetTitleName(i))
+ playerTitles[titleCount].id = i
+
+ if i == currentTitle then
+ PaperDollTitlesPane.selected = i
+ end
+
+ fontstringText:SetText(playerTitles[titleCount].name)
+ end
+ end
+
+ sort(playerTitles, PlayerTitleSort)
+ playerTitles[1].name = NONE
+ PaperDollTitlesPane.titles = playerTitles
+
+ HybridScrollFrame_Update(PaperDollTitlesPane, (titleCount * 22) + 20 , PaperDollTitlesPane:GetHeight())
+ if not PaperDollTitlesPane.scrollBar.thumbTexture:IsShown() then
+ PaperDollTitlesPane.scrollBar.thumbTexture:Show()
+ end
+
+ self:PaperDollTitlesPane_UpdateScrollFrame()
+end
+
+function module:PaperDollEquipmentManagerPane_Update()
+ local _, setID = GetEquipmentSetInfoByName(PaperDollEquipmentManagerPane.selectedSetName or "")
+ if setID then
+ PaperDollEquipmentManagerPaneSaveSet:Enable()
+ PaperDollEquipmentManagerPaneEquipSet:Enable()
+ else
+ PaperDollEquipmentManagerPaneSaveSet:Disable()
+ PaperDollEquipmentManagerPaneEquipSet:Disable()
+
+ if PaperDollEquipmentManagerPane.selectedSetName then
+ PaperDollEquipmentManagerPane.selectedSetName = nil
+ PaperDollFrame_ClearIgnoredSlots()
+ end
+ end
+
+ local numSets = GetNumEquipmentSets()
+ local numRows = numSets
+ if numSets < MAX_EQUIPMENT_SETS_PER_PLAYER then
+ numRows = numRows + 1
+ end
+
+ HybridScrollFrame_Update(PaperDollEquipmentManagerPane, numRows * 44 + PaperDollEquipmentManagerPaneEquipSet:GetHeight() + 20 , PaperDollEquipmentManagerPane:GetHeight())
+ if not PaperDollEquipmentManagerPane.scrollBar.thumbTexture:IsShown() then
+ PaperDollEquipmentManagerPane.scrollBar.thumbTexture:Show()
+ end
+
+ local scrollOffset = HybridScrollFrame_GetOffset(PaperDollEquipmentManagerPane)
+ local buttons = PaperDollEquipmentManagerPane.buttons
+ local selectedName = PaperDollEquipmentManagerPane.selectedSetName
+ local name, texture, button
+
+ for i = 1, #buttons do
+ button = buttons[i]
+ if (i + scrollOffset) <= numRows then
+ button:Show()
+ button:Enable()
+
+ if (i + scrollOffset) <= numSets then
+ name, texture = GetEquipmentSetInfo(i + scrollOffset)
+ button.name = name
+ button.text:SetText(name)
+ button.text:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
+
+ if texture then
+ button.icon:SetTexture(texture)
+ else
+ button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
+ end
+
+ if selectedName and button.name == selectedName then
+ button.SelectedBar:Show()
+ GearManagerDialog.selectedSet = button
+ else
+ button.SelectedBar:Hide()
+ end
+ else
+ button.name = nil
+ button.text:SetText(L["New Set"])
+ button.text:SetTextColor(GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b)
+ button.icon:SetTexture("Interface\\Icons\\Spell_ChargePositive")
+ button.SelectedBar:Hide()
+ end
+
+ if (i + scrollOffset) % 2 == 0 then
+ button.Stripe:SetTexture(0.9, 0.9, 1)
+ button.Stripe:SetAlpha(0.1)
+ button.Stripe:Show()
+ else
+ button.Stripe:Hide()
+ end
+ else
+ button:Hide()
+ end
+ end
+end
+
+local EnchantSlots = {
+ {INVSLOT_HEAD, "HEADSLOT"},
+ {INVSLOT_NECK, "NECKSLOT"},
+ {INVSLOT_SHOULDER, "SHOULDERSLOT"},
+ {INVSLOT_CHEST, "CHESTSLOT"},
+ {INVSLOT_WAIST, "WAISTSLOT"},
+ {INVSLOT_LEGS, "LEGSSLOT"},
+ {INVSLOT_FEET, "FEETSLOT"},
+ {INVSLOT_WRIST, "WRISTSLOT"},
+ {INVSLOT_HAND, "HANDSSLOT"},
+ {INVSLOT_FINGER1, "FINGER0SLOT"},
+ {INVSLOT_FINGER2, "FINGER1SLOT"},
+ {INVSLOT_TRINKET1, "TRINKET0SLOT"},
+ {INVSLOT_TRINKET2, "TRINKET1SLOT"},
+ {INVSLOT_BACK, "BACKSLOT"},
+ {INVSLOT_MAINHAND, "MAINHANDSLOT"},
+ {INVSLOT_OFFHAND, "SECONDARYHANDSLOT"},
+ {INVSLOT_RANGED, "RANGEDSLOT"},
+}
+
+function module:MysticEnchantPane_Update()
+ HybridScrollFrame_Update(PaperDollMysticEnchantPane, 768, PaperDollMysticEnchantPane:GetHeight())
+ if not PaperDollMysticEnchantPane.scrollBar.thumbTexture:IsShown() then
+ PaperDollMysticEnchantPane.scrollBar.thumbTexture:Show()
+ end
+
+ local scrollOffset = HybridScrollFrame_GetOffset(PaperDollMysticEnchantPane)
+ local buttons = PaperDollMysticEnchantPane.buttons
+ local name, texture, button
+
+ for i = 1, #buttons do
+ button = buttons[i]
+ if (i + scrollOffset) <= 17 then
+ button:Show()
+ button:Enable()
+ local slot, slotStr = unpack(EnchantSlots[i + scrollOffset])
+ local enchant = GetInventoryItemMysticEnchant("player", slot)
+
+ if enchant then
+ local RE = GetREData(enchant)
+ name, _, texture = GetSpellInfo(RE.spellID)
+
+ if not name then
+ name = "|cffFF0000Unknown Enchant: " .. RE.spellID .. "|r"
+ texture = nil
+ else
+ name = ITEM_QUALITY_COLORS[RE.quality]:WrapText(name)
+ end
+ else
+ name = nil
+ texture = select(2, GetInventorySlotInfo(slotStr))
+ end
+
+ local slotName = _G[slotStr]
+ if name then
+ button.name = slotName .. "\n" .. name
+ else
+ button.name = slotName
+ end
+
+ button.enchant = enchant
+ button.text:SetText(button.name)
+ button.text:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
+
+ if texture then
+ button.icon:SetTexture(texture)
+ else
+ button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
+ end
+
+ if (i + scrollOffset) % 2 == 0 then
+ button.Stripe:SetTexture(0.9, 0.9, 1)
+ button.Stripe:SetAlpha(0.1)
+ button.Stripe:Show()
+ else
+ button.Stripe:Hide()
+ end
+ else
+ button:Hide()
+ end
+ end
+end
+
+function module:PetPaperDollCompanionPane_Update()
+ local scrollFrame = PetPaperDollCompanionPane
+ local offset = HybridScrollFrame_GetOffset(scrollFrame)
+ local buttons = scrollFrame.buttons
+ local selected, text
+ local button, displayIndex, index
+ local creatureID, creatureName, spellID, icon, active
+
+ if PetPaperDollFrameCompanionFrame.mode == "CRITTER" then
+ selected = PetPaperDollFrame_FindCompanionIndex(PetPaperDollFrameCompanionFrame.idCritter)
+ text = L["Total Companions"]
+ elseif PetPaperDollFrameCompanionFrame.mode == "MOUNT" then
+ selected = PetPaperDollFrame_FindCompanionIndex(PetPaperDollFrameCompanionFrame.idMount)
+ text = L["Total Mounts"]
+ end
+
+ local numCompanions = GetNumCompanions(PetPaperDollFrameCompanionFrame.mode)
+ scrollFrame.text:SetFormattedText("%s: %d", text, numCompanions)
+
+ for i = 1, #buttons do
+ button = buttons[i]
+ displayIndex = i + offset
+
+ if displayIndex <= numCompanions then
+ index = displayIndex
+ creatureID, creatureName, spellID, icon, active = GetCompanionInfo(PetPaperDollFrameCompanionFrame.mode, index)
+
+ button:Show()
+ button:SetID(index)
+ _G[button:GetName().."Cooldown"]:SetInside()
+
+ button.creatureID = creatureID
+ button.spellID = spellID
+ button.active = active
+
+ if creatureID then
+ button.name:SetText(creatureName)
+ button.icon:SetTexture(icon)
+ button:Enable()
+
+ local start, duration, enable = GetCompanionCooldown(PetPaperDollFrameCompanionFrame.mode, index)
+ if start and duration and enable then
+ CooldownFrame_SetTimer(_G[button:GetName().."Cooldown"], start, duration, enable)
+ end
+ else
+ button.name:SetText("")
+ _G[button:GetName().."Cooldown"]:Hide()
+ button:Disable()
+ end
+
+ if (index == selected) and creatureID then
+ button.SelectedBar:Show()
+ button.SelectedBar:SetTexture(1, 1, 1, 0.2)
+ elseif active then
+ button.SelectedBar:Show()
+ button.SelectedBar:SetTexture(1, 1, 0, 0.2)
+ else
+ button.SelectedBar:Hide()
+ end
+
+ if (i + offset) % 2 == 0 then
+ button.Stripe:SetTexture(0.9, 0.9, 1)
+ button.Stripe:SetAlpha(0.1)
+ button.Stripe:Show()
+ else
+ button.Stripe:Hide()
+ end
+ else
+ button:Hide()
+ end
+ end
+
+ local totalHeight = numCompanions * 44
+ HybridScrollFrame_Update(scrollFrame, totalHeight, scrollFrame:GetHeight())
+ if not scrollFrame.scrollBar.thumbTexture:IsShown() then
+ scrollFrame.scrollBar.thumbTexture:Show()
+ end
+end
+
+function module:UpdateCharacterModelFrame()
+ if not module.Initialized then return end
+
+ if E.db.enhanced.character.characterBackground then
+ if not CharacterModelFrame.backdrop then
+ CharacterModelFrame:CreateBackdrop()
+ CharacterModelFrame.backdrop:SetAllPoints(CharacterModelFrame)
+
+ CharacterModelFrame.textureTopLeft = CharacterModelFrame:CreateTexture("$parentTextureTopLeft", "BACKGROUND")
+ CharacterModelFrame.textureTopLeft:Point("TOPLEFT", 1, -1)
+ CharacterModelFrame.textureTopLeft:Size(216, 246)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 256, 256, 216, 248, 40, 8
+ CharacterModelFrame.textureTopLeft:SetTexCoord(0.15625, 1, 0.03125, 1)
+
+ CharacterModelFrame.textureTopRight = CharacterModelFrame:CreateTexture("$parentTextureTopRight", "BACKGROUND")
+ CharacterModelFrame.textureTopRight:Point("TOPLEFT", CharacterModelFrame.textureTopLeft, "TOPRIGHT")
+ CharacterModelFrame.textureTopRight:Size(19, 246)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 64, 256, 19, 248, 0, 8
+ CharacterModelFrame.textureTopRight:SetTexCoord(0, 0.296875, 0.03125, 1)
+
+ CharacterModelFrame.textureBotLeft = CharacterModelFrame:CreateTexture("$parentTextureBotLeft", "BACKGROUND")
+ CharacterModelFrame.textureBotLeft:Point("TOPLEFT", CharacterModelFrame.textureTopLeft, "BOTTOMLEFT")
+ CharacterModelFrame.textureBotLeft:Size(216, 76)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 256, 128, 216, 76, 40, 0
+ CharacterModelFrame.textureBotLeft:SetTexCoord(0.15625, 1, 0, 0.59375)
+
+ CharacterModelFrame.textureBotRight = CharacterModelFrame:CreateTexture("$parentTextureBotRight", "BACKGROUND")
+ CharacterModelFrame.textureBotRight:Point("TOPLEFT", CharacterModelFrame.textureTopLeft, "BOTTOMRIGHT")
+ CharacterModelFrame.textureBotRight:Size(19, 76)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 64, 128, 19, 76, 0, 0
+ CharacterModelFrame.textureBotRight:SetTexCoord(0, 0.296875, 0, 0.59375)
+
+ CharacterModelFrame.backgroundOverlay = CharacterModelFrame:CreateTexture("$parentBackgroundOverlay", "BORDER")
+ CharacterModelFrame.backgroundOverlay:SetInside(CharacterModelFrame.backdrop)
+ CharacterModelFrame.backgroundOverlay:SetTexture(0, 0, 0)
+ else
+ CharacterModelFrame.backdrop:Show()
+ end
+
+ local desaturate = E.db.enhanced.character.desaturateCharacter and true or false
+ local raceEng = lower(E.myrace)
+
+ CharacterModelFrame.textureTopLeft:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\"..raceEng.."_1.blp")
+ CharacterModelFrame.textureTopLeft:SetDesaturated(desaturate)
+ CharacterModelFrame.textureTopLeft:Show()
+
+ CharacterModelFrame.textureTopRight:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\"..raceEng.."_2.blp")
+ CharacterModelFrame.textureTopRight:SetDesaturated(desaturate)
+ CharacterModelFrame.textureTopRight:Show()
+
+ CharacterModelFrame.textureBotLeft:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\"..raceEng.."_3.blp")
+ CharacterModelFrame.textureBotLeft:SetDesaturated(desaturate)
+ CharacterModelFrame.textureBotLeft:Show()
+
+ CharacterModelFrame.textureBotRight:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\"..raceEng.."_4.blp")
+ CharacterModelFrame.textureBotRight:SetDesaturated(desaturate)
+ CharacterModelFrame.textureBotRight:Show()
+
+ CharacterModelFrame.backgroundOverlay:Show()
+
+ if raceEng == "scourge" then
+ CharacterModelFrame.backgroundOverlay:SetAlpha(0.2)
+ elseif raceEng == "bloodelf" or raceEng == "nightelf" then
+ CharacterModelFrame.backgroundOverlay:SetAlpha(0.7)
+ elseif raceEng == "troll" or raceEng == "orc" then
+ CharacterModelFrame.backgroundOverlay:SetAlpha(0.5)
+ else
+ CharacterModelFrame.backgroundOverlay:SetAlpha(0.6)
+ end
+ elseif CharacterModelFrame.textureTopLeft then
+ CharacterModelFrame.backdrop:Hide()
+ CharacterModelFrame.textureTopLeft:Hide()
+ CharacterModelFrame.textureTopRight:Hide()
+ CharacterModelFrame.textureBotLeft:Hide()
+ CharacterModelFrame.textureBotRight:Hide()
+ CharacterModelFrame.backgroundOverlay:Hide()
+ end
+end
+
+function module:UpdateInspectModelFrame()
+ if not module.Initialized or not InspectModelFrame then return end
+
+ if E.db.enhanced.character.inspectBackground then
+ if not InspectModelFrame.backdrop then
+ InspectModelFrame:CreateBackdrop("Default")
+ InspectModelFrame.backdrop:SetAllPoints(InspectModelFrame)
+
+ InspectModelFrame.textureTopLeft = InspectModelFrame:CreateTexture("$parentTextureTopLeft", "BACKGROUND")
+ InspectModelFrame.textureTopLeft:Point("TOPLEFT", 1, -1)
+ InspectModelFrame.textureTopLeft:Size(216, 246)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 256, 256, 216, 248, 40, 8
+ InspectModelFrame.textureTopLeft:SetTexCoord(0.15625, 1, 0.03125, 1)
+
+ InspectModelFrame.textureTopRight = InspectModelFrame:CreateTexture("$parentTextureTopRight", "BACKGROUND")
+ InspectModelFrame.textureTopRight:Point("TOPLEFT", InspectModelFrame.textureTopLeft, "TOPRIGHT")
+ InspectModelFrame.textureTopRight:Size(19, 246)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 64, 256, 19, 248, 0, 8
+ InspectModelFrame.textureTopRight:SetTexCoord(0, 0.296875, 0.03125, 1)
+
+ InspectModelFrame.textureBotLeft = InspectModelFrame:CreateTexture("$parentTextureBotLeft", "BACKGROUND")
+ InspectModelFrame.textureBotLeft:Point("TOPLEFT", InspectModelFrame.textureTopLeft, "BOTTOMLEFT")
+ InspectModelFrame.textureBotLeft:Size(216, 76)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 256, 128, 216, 76, 40, 0
+ InspectModelFrame.textureBotLeft:SetTexCoord(0.15625, 1, 0, 0.59375)
+
+ InspectModelFrame.textureBotRight = InspectModelFrame:CreateTexture("$parentTextureBotRight", "BACKGROUND")
+ InspectModelFrame.textureBotRight:Point("TOPLEFT", InspectModelFrame.textureTopLeft, "BOTTOMRIGHT")
+ InspectModelFrame.textureBotRight:Size(19, 76)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 64, 128, 19, 76, 0, 0
+ InspectModelFrame.textureBotRight:SetTexCoord(0, 0.296875, 0, 0.59375)
+
+ InspectModelFrame.backgroundOverlay = InspectModelFrame:CreateTexture("$parentBackgroundOverlay", "BORDER")
+ InspectModelFrame.backgroundOverlay:SetInside(InspectModelFrame.backdrop)
+ InspectModelFrame.backgroundOverlay:SetTexture(0, 0, 0)
+ else
+ InspectModelFrame.backdrop:Show()
+ end
+
+ local _, raceEng = UnitRace(InspectFrame.unit)
+ raceEng = lower(raceEng)
+ local desaturate = E.db.enhanced.character.desaturateInspect and true or false
+
+ InspectModelFrame.textureTopLeft:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\"..raceEng.."_1.blp")
+ InspectModelFrame.textureTopLeft:SetDesaturated(desaturate)
+ InspectModelFrame.textureTopLeft:Show()
+
+ InspectModelFrame.textureTopRight:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\"..raceEng.."_2.blp")
+ InspectModelFrame.textureTopRight:SetDesaturated(desaturate)
+ InspectModelFrame.textureTopRight:Show()
+
+ InspectModelFrame.textureBotLeft:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\"..raceEng.."_3.blp")
+ InspectModelFrame.textureBotLeft:SetDesaturated(desaturate)
+ InspectModelFrame.textureBotLeft:Show()
+
+ InspectModelFrame.textureBotRight:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\"..raceEng.."_4.blp")
+ InspectModelFrame.textureBotRight:SetDesaturated(desaturate)
+ InspectModelFrame.textureBotRight:Show()
+
+ InspectModelFrame.backgroundOverlay:Show()
+
+ if raceEng == "scourge" then
+ InspectModelFrame.backgroundOverlay:SetAlpha(0.2)
+ elseif raceEng == "bloodelf" or raceEng == "nightelf" then
+ InspectModelFrame.backgroundOverlay:SetAlpha(0.7)
+ elseif raceEng == "troll" or raceEng == "orc" then
+ InspectModelFrame.backgroundOverlay:SetAlpha(0.5)
+ else
+ InspectModelFrame.backgroundOverlay:SetAlpha(0.6)
+ end
+ elseif InspectModelFrame.textureTopLeft then
+ InspectModelFrame.backdrop:Hide()
+ InspectModelFrame.textureTopLeft:Hide()
+ InspectModelFrame.textureTopRight:Hide()
+ InspectModelFrame.textureBotLeft:Hide()
+ InspectModelFrame.textureBotRight:Hide()
+ InspectModelFrame.backgroundOverlay:Hide()
+ end
+end
+
+function module:UpdatePetModelFrame()
+ if not module.Initialized then return end
+
+ if E.db.enhanced.character.petBackground then
+ if not PetModelFrame.backdrop then
+ PetModelFrame:CreateBackdrop("Default")
+ PetModelFrame.backdrop:SetAllPoints(PetModelFrame)
+
+ PetModelFrame.petPaperDollPetModelBg = PetModelFrame:CreateTexture("$parentPetPaperDollPetModelBg", "BACKGROUND")
+ PetModelFrame.petPaperDollPetModelBg:SetInside(PetModelFrame.backdrop)
+ PetModelFrame.petPaperDollPetModelBg:SetTexCoord(0.00390625, 0.623046875, 0.00390625, 0.689453125)
+
+ PetModelFrame.backgroundOverlay = PetModelFrame:CreateTexture("$parentBackgroundOverlay", "BORDER")
+ PetModelFrame.backgroundOverlay:SetInside(PetModelFrame.backdrop)
+ PetModelFrame.backgroundOverlay:SetTexture(0, 0, 0)
+ else
+ PetModelFrame.backdrop:Show()
+ end
+
+ if E.myclass == "HUNTER" then
+ PetModelFrame.petPaperDollPetModelBg:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\petHunter.blp")
+ PetModelFrame.backgroundOverlay:SetAlpha(0.4)
+ elseif E.myclass == "WARLOCK" then
+ PetModelFrame.petPaperDollPetModelBg:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\petWarlock.blp")
+ PetModelFrame.backgroundOverlay:SetAlpha(0.2)
+ elseif E.myclass == "DEATHKNIGHT" then
+ PetModelFrame.petPaperDollPetModelBg:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\petDeathKnight.blp")
+ PetModelFrame.backgroundOverlay:SetAlpha(0.1)
+ else
+ PetModelFrame.petPaperDollPetModelBg:Hide()
+ end
+
+ PetModelFrame.petPaperDollPetModelBg:SetDesaturated(E.db.enhanced.character.desaturatePet and true or false)
+
+ PetModelFrame.petPaperDollPetModelBg:Show()
+ PetModelFrame.backgroundOverlay:Show()
+ elseif PetModelFrame.petPaperDollPetModelBg then
+ PetModelFrame.backdrop:Hide()
+ PetModelFrame.petPaperDollPetModelBg:Hide()
+ PetModelFrame.backgroundOverlay:Hide()
+ end
+end
+
+function module:UpdateCompanionModelFrame()
+ if not module.Initialized then return end
+
+ if E.db.enhanced.character.companionBackground then
+ if not CompanionModelFrame.backdrop then
+ CompanionModelFrame:CreateBackdrop("Default")
+ CompanionModelFrame.backdrop:SetAllPoints(CompanionModelFrame)
+
+ CompanionModelFrame.backgroundTex = CompanionModelFrame:CreateTexture("$parentBackgroundTex", "BACKGROUND")
+ CompanionModelFrame.backgroundTex:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\MountJournal-BG")
+ CompanionModelFrame.backgroundTex:SetInside(CompanionModelFrame.backdrop)
+ CompanionModelFrame.backgroundTex:SetTexCoord(0.00390625, 0.783203125, 0.0078125, 0.984375)
+
+ CompanionModelFrame.backgroundOverlay = CompanionModelFrame:CreateTexture("$parentBackgroundOverlay", "BORDER")
+ CompanionModelFrame.backgroundOverlay:SetInside(CompanionModelFrame.backdrop)
+ CompanionModelFrame.backgroundOverlay:SetTexture(0, 0, 0)
+ CompanionModelFrame.backgroundOverlay:SetAlpha(0.3)
+ else
+ CompanionModelFrame.backdrop:Show()
+ end
+
+ CompanionModelFrame.backgroundTex:SetDesaturated(E.db.enhanced.character.desaturateCompanion and true or false)
+
+ CompanionModelFrame.backgroundTex:Show()
+ CompanionModelFrame.backgroundOverlay:Show()
+ elseif CompanionModelFrame.backgroundTex then
+ CompanionModelFrame.backdrop:Hide()
+ CompanionModelFrame.backgroundTex:Hide()
+ CompanionModelFrame.backgroundOverlay:Hide()
+ end
+end
+
+local function SetScrollValue(self, value)
+ if self.scrollBar.anim:IsPlaying() then
+ self.scrollBar.anim:Stop()
+ end
+ self.scrollBar.anim.progress:SetChange(value)
+ self.scrollBar.anim:Play()
+end
+
+local function Animation_OnMouseWheel(self, delta, stepSize)
+ if not self.scrollBar:IsVisible() then return end
+
+ self.times = self.times + 1
+
+ if self.direction ~= delta then
+ self.direction = delta
+ self.times = 1
+ end
+
+ local minVal, maxVal = 0, self.range
+ stepSize = stepSize or self.stepSize or self.buttonHeight or self.scrollBar.scrollStep
+
+ if delta == 1 then
+ SetScrollValue(self, max(minVal, self.scrollBar:GetValue() - (stepSize * self.times)))
+ else
+ SetScrollValue(self, min(maxVal, self.scrollBar:GetValue() + (stepSize * self.times)))
+ end
+end
+
+local function CreateSmoothScrollAnimation(scrollBar, hybridScroll)
+ if not E.db.enhanced.character.animations then return end
+
+ local scrollFrame = scrollBar:GetParent()
+ scrollFrame.times = 0
+ scrollFrame.direction = -1
+
+ scrollBar.anim = CreateAnimationGroup(scrollBar)
+ scrollBar.anim.progress = scrollBar.anim:CreateAnimation("Progress")
+ scrollBar.anim.progress:SetSmoothing("Out")
+ scrollBar.anim.progress:SetDuration(0.5)
+
+ scrollBar.anim.progress:SetScript("OnPlay", function(self)
+ if (self:GetChange() >= self.Parent:GetParent().range) or (self:GetChange() <= 0) then
+ self.Parent:GetParent().times = self.Parent:GetParent().times - 1
+ end
+ end)
+
+ scrollBar.anim.progress:SetScript("OnFinished", function(self)
+ self.Parent:GetParent().times = 0
+ end)
+
+ scrollFrame:SetScript("OnMouseWheel", Animation_OnMouseWheel)
+
+ if not hybridScroll then
+ scrollFrame:HookScript("OnScrollRangeChanged", function(self)
+ self.range = select(2, self.scrollBar:GetMinMaxValues())
+ end)
+ end
+end
+
+function module:Initialize()
+ if not E.private.enhanced.character.enable then return end
+
+ self.skinEnabled = (E.private.skins.blizzard.enable and E.private.skins.blizzard.character) and true or false
+
+ if PersonalGearScore then
+ PersonalGearScore:Hide()
+ end
+ if GearScore2 then
+ GearScore2:Hide()
+ end
+
+ PlayerTitleFrame:Kill()
+ PlayerTitlePickerFrame:Kill()
+ CharacterAttributesFrame:Kill()
+ CharacterResistanceFrame:Kill()
+ GearManagerToggleButton:Kill()
+
+ SetCVar("equipmentManager", 1)
+
+ if self.skinEnabled then
+ AscensionCharacterFrame:Hide()
+ CharacterNameFrame:ClearAllPoints()
+ CharacterNameFrame:Point("CENTER", CharacterFrame.backdrop, 6, 200)
+ CharacterFrameCloseButton:Point("CENTER", CharacterFrame.backdrop, "TOPRIGHT", -12, -13)
+
+ CharacterFrame.backdrop:ClearAllPoints()
+ CharacterFrame.backdrop:Point("TOPLEFT", 11, -12)
+ CharacterFrame.backdrop:Size(341, 424)
+
+ S:SetUIPanelWindowInfo(CharacterFrame, "width")
+
+ S:SetBackdropHitRect(PaperDollFrame, CharacterFrame.backdrop)
+ S:SetBackdropHitRect(PetPaperDollFrame, CharacterFrame.backdrop)
+ S:SetBackdropHitRect(PetPaperDollFrameCompanionFrame, CharacterFrame.backdrop)
+ S:SetBackdropHitRect(PetPaperDollFramePetFrame, CharacterFrame.backdrop)
+ end
+
+ local function FixHybridScrollBarSkin(frame, h1, h2)
+ frame.scrollUp:Size(18)
+ frame.scrollDown:Size(18)
+
+ frame.scrollBar.thumbTexture:Size(18, 24)
+
+ frame.scrollBar.backdrop:Point("TOPLEFT", frame.scrollBar.Thumb, "TOPLEFT", 2, h1 or -5)
+ frame.scrollBar.backdrop:Point("BOTTOMRIGHT", frame.scrollBar.Thumb, "BOTTOMRIGHT", -2, h2 or 1)
+ end
+
+ local expandButton = CreateFrame("Button", "CharacterFrameExpandButton", CharacterFrame)
+ expandButton:Point("BOTTOMLEFT", CharacterFrame, 325, 85)
+ expandButton:SetFrameLevel(CharacterFrame:GetFrameLevel() + 5)
+ S:HandleNextPrevButton(expandButton)
+ expandButton:Size(19)
+
+ expandButton:SetScript("OnClick", function(self)
+ if CharacterFrame.Expanded then
+ E.private.enhanced.character.collapsed = true
+ module:CharacterFrame_Collapse()
+ PlaySound("igCharacterInfoClose")
+ else
+ E.private.enhanced.character.collapsed = false
+ module:CharacterFrame_Expand()
+ PlaySound("igCharacterInfoOpen")
+ end
+ if GameTooltip:GetOwner() == self then
+ self:GetScript("OnEnter")(self)
+ end
+ end)
+
+ expandButton:SetScript("OnEnter", function(self)
+ S.SetModifiedBackdrop(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
+ if CharacterFrame.Expanded then
+ GameTooltip:SetText(self.collapseTooltip)
+ else
+ GameTooltip:SetText(self.expandTooltip)
+ end
+ end)
+ expandButton:SetScript("OnLeave", function(self)
+ S.SetOriginalBackdrop(self)
+ GameTooltip_Hide()
+ end)
+
+do -- CharacterFrame
+ local sidebarTabs = CreateFrame("Frame", "PaperDollSidebarTabs", PaperDollFrame)
+ sidebarTabs:Hide()
+ sidebarTabs:Size(152, 35)
+ sidebarTabs:Point("BOTTOMRIGHT", CharacterFrame.backdrop, "TOPRIGHT", -29, -59)
+
+ local sidebarTabs4 = CreateFrame("Button", "PaperDollSidebarTab4", sidebarTabs)
+ sidebarTabs4:SetID(4)
+ sidebarTabs4:Point("BOTTOMRIGHT", 0, 0)
+ self:PaperDollSidebarTab(sidebarTabs4)
+
+ local sidebarTabs3 = CreateFrame("Button", "PaperDollSidebarTab3", sidebarTabs)
+ sidebarTabs3:SetID(3)
+ sidebarTabs3:Point("RIGHT", "PaperDollSidebarTab4", "LEFT", -5, 0)
+ self:PaperDollSidebarTab(sidebarTabs3)
+
+ local sidebarTabs2 = CreateFrame("Button", "PaperDollSidebarTab2", sidebarTabs)
+ sidebarTabs2:SetID(2)
+ sidebarTabs2:Point("RIGHT", "PaperDollSidebarTab3", "LEFT", -5, 0)
+ self:PaperDollSidebarTab(sidebarTabs2)
+
+ local sidebarTabs1 = CreateFrame("Button", "PaperDollSidebarTab1", sidebarTabs)
+ sidebarTabs1:SetID(1)
+ sidebarTabs1:Point("RIGHT", "PaperDollSidebarTab2", "LEFT", -5, 0)
+ self:PaperDollSidebarTab(sidebarTabs1)
+
+ sidebarTabs1:RegisterEvent("UNIT_PORTRAIT_UPDATE")
+ sidebarTabs1:RegisterEvent("PLAYER_ENTERING_WORLD")
+
+ local tcoords = PAPERDOLL_SIDEBARS[1].texCoords
+ sidebarTabs1.Icon:SetTexCoord(tcoords[1], tcoords[2], tcoords[3], tcoords[4])
+
+ sidebarTabs1:SetScript("OnEvent", function(self, event, unit)
+ if event == "UNIT_PORTRAIT_UPDATE" then
+ if not unit or unit == "player" then
+ SetPortraitTexture(self.Icon, "player")
+ end
+ elseif event == "PLAYER_ENTERING_WORLD" then
+ SetPortraitTexture(self.Icon, "player")
+ end
+ end)
+
+ --
+ -- Title Pane
+ --
+ local titlePane = CreateFrame("ScrollFrame", "PaperDollTitlesPane", PaperDollFrame, "HybridScrollFrameTemplate")
+ titlePane:Hide()
+ titlePane:Size(169, 350)
+ titlePane:Point("TOPRIGHT", CharacterFrame.backdrop, -29, -64)
+
+ titlePane.scrollBar = CreateFrame("Slider", "$parentScrollBar", titlePane, "HybridScrollBarTemplate")
+ titlePane.scrollBar:Point("TOPLEFT", titlePane, "TOPRIGHT", 2, -16)
+ titlePane.scrollBar:Point("BOTTOMLEFT", titlePane, "BOTTOMRIGHT", 2, 14)
+ S:HandleScrollBar(titlePane.scrollBar)
+ FixHybridScrollBarSkin(titlePane)
+
+ CreateSmoothScrollAnimation(titlePane.scrollBar, true)
+
+ titlePane:SetScript("OnShow", function(self)
+ module:PaperDollTitlesPane_Update()
+ end)
+
+ titlePane.scrollBar.Show = function(self)
+ titlePane:Width(169)
+ titlePane:Point("TOPRIGHT", CharacterFrame.backdrop, -29, -64)
+ for _, button in next, titlePane.buttons do
+ button:Width(169)
+ end
+ getmetatable(self).__index.Show(self)
+ end
+
+ titlePane.scrollBar.Hide = function(self)
+ titlePane:Width(190)
+ titlePane:Point("TOPRIGHT", CharacterFrame.backdrop, -8, -64)
+ for _, button in next, titlePane.buttons do
+ button:Width(190)
+ end
+ getmetatable(self).__index.Hide(self)
+ end
+
+ titlePane:SetFrameLevel(CharacterFrame:GetFrameLevel() + 1)
+
+ HybridScrollFrame_OnLoad(titlePane)
+ titlePane.update = self.PaperDollTitlesPane_UpdateScrollFrame
+ HybridScrollFrame_CreateButtons(PaperDollTitlesPane, "PlayerTitleButtonTemplate2", 2, -4)
+
+ local statsPane = CreateFrame("ScrollFrame", "CharacterStatsPane", CharacterFrame, "UIPanelScrollFrameTemplate")
+ statsPane:Hide()
+ statsPane:Size(169, 350)
+ statsPane:Point("TOPRIGHT", CharacterFrame.backdrop, -29, -64)
+ statsPane.Categories = {}
+
+ statsPane.scrollBar = CharacterStatsPaneScrollBar
+ CharacterStatsPaneScrollBar:Point("TOPLEFT", CharacterStatsPane, "TOPRIGHT", 4, -18)
+ CharacterStatsPaneScrollBar:Point("BOTTOMLEFT", CharacterStatsPane, "BOTTOMRIGHT", 4, 16)
+ S:HandleScrollBar(CharacterStatsPaneScrollBar)
+
+ CharacterStatsPaneScrollBar.scrollStep = 50
+ CharacterStatsPane.scrollBarHideable = 1
+
+ statsPane:SetScript("OnMouseWheel", function(self, value, scrollBar)
+ scrollBar = scrollBar or self.scrollBar
+ local scrollStep = scrollBar.scrollStep or scrollBar:GetHeight() / 2
+
+ if value > 0 then
+ scrollBar:SetValue(scrollBar:GetValue() - scrollStep)
+ else
+ scrollBar:SetValue(scrollBar:GetValue() + scrollStep)
+ end
+ end)
+
+ CharacterStatsPaneScrollBarScrollUpButton:SetScript("OnClick", function(self)
+ local parent = self:GetParent()
+ local scrollStep = parent.scrollStep or (parent:GetHeight() / 2)
+ parent:SetValue(parent:GetValue() - scrollStep)
+ PlaySound("UChatScrollButton")
+ end)
+ CharacterStatsPaneScrollBarScrollDownButton:SetScript("OnClick", function(self)
+ local parent = self:GetParent()
+ local scrollStep = parent.scrollStep or (parent:GetHeight() / 2)
+ parent:SetValue(parent:GetValue() + scrollStep)
+ PlaySound("UChatScrollButton")
+ end)
+
+ CreateSmoothScrollAnimation(CharacterStatsPaneScrollBar)
+
+ --
+ -- Stats Pane
+ --
+ local statsPaneScrollChild = CreateFrame("Frame", "CharacterStatsPaneScrollChild", statsPane)
+ statsPaneScrollChild:Size(169, 0)
+ statsPaneScrollChild:Point("TOPLEFT")
+
+ for i = 1, 10 do
+ local button = CreateFrame("Frame", "CharacterStatsPaneCategory"..i, statsPaneScrollChild)
+ button:Size(169, 0)
+
+ button.Toolbar = CreateFrame("Button", nil, button)
+ button.Toolbar:RegisterForDrag("LeftButton")
+ button.Toolbar:Size(150, 18)
+ button.Toolbar:Point("TOP")
+ button.Toolbar:SetTemplate("Default", true)
+ button.Toolbar:HookScript("OnEnter", S.SetModifiedBackdrop)
+ button.Toolbar:HookScript("OnLeave", S.SetOriginalBackdrop)
+
+ button.Toolbar:SetScript("OnClick", function(self)
+ if self:GetParent().collapsed then
+ PaperDollFrame_ExpandStatCategory(self:GetParent())
+ CharacterStatsPane.collapsedData[self:GetParent().Category] = false
+ else
+ PaperDollFrame_CollapseStatCategory(self:GetParent())
+ CharacterStatsPane.collapsedData[self:GetParent().Category] = true
+ end
+ end)
+ button.Toolbar:SetScript("OnDragStart", function(self)
+ PaperDollStatCategory_OnDragStart(self:GetParent())
+ end)
+ button.Toolbar:SetScript("OnDragStop", function(self)
+ PaperDollStatCategory_OnDragStop(self:GetParent())
+ end)
+
+ button.NameText = button.Toolbar:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
+ button.NameText:Point("CENTER")
+
+ button.Stats = {}
+ button.Stats[1] = CreateFrame("Frame", "$parentStat1", button, "CharacterStatFrameTemplate")
+ button.Stats[1]:Point("TOPLEFT", 0, -23)
+ button.Stats[1]:Point("RIGHT", -4, 0)
+
+ statsPane.Categories[i] = button
+ end
+
+ statsPane:SetScrollChild(statsPaneScrollChild)
+
+ CharacterStatsPaneScrollBar.Show = function(self)
+ statsPane:Width(169)
+ statsPane:Point("TOPRIGHT", CharacterFrame.backdrop, -29, -64)
+ for _, button in next, statsPane.Categories do
+ button:Width(169)
+ button.Toolbar:Width(132)
+ end
+ getmetatable(self).__index.Show(self)
+ end
+
+ CharacterStatsPaneScrollBar.Hide = function(self)
+ statsPane:Width(190)
+ statsPane:Point("TOPRIGHT", CharacterFrame.backdrop, -8, -64)
+ for _, button in next, statsPane.Categories do
+ button:Width(190)
+ button.Toolbar:Width(150)
+ end
+ getmetatable(self).__index.Hide(self)
+ end
+
+ --
+ -- Equipment Manager Pane
+ --
+ local equipmentManagerPane = CreateFrame("ScrollFrame", "PaperDollEquipmentManagerPane", PaperDollFrame, "HybridScrollFrameTemplate")
+ equipmentManagerPane:Hide()
+ equipmentManagerPane:Size(169, 350)
+ equipmentManagerPane:Point("TOPRIGHT", CharacterFrame.backdrop, -29, -64)
+
+ equipmentManagerPane.EquipSet = CreateFrame("Button", "$parentEquipSet", equipmentManagerPane, "UIPanelButtonTemplate")
+ equipmentManagerPane.EquipSet:SetText(EQUIPSET_EQUIP)
+ equipmentManagerPane.EquipSet:Size(93, 22)
+ equipmentManagerPane.EquipSet:Point("TOPLEFT")
+ S:HandleButton(equipmentManagerPane.EquipSet)
+
+ equipmentManagerPane.EquipSet:SetScript("OnClick", function()
+ local selectedSetName = PaperDollEquipmentManagerPane.selectedSetName
+ if selectedSetName and selectedSetName ~= "" then
+ PlaySound("igCharacterInfoTab")
+ EquipmentManager_EquipSet(selectedSetName)
+ end
+ end)
+
+ equipmentManagerPane.SaveSet = CreateFrame("Button", "$parentSaveSet", equipmentManagerPane, "UIPanelButtonTemplate")
+ equipmentManagerPane.SaveSet:SetText(SAVE)
+ equipmentManagerPane.SaveSet:Size(94, 22)
+ equipmentManagerPane.SaveSet:Point("LEFT", "$parentEquipSet", "RIGHT", 3, 0)
+ S:HandleButton(equipmentManagerPane.SaveSet)
+
+ equipmentManagerPane.SaveSet:SetScript("OnClick", GearManagerDialogSaveSet_OnClick)
+
+ equipmentManagerPane.scrollBar = CreateFrame("Slider", "$parentScrollBar", equipmentManagerPane, "HybridScrollBarTemplate")
+ equipmentManagerPane.scrollBar:Point("TOPLEFT", equipmentManagerPane, "TOPRIGHT", 2, -16)
+ equipmentManagerPane.scrollBar:Point("BOTTOMLEFT", equipmentManagerPane, "BOTTOMRIGHT", 2, 14)
+ S:HandleScrollBar(equipmentManagerPane.scrollBar)
+ FixHybridScrollBarSkin(equipmentManagerPane)
+
+ CreateSmoothScrollAnimation(equipmentManagerPane.scrollBar, true)
+
+ equipmentManagerPane.scrollBar.Show = function(self)
+ equipmentManagerPane.EquipSet:Width(83)
+ equipmentManagerPane.SaveSet:Width(83)
+
+ equipmentManagerPane:Width(169)
+ equipmentManagerPane:Point("TOPRIGHT", CharacterFrame.backdrop, -29, -64)
+ for _, button in next, equipmentManagerPane.buttons do
+ button:Width(169)
+ end
+ getmetatable(self).__index.Show(self)
+ end
+
+ equipmentManagerPane.scrollBar.Hide = function(self)
+ equipmentManagerPane.EquipSet:Width(93)
+ equipmentManagerPane.SaveSet:Width(94)
+
+ equipmentManagerPane:Width(190)
+ equipmentManagerPane:Point("TOPRIGHT", CharacterFrame.backdrop, -8, -64)
+ for _, button in next, equipmentManagerPane.buttons do
+ button:Width(190)
+ end
+ getmetatable(self).__index.Hide(self)
+ end
+
+ equipmentManagerPane:SetFrameLevel(CharacterFrame:GetFrameLevel() + 1)
+ equipmentManagerPane.EquipSet:SetFrameLevel(equipmentManagerPane:GetFrameLevel() + 3)
+ equipmentManagerPane.SaveSet:SetFrameLevel(equipmentManagerPane:GetFrameLevel() + 3)
+
+ HybridScrollFrame_OnLoad(equipmentManagerPane)
+ equipmentManagerPane.update = self.PaperDollEquipmentManagerPane_Update
+ HybridScrollFrame_CreateButtons(equipmentManagerPane, "GearSetButtonTemplate2", 2, -(equipmentManagerPane.EquipSet:GetHeight() + 4))
+
+ equipmentManagerPane:RegisterEvent("EQUIPMENT_SWAP_FINISHED")
+ equipmentManagerPane:RegisterEvent("EQUIPMENT_SETS_CHANGED")
+ equipmentManagerPane:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
+ equipmentManagerPane:RegisterEvent("BAG_UPDATE")
+
+ equipmentManagerPane:SetScript("OnShow", function(self)
+ module:PaperDollEquipmentManagerPane_Update()
+ PaperDollFrameItemPopoutButton_ShowAll()
+ end)
+
+ equipmentManagerPane:SetScript("OnHide", function()
+ PaperDollFrame_ClearIgnoredSlots()
+ PaperDollFrameItemPopoutButton_HideAll()
+ GearManagerDialogPopup:Hide()
+ StaticPopup_Hide("CONFIRM_SAVE_EQUIPMENT_SET")
+ StaticPopup_Hide("CONFIRM_OVERWRITE_EQUIPMENT_SET")
+ end)
+
+ equipmentManagerPane:SetScript("OnEvent", function(self, event, ...)
+ if event == "EQUIPMENT_SWAP_FINISHED" then
+ local completed, setName = ...
+ if completed then
+ if self:IsShown() then
+ self.selectedSetName = setName
+ module:PaperDollEquipmentManagerPane_Update()
+ end
+ end
+ end
+
+ if self:IsShown() then
+ if event == "EQUIPMENT_SETS_CHANGED" then
+ module:PaperDollEquipmentManagerPane_Update()
+ elseif event == "PLAYER_EQUIPMENT_CHANGED" or event == "BAG_UPDATE" then
+ self.queuedUpdate = true
+ end
+ end
+ end)
+
+ equipmentManagerPane:SetScript("OnUpdate", function(self)
+ for i = 1, #self.buttons do
+ local button = self.buttons[i]
+ if button:IsMouseOver() then
+ if button.name then
+ button.DeleteButton:Show()
+ button.EditButton:Show()
+ else
+ button.DeleteButton:Hide()
+ button.EditButton:Hide()
+ end
+ button.HighlightBar:Show()
+ else
+ button.DeleteButton:Hide()
+ button.EditButton:Hide()
+ button.HighlightBar:Hide()
+ end
+ end
+ if self.queuedUpdate then
+ module:PaperDollEquipmentManagerPane_Update()
+ self.queuedUpdate = false
+ end
+ end)
+
+ GearManagerDialogPopup:SetParent(PaperDollFrame)
+ GearManagerDialogPopup:ClearAllPoints()
+ GearManagerDialogPopup:Point("BOTTOMLEFT", CharacterFrame.backdrop, "BOTTOMRIGHT", -6, -8)
+
+ --
+ -- Mystic Enchants Pane
+ --
+ local mysticEnchantPane = CreateFrame("ScrollFrame", "PaperDollMysticEnchantPane", PaperDollFrame, "HybridScrollFrameTemplate")
+ mysticEnchantPane:Hide()
+ mysticEnchantPane:Size(169, 350)
+ mysticEnchantPane.scrollBar = CreateFrame("Slider", "$parentScrollBar", mysticEnchantPane, "HybridScrollBarTemplate")
+ mysticEnchantPane.scrollBar:Point("TOPLEFT", mysticEnchantPane, "TOPRIGHT", 2, -16)
+ mysticEnchantPane.scrollBar:Point("BOTTOMLEFT", mysticEnchantPane, "BOTTOMRIGHT", 2, 14)
+ S:HandleScrollBar(mysticEnchantPane.scrollBar)
+ FixHybridScrollBarSkin(mysticEnchantPane)
+
+ CreateSmoothScrollAnimation(mysticEnchantPane.scrollBar, true)
+
+ mysticEnchantPane:SetScript("OnShow", function(self)
+ module:MysticEnchantPane_Update()
+ end)
+
+ mysticEnchantPane.scrollBar.Show = function(self)
+ mysticEnchantPane:Width(169)
+ mysticEnchantPane:Point("TOPRIGHT", CharacterFrame.backdrop, -29, -64)
+ for _, button in next, mysticEnchantPane.buttons do
+ button:Width(169)
+ end
+ getmetatable(self).__index.Show(self)
+ end
+
+ mysticEnchantPane.scrollBar.Hide = function(self)
+ mysticEnchantPane:Width(190)
+ mysticEnchantPane:Point("TOPRIGHT", CharacterFrame.backdrop, -8, -64)
+ for _, button in next, mysticEnchantPane.buttons do
+ button:Width(190)
+ end
+ getmetatable(self).__index.Hide(self)
+ end
+
+ mysticEnchantPane:SetFrameLevel(CharacterFrame:GetFrameLevel() + 1)
+
+ HybridScrollFrame_OnLoad(mysticEnchantPane)
+ mysticEnchantPane.update = self.MysticEnchantPane_Update
+ HybridScrollFrame_CreateButtons(PaperDollMysticEnchantPane, "MysticEnchantButtonTemplate2", 2, -4)
+
+
+ CharacterModelFrame:Size(237, 324)
+
+ if not E.private.enhanced.character.player.orderName2 then
+ E.private.enhanced.character.player.orderName2 = E.private.enhanced.character.player.orderName
+ E.private.enhanced.character.player.collapsedName2 = table.copy(E.private.enhanced.character.player.collapsedName)
+ end
+
+ local activeSpec = GetActiveTalentGroup()
+ if activeSpec == 1 then
+ self:PaperDoll_InitStatCategories(PAPERDOLL_STATCATEGORY_DEFAULTORDER, E.private.enhanced.character.player.orderName, E.private.enhanced.character.player.collapsedName, "player")
+ else
+ self:PaperDoll_InitStatCategories(PAPERDOLL_STATCATEGORY_DEFAULTORDER, E.private.enhanced.character.player.orderName2, E.private.enhanced.character.player.collapsedName2, "player")
+ end
+
+ PaperDollFrame:RegisterEvent("PLAYER_TALENT_UPDATE")
+ PaperDollFrame:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED")
+
+ PaperDollFrame:SetScript("OnEvent", function(self, event, unit)
+ if event == "PLAYER_ENTERING_WORLD" or (event == "UNIT_MODEL_CHANGED" and unit == "player") then
+ CharacterModelFrame:SetUnit("player")
+ return
+ elseif event == "KNOWN_TITLES_UPDATE" or (event == "UNIT_NAME_UPDATE" and unit == "player") then
+ if PaperDollTitlesPane:IsShown() then
+ module:PaperDollTitlesPane_Update()
+ end
+ end
+
+ if not self:IsVisible() then return end
+
+ if unit == "player" then
+ if event == "UNIT_LEVEL" then
+ module:PaperDollFrame_SetLevel()
+ elseif event == "UNIT_DAMAGE" or event == "PLAYER_DAMAGE_DONE_MODS" or event == "UNIT_ATTACK_SPEED" or event == "UNIT_RANGEDDAMAGE" or event == "UNIT_ATTACK" or event == "UNIT_STATS" or event == "UNIT_RANGED_ATTACK_POWER" or event == "UNIT_RESISTANCES" then
+ self:SetScript("OnUpdate", PaperDollFrame_QueuedUpdate)
+ end
+ end
+
+ if event == "COMBAT_RATING_UPDATE" then
+ self:SetScript("OnUpdate", PaperDollFrame_QueuedUpdate)
+ elseif event == "PLAYER_TALENT_UPDATE" then
+ module:PaperDollFrame_SetLevel()
+ elseif event == "ACTIVE_TALENT_GROUP_CHANGED" then
+ if GetActiveTalentGroup() == 1 then
+ module:PaperDoll_InitStatCategories(PAPERDOLL_STATCATEGORY_DEFAULTORDER, E.private.enhanced.character.player.orderName, E.private.enhanced.character.player.collapsedName, "player")
+ else
+ module:PaperDoll_InitStatCategories(PAPERDOLL_STATCATEGORY_DEFAULTORDER, E.private.enhanced.character.player.orderName2, E.private.enhanced.character.player.collapsedName2, "player")
+ end
+ end
+ end)
+
+ PaperDollFrame:SetScript("OnShow", function()
+ module:PaperDollFrame_SetLevel()
+
+ -- Include Hit Rating Adjustments
+ C_Cache:QueryAllStats()
+
+ if UnitHasRelicSlot("player") then
+ CharacterAmmoSlot:Hide()
+ else
+ CharacterAmmoSlot:Show()
+ end
+
+ if PaperDollFrame.currentSideBarID == 2 then
+ module:PaperDollTitlesPane_Update()
+ end
+
+ if GetActiveTalentGroup() == 1 then
+ module:PaperDoll_InitStatCategories(PAPERDOLL_STATCATEGORY_DEFAULTORDER, E.private.enhanced.character.player.orderName, E.private.enhanced.character.player.collapsedName, "player")
+ else
+ module:PaperDoll_InitStatCategories(PAPERDOLL_STATCATEGORY_DEFAULTORDER, E.private.enhanced.character.player.orderName2, E.private.enhanced.character.player.collapsedName2, "player")
+ end
+
+ if E.private.enhanced.character.collapsed then
+ module:CharacterFrame_Collapse()
+ else
+ module:CharacterFrame_Expand()
+ end
+
+ CharacterFrameExpandButton:Show()
+ CharacterFrameExpandButton.collapseTooltip = L["Hide Character Information"]
+ CharacterFrameExpandButton.expandTooltip = L["Show Character Information"]
+ end)
+
+ PaperDollFrame:SetScript("OnHide", function(self)
+ module:CharacterFrame_Collapse()
+ CharacterFrameExpandButton:Hide()
+ if MOVING_STAT_CATEGORY then
+ PaperDollStatCategory_OnDragStop(MOVING_STAT_CATEGORY)
+ end
+ end)
+
+ hooksecurefunc("PaperDollFrame_UpdateStats", function() module:PaperDollFrame_UpdateStats() end)
+end
+
+do -- PetFrame
+ PetNameText:ClearAllPoints()
+ PetNameText:Point("CENTER", CharacterFrame.backdrop, 0, 200)
+
+ PetLevelText:ClearAllPoints()
+ PetLevelText:Point("TOP", CharacterFrame.backdrop, 0, -20)
+
+ PetPaperDollCloseButton:Kill()
+ PetAttributesFrame:Kill()
+ PetResistanceFrame:Kill()
+
+ PetModelFrame:Size(325, 324)
+ PetModelFrame:Point("TOPLEFT", 19, -76)
+
+ PetModelFrameRotateLeftButton:Point("TOPLEFT", PetPaperDollFrame, "TOPLEFT", 23, -80)
+
+ PetPaperDollFrameExpBar:Width(297)
+ PetPaperDollFrameExpBar:Point("BOTTOMLEFT", 20, 88)
+
+ self:PaperDoll_InitStatCategories(PETPAPERDOLL_STATCATEGORY_DEFAULTORDER, E.private.enhanced.character.pet.orderName, E.private.enhanced.character.pet.collapsedName, "pet")
+
+ PetPaperDollFrame:SetScript("OnEvent", function(self, event, unit)
+ if event == "PET_UI_UPDATE" or event == "PET_UI_CLOSE" or event == "PET_BAR_UPDATE"
+ or (event == "UNIT_PET" and unit == "player")
+ or (event == "UNIT_NAME_UPDATE" and unit == "pet") then
+ PetPaperDollFrame_UpdateTabs()
+
+ if self:IsVisible() then
+ self:SetScript("OnUpdate", PetPaperDollFrame_QueuedUpdate)
+ end
+ elseif event == "UNIT_PET_EXPERIENCE" then
+ PetExpBar_Update()
+ elseif event == "COMPANION_UPDATE" then
+ if not PetPaperDollFrameCompanionFrame.idMount then
+ PetPaperDollFrameCompanionFrame.idMount = GetCompanionInfo("MOUNT", 1)
+ end
+ if not PetPaperDollFrameCompanionFrame.idCritter then
+ PetPaperDollFrameCompanionFrame.idCritter = GetCompanionInfo("CRITTER", 1)
+ end
+
+ if PetPaperDollFrameCompanionFrame:IsVisible() then
+ module:PetPaperDollCompanionPane_Update()
+ end
+ elseif event == "COMPANION_LEARNED" then
+ if not CharacterFrame:IsVisible() then
+ SetButtonPulse(CharacterMicroButton, 60, 1)
+ end
+ if not PetPaperDollFrame:IsVisible() then
+ SetButtonPulse(CharacterFrameTab2, 60, 1)
+ end
+
+ if self:IsVisible() then
+ PetPaperDollFrame_UpdateTabs()
+ module:PetPaperDollCompanionPane_Update()
+ end
+ elseif event == "COMPANION_UNLEARNED" then
+ if self:IsVisible() then
+ PetPaperDollFrame_UpdateTabs()
+ module:PetPaperDollCompanionPane_Update()
+ end
+ elseif event == "SPELL_UPDATE_COOLDOWN" then
+ if PetPaperDollFrameCompanionFrame:IsVisible() then
+ PetPaperDollFrame_UpdateCompanionCooldowns()
+ end
+ elseif ((event == "UNIT_ENTERED_VEHICLE" or event == "UNIT_EXITED_VEHICLE") and unit == "player") then
+ module:PetPaperDollCompanionPane_Update()
+ elseif event == "PET_SPELL_POWER_UPDATE" then
+ if self:IsVisible() then
+ self:SetScript("OnUpdate", PetPaperDollFrame_QueuedUpdate)
+ end
+ elseif unit == "pet" then
+ if self:IsVisible() then
+ self:SetScript("OnUpdate", PetPaperDollFrame_QueuedUpdate)
+ end
+ end
+ end)
+
+ PetPaperDollFramePetFrame:HookScript("OnShow", function()
+ if E.private.enhanced.character.collapsed then
+ module:CharacterFrame_Collapse()
+ else
+ module:CharacterFrame_Expand()
+ end
+
+ CharacterFrameExpandButton:Show()
+ CharacterFrameExpandButton.collapseTooltip = L["Hide Pet Information"]
+ CharacterFrameExpandButton.expandTooltip = L["Show Pet Information"]
+
+ module:PaperDoll_InitStatCategories(PETPAPERDOLL_STATCATEGORY_DEFAULTORDER, E.private.enhanced.character.pet.orderName, E.private.enhanced.character.pet.collapsedName, "pet")
+
+ module:PaperDollFrame_UpdateStats()
+ end)
+
+ PetPaperDollFramePetFrame:HookScript("OnHide", function()
+ if PaperDollFrame:IsShown() then return end
+
+ module:CharacterFrame_Collapse()
+ CharacterFrameExpandButton:Hide()
+ end)
+end
+
+do -- CompanionFrame
+ CompanionModelFrame:Size(325, 352)
+ CompanionModelFrame:Point("TOPLEFT", 19, -76)
+
+ CompanionModelFrameRotateLeftButton:Point("TOPLEFT", PetPaperDollFrame, "TOPLEFT", 23, -80)
+
+ CompanionSelectedName:ClearAllPoints()
+ CompanionSelectedName:Point("BOTTOM", CompanionModelFrame, "BOTTOM", 0, 10)
+ CompanionSelectedName:SetParent(CompanionModelFrame)
+ CompanionSelectedName:SetTextColor(1, 1, 1)
+
+ CompanionPageNumber:Kill()
+ CompanionSummonButton:Kill()
+ for i = 1, 12 do
+ _G["CompanionButton"..i]:Kill()
+ _G["CompanionButton"..i].Disable = E.noop
+ _G["CompanionButton"..i].Enable = E.noop
+ end
+ CompanionPrevPageButton:Kill()
+ CompanionNextPageButton:Kill()
+
+ local companionPane = CreateFrame("ScrollFrame", "PetPaperDollCompanionPane", PetPaperDollFrameCompanionFrame, "HybridScrollFrameTemplate")
+ companionPane:Hide()
+ companionPane:Size(169, 350)
+ companionPane:Point("TOPRIGHT", CharacterFrame.backdrop, -29, -64)
+
+ companionPane.text = companionPane:CreateFontString(nil, "OVERLAY")
+ companionPane.text:Size(169, 20)
+ companionPane.text:Point("BOTTOM", PetPaperDollCompanionPane, "TOP", 0, 7)
+ companionPane.text:FontTemplate()
+
+ companionPane.scrollBar = CreateFrame("Slider", "$parentScrollBar", companionPane, "HybridScrollBarTemplate")
+ companionPane.scrollBar:Point("TOPLEFT", companionPane, "TOPRIGHT", 2, -16)
+ companionPane.scrollBar:Point("BOTTOMLEFT", companionPane, "BOTTOMRIGHT", 2, 14)
+ S:HandleScrollBar(companionPane.scrollBar)
+ FixHybridScrollBarSkin(companionPane)
+
+ CreateSmoothScrollAnimation(companionPane.scrollBar, true)
+
+ companionPane.scrollBar.Show = function(self)
+ companionPane:Width(169)
+ companionPane:Point("TOPRIGHT", CharacterFrame.backdrop, -29, -64)
+ for _, button in next, companionPane.buttons do
+ button:Width(169)
+ end
+ getmetatable(self).__index.Show(self)
+ end
+
+ companionPane.scrollBar.Hide = function(self)
+ companionPane:Width(190)
+ companionPane:Point("TOPRIGHT", CharacterFrame.backdrop, -8, -64)
+ for _, button in next, companionPane.buttons do
+ button:Width(190)
+ end
+ getmetatable(self).__index.Hide(self)
+ end
+
+ companionPane.update = self.PetPaperDollCompanionPane_Update
+ HybridScrollFrame_CreateButtons(companionPane, "CompanionButtonTemplate2", 2)
+
+ PetPaperDollFrameCompanionFrame:HookScript("OnShow", function(self)
+ if not CharacterFrame.Expanded then
+ module:CharacterFrame_Expand(true)
+ end
+ module:PetPaperDollCompanionPane_Update()
+ end)
+
+ PetPaperDollFrameCompanionFrame:HookScript("OnHide", function(self)
+ if PaperDollFrame:IsShown() or PetPaperDollFramePetFrame:IsShown() then return end
+ module:CharacterFrame_Collapse(true)
+ end)
+end
+
+ hooksecurefunc("PetPaperDollFrame_SetTab", function(id)
+ if id == 1 and HasPetUI() then
+ PetPaperDollCompanionPane:Hide()
+ elseif (id == 2 and GetNumCompanions("CRITTER") > 0)
+ or (id == 3 and GetNumCompanions("MOUNT") > 0)
+ then
+ PetPaperDollCompanionPane:Show()
+ module:PetPaperDollCompanionPane_Update()
+ end
+ end)
+
+ self.Initialized = true
+
+ self:UpdateCharacterModelFrame()
+ self:UpdatePetModelFrame()
+ self:UpdateCompanionModelFrame()
+
+ self:RegisterEvent("ADDON_LOADED", function(event, addon)
+ if addon == "Blizzard_InspectUI" then
+ module:UnregisterEvent(event)
+ module:SecureHook("InspectFrame_UpdateTalentTab", "UpdateInspectModelFrame")
+ end
+ end)
+end
+
+local function InitializeCallback()
+ module:Initialize()
+end
+
+E:RegisterModule(module:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/CharacterFrame.xml b/ElvUI_Enhanced/Modules/Blizzard/CharacterFrame.xml
new file mode 100644
index 0000000..222ee9d
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/CharacterFrame.xml
@@ -0,0 +1,414 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PaperDollStatTooltip("player")
+
+
+ GameTooltip:Hide()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:CreateBackdrop("Default")
+ self.backdrop:SetOutside(self.icon)
+ self.icon:SetParent(self.backdrop)
+
+
+ if self.enchant then
+ local RE = GetREData(self.enchant)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
+ GameTooltip:SetHyperlink("spell:"..RE.spellID)
+ GameTooltip:Show()
+ end
+
+
+ GameTooltip:Hide()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.Stripe:SetInside()
+ self.HighlightBar:SetInside()
+ self.SelectedBar:SetInside()
+ CompanionButton_OnLoad(self)
+ self:CreateBackdrop("Default")
+ self.backdrop:SetOutside(self.icon)
+ _G[self:GetName() .. "Cooldown"]:SetInside(self.icon)
+ _G[self:GetName() .. "Cooldown"]:SetParent(self.backdrop)
+ self.icon:SetParent(self.backdrop)
+
+
+ if IsModifiedClick() then
+ CompanionButton_OnModifiedClick(self, button)
+ else
+ local selected, selectedID
+ if PetPaperDollFrameCompanionFrame.mode == "CRITTER" then
+ selected = PetPaperDollFrame_FindCompanionIndex(PetPaperDollFrameCompanionFrame.idCritter)
+ selectedID = PetPaperDollFrameCompanionFrame.idCritter
+ elseif PetPaperDollFrameCompanionFrame.mode == "MOUNT" then
+ selected = PetPaperDollFrame_FindCompanionIndex(PetPaperDollFrameCompanionFrame.idMount)
+ selectedID = PetPaperDollFrameCompanionFrame.idMount
+ end
+
+ if button ~= "LeftButton" or selectedID == self.creatureID then
+ local index = self:GetID()
+ if self.active then
+ DismissCompanion(PetPaperDollFrameCompanionFrame.mode)
+ else
+ CallCompanion(PetPaperDollFrameCompanionFrame.mode, index)
+ end
+ else
+ if PetPaperDollFrameCompanionFrame.mode == "CRITTER" then
+ PetPaperDollFrameCompanionFrame.idCritter = self.creatureID
+ PetPaperDollFrame_UpdateCompanionPreview()
+ elseif PetPaperDollFrameCompanionFrame.mode == "MOUNT" then
+ PetPaperDollFrameCompanionFrame.idMount = self.creatureID
+ PetPaperDollFrame_UpdateCompanionPreview()
+ end
+ end
+
+ ElvUI[1]:GetModule("Enhanced_CharacterFrame"):PetPaperDollCompanionPane_Update()
+ end
+ PlaySound("igMainMenuOptionCheckBoxOn")
+
+
+ PickupCompanion(PetPaperDollFrameCompanionFrame.mode, self:GetID())
+
+
+ PickupCompanion(PetPaperDollFrameCompanionFrame.mode, self:GetID())
+
+
+ CompanionButton_OnEnter(self, motion)
+ self.HighlightBar:Show()
+
+
+ GameTooltip:Hide()
+ self.HighlightBar:Hide()
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/DeathRecap.lua b/ElvUI_Enhanced/Modules/Blizzard/DeathRecap.lua
new file mode 100644
index 0000000..4553822
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/DeathRecap.lua
@@ -0,0 +1,592 @@
+local E, L, V, P, G = unpack(ElvUI)
+local mod = E:GetModule("Enhanced_Blizzard")
+
+local _G = _G
+local select = select
+local tonumber = tonumber
+local unpack = unpack
+local band = bit.band
+local ceil, floor = math.ceil, math.floor
+local format, upper, split, sub = string.format, string.upper, string.split, string.sub
+local tsort, twipe = table.sort, table.wipe
+
+local CannotBeResurrected = CannotBeResurrected
+local CopyTable = CopyTable
+local CreateFrame = CreateFrame
+local GetReleaseTimeRemaining = GetReleaseTimeRemaining
+local GetSpellInfo = GetSpellInfo
+local GetSpellLink = GetSpellLink
+local HasSoulstone = HasSoulstone
+local IsActiveBattlefieldArena = IsActiveBattlefieldArena
+local IsFalling = IsFalling
+local IsOutOfBounds = IsOutOfBounds
+local RepopMe = RepopMe
+local UnitHealth = UnitHealth
+local UnitHealthMax = UnitHealthMax
+local UseSoulstone = UseSoulstone
+
+local ACTION_SWING = ACTION_SWING
+local ARENA_SPECTATOR = ARENA_SPECTATOR
+local COMBATLOG_FILTER_ME = COMBATLOG_FILTER_ME
+local COMBATLOG_UNKNOWN_UNIT = COMBATLOG_UNKNOWN_UNIT
+local DEATH_RELEASE_NOTIMER = DEATH_RELEASE_NOTIMER
+local DEATH_RELEASE_SPECTATOR = DEATH_RELEASE_SPECTATOR
+local DEATH_RELEASE_TIMER = DEATH_RELEASE_TIMER
+local MINUTES = MINUTES
+local SECONDS = SECONDS
+local TEXT_MODE_A_STRING_VALUE_SCHOOL = TEXT_MODE_A_STRING_VALUE_SCHOOL
+
+local lastDeathEvents
+local index = 0
+local deathList = {}
+local eventList = {}
+
+local function AddEvent(timestamp, event, sourceName, spellId, spellName, environmentalType, amount, overkill, school, resisted, blocked, absorbed)
+ if index > 0 and eventList[index].timestamp + 10 <= timestamp then
+ index = 0
+ twipe(eventList)
+ end
+
+ if index < 5 then
+ index = index + 1
+ else
+ index = 1
+ end
+
+ if not eventList[index] then
+ eventList[index] = {}
+ else
+ twipe(eventList[index])
+ end
+
+ eventList[index].timestamp = timestamp
+ eventList[index].event = event
+ eventList[index].sourceName = sourceName
+ eventList[index].spellId = spellId
+ eventList[index].spellName = spellName
+ eventList[index].environmentalType = environmentalType
+ eventList[index].amount = amount
+ eventList[index].overkill = overkill
+ eventList[index].school = school
+ eventList[index].resisted = resisted
+ eventList[index].blocked = blocked
+ eventList[index].absorbed = absorbed
+ eventList[index].currentHP = UnitHealth("player")
+ eventList[index].maxHP = UnitHealthMax("player")
+end
+
+local function HasEvents()
+ if lastDeathEvents then
+ return #deathList > 0, #deathList
+ else
+ return false, #deathList
+ end
+end
+
+local function EraseEvents()
+ if index > 0 then
+ index = 0
+ twipe(eventList)
+ end
+end
+
+local function AddDeath()
+ if #eventList > 0 then
+ local _, deathEvents = HasEvents()
+ local deathIndex = deathEvents + 1
+ deathList[deathIndex] = CopyTable(eventList)
+ EraseEvents()
+
+ DEFAULT_CHAT_FRAME:AddMessage("|cff71d5ff|Hdeath:"..deathIndex.."|h["..L["You died."].."]|h|r")
+
+ return true
+ end
+end
+
+local function GetDeathEvents(recapID)
+ if recapID and deathList[recapID] then
+ local deathEvents = deathList[recapID]
+ tsort(deathEvents, function(a, b) return a.timestamp > b.timestamp end)
+ return deathEvents
+ end
+end
+
+local function GetTableInfo(data)
+ local texture
+ local nameIsNotSpell = false
+
+ local event = data.event
+ local spellId = data.spellId
+ local spellName = data.spellName
+
+ if event == "SWING_DAMAGE" then
+ spellId = 6603
+ spellName = ACTION_SWING
+
+ nameIsNotSpell = true
+ elseif event == "RANGE_DAMAGE" then
+ nameIsNotSpell = true
+-- elseif sub(event, 1, 5) == "SPELL" then
+ elseif event == "ENVIRONMENTAL_DAMAGE" then
+ local environmentalType = data.environmentalType
+ environmentalType = upper(environmentalType)
+ spellName = _G["ACTION_ENVIRONMENTAL_DAMAGE_"..environmentalType]
+ nameIsNotSpell = true
+
+ if environmentalType == "DROWNING" then
+ texture = "spell_shadow_demonbreath"
+ elseif environmentalType == "FALLING" then
+ texture = "ability_rogue_quickrecovery"
+ elseif environmentalType == "FIRE" or environmentalType == "LAVA" then
+ texture = "spell_fire_fire"
+ elseif environmentalType == "SLIME" then
+ texture = "inv_misc_slime_01"
+ elseif environmentalType == "FATIGUE" then
+ texture = "ability_creature_cursed_05"
+ else
+ texture = "ability_creature_cursed_05"
+ end
+
+ texture = "Interface\\Icons\\" .. texture
+ end
+
+ if spellName and nameIsNotSpell then
+ spellName = format("|Haction:%s|h%s|h", event, spellName)
+ end
+
+ if spellId and not texture then
+ texture = select(3, GetSpellInfo(spellId))
+ end
+
+ return spellId, spellName, texture
+end
+
+local function OpenRecap(recapID)
+ local self = ElvUI_DeathRecapFrame
+
+ if self:IsShown() and self.recapID == recapID then
+ self:Hide()
+ return
+ end
+
+ local deathEvents = GetDeathEvents(recapID)
+ if not deathEvents then return end
+
+ self.recapID = recapID
+ self:Show()
+
+ if not deathEvents or #deathEvents <= 0 then
+ for i = 1, 5 do
+ self.DeathRecapEntry[i]:Hide()
+ end
+
+ self.Unavailable:Show()
+
+ return
+ end
+
+ self.Unavailable:Hide()
+
+ local highestDmgIdx, highestDmgAmount = 1, 0
+ self.DeathTimeStamp = nil
+
+ for i = 1, #deathEvents do
+ local entry = self.DeathRecapEntry[i]
+ local dmgInfo = entry.DamageInfo
+ local evtData = deathEvents[i]
+ local spellId, spellName, texture = GetTableInfo(evtData)
+
+ entry:Show()
+ self.DeathTimeStamp = self.DeathTimeStamp or evtData.timestamp
+
+ if evtData.amount then
+ local amountStr = -evtData.amount
+ dmgInfo.Amount:SetText(amountStr)
+ dmgInfo.AmountLarge:SetText(amountStr)
+ dmgInfo.amount = evtData.amount
+
+ dmgInfo.dmgExtraStr = ""
+ if evtData.overkill and evtData.overkill > 0 then
+ dmgInfo.dmgExtraStr = format(L["(%d Overkill)"], evtData.overkill)
+ dmgInfo.amount = evtData.amount - evtData.overkill
+ end
+ if evtData.absorbed and evtData.absorbed > 0 then
+ dmgInfo.dmgExtraStr = dmgInfo.dmgExtraStr.." "..format(L["(%d Absorbed)"], evtData.absorbed)
+ dmgInfo.amount = evtData.amount - evtData.absorbed
+ end
+ if evtData.resisted and evtData.resisted > 0 then
+ dmgInfo.dmgExtraStr = dmgInfo.dmgExtraStr.." "..format(L["(%d Resisted)"], evtData.resisted)
+ dmgInfo.amount = evtData.amount - evtData.resisted
+ end
+ if evtData.blocked and evtData.blocked > 0 then
+ dmgInfo.dmgExtraStr = dmgInfo.dmgExtraStr.." "..format(L["(%d Blocked)"], evtData.blocked)
+ dmgInfo.amount = evtData.amount - evtData.blocked
+ end
+
+ if evtData.amount > highestDmgAmount then
+ highestDmgIdx = i
+ highestDmgAmount = evtData.amount
+ end
+
+ dmgInfo.Amount:Show()
+ dmgInfo.AmountLarge:Hide()
+ else
+ dmgInfo.Amount:SetText("")
+ dmgInfo.AmountLarge:SetText("")
+ dmgInfo.amount = nil
+ dmgInfo.dmgExtraStr = nil
+ end
+
+ dmgInfo.timestamp = evtData.timestamp
+ dmgInfo.hpPercent = floor(evtData.currentHP / evtData.maxHP * 100)
+
+ dmgInfo.spellName = spellName
+
+ dmgInfo.caster = evtData.sourceName or COMBATLOG_UNKNOWN_UNIT
+
+ if evtData.school and evtData.school > 1 then
+ local colorArray = CombatLog_Color_ColorArrayBySchool(evtData.school)
+ entry.SpellInfo.FrameIcon:SetBackdropBorderColor(colorArray.r, colorArray.g, colorArray.b)
+ else
+ entry.SpellInfo.FrameIcon:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+
+ dmgInfo.school = evtData.school
+
+ entry.SpellInfo.Caster:SetText(dmgInfo.caster)
+
+ entry.SpellInfo.Name:SetText(spellName)
+ entry.SpellInfo.Icon:SetTexture(texture)
+
+ entry.SpellInfo.spellId = spellId
+ end
+
+ for i = #deathEvents + 1, #self.DeathRecapEntry do
+ self.DeathRecapEntry[i]:Hide()
+ end
+
+ local entry = self.DeathRecapEntry[highestDmgIdx]
+ if entry.DamageInfo.amount then
+ entry.DamageInfo.Amount:Hide()
+ entry.DamageInfo.AmountLarge:Show()
+ end
+
+ local deathEntry = self.DeathRecapEntry[1]
+ local tombstoneIcon = deathEntry.tombstone
+ if entry == deathEntry then
+ tombstoneIcon:Point("RIGHT", deathEntry.DamageInfo.AmountLarge, "LEFT", -10, 0)
+ end
+end
+
+local function Spell_OnEnter(self)
+ if self.spellId then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
+ GameTooltip:SetHyperlink(GetSpellLink(self.spellId))
+ GameTooltip:Show()
+ end
+end
+
+local function Amount_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT")
+ GameTooltip:ClearLines()
+
+ if self.amount then
+ local valueStr = self.school and format(TEXT_MODE_A_STRING_VALUE_SCHOOL, self.amount, CombatLog_String_SchoolString(self.school)) or self.amount
+ GameTooltip:AddLine(format(L["%s %s"], valueStr, self.dmgExtraStr), 1, 0, 0, false)
+ end
+
+ if self.spellName then
+ if self.caster then
+ GameTooltip:AddLine(format(L["%s by %s"], self.spellName, self.caster), 1, 1, 1, true)
+ else
+ GameTooltip:AddLine(self.spellName, 1, 1, 1, true)
+ end
+ end
+
+ local seconds = ElvUI_DeathRecapFrame.DeathTimeStamp - self.timestamp
+ if seconds > 0 then
+ GameTooltip:AddLine(format(L["%s sec before death at %s%% health."], format("%.1F", seconds), self.hpPercent), 1, 0.824, 0, true)
+ else
+ GameTooltip:AddLine(format(L["Killing blow at %s%% health."], self.hpPercent), 1, 0.824, 0, true)
+ end
+
+ GameTooltip:Show()
+end
+
+function mod:HideDeathPopup()
+ E:StaticPopup_Hide("DEATH")
+end
+
+function mod:PLAYER_DEAD()
+ if StaticPopup_FindVisible("DEATH") then
+ if AddDeath() then
+ lastDeathEvents = true
+ else
+ lastDeathEvents = false
+ end
+
+ StaticPopup_Hide("DEATH")
+ E:StaticPopup_Show("DEATH", GetReleaseTimeRemaining(), SECONDS)
+ end
+end
+
+function mod:COMBAT_LOG_EVENT_UNFILTERED(_, timestamp, event, _, sourceName, sourceFlags, destGUID, destName, destFlags, ...)
+ if (band(destFlags, COMBATLOG_FILTER_ME) ~= COMBATLOG_FILTER_ME) or (band(sourceFlags, COMBATLOG_FILTER_ME) == COMBATLOG_FILTER_ME) then return end
+ if event ~= "ENVIRONMENTAL_DAMAGE"
+ and event ~= "RANGE_DAMAGE"
+ and event ~= "SPELL_DAMAGE"
+ and event ~= "SPELL_EXTRA_ATTACKS"
+ and event ~= "SPELL_INSTAKILL"
+ and event ~= "SPELL_PERIODIC_DAMAGE"
+ and event ~= "SWING_DAMAGE"
+ then return end
+
+ local subVal = sub(event, 1, 5)
+ local environmentalType, spellId, spellName, amount, overkill, school, resisted, blocked, absorbed
+
+ if event == "SWING_DAMAGE" then
+ amount, overkill, school, resisted, blocked, absorbed = ...
+ elseif subVal == "SPELL" then
+ spellId, spellName, _, amount, overkill, school, resisted, blocked, absorbed = ...
+ elseif event == "ENVIRONMENTAL_DAMAGE" then
+ environmentalType, amount, overkill, school, resisted, blocked, absorbed = ...
+ end
+
+ if not tonumber(amount) then return end
+
+ AddEvent(timestamp, event, sourceName, spellId, spellName, environmentalType, amount, overkill, school, resisted, blocked, absorbed)
+end
+
+function mod:SetItemRef(link, ...)
+ if sub(link, 1, 5) == "death" then
+ local _, id = split(":", link)
+ OpenRecap(tonumber(id))
+ return
+ else
+ self.hooks.SetItemRef(link, ...)
+ end
+end
+
+function mod:DeathRecap()
+ if DeathRecapFrame then return end
+ if not E.private.enhanced.deathRecap then return end
+
+ local S = E:GetModule("Skins")
+
+ local frame = CreateFrame("Frame", "ElvUI_DeathRecapFrame", UIParent)
+ frame:Size(340, 326)
+ frame:Point("CENTER")
+ frame:SetTemplate("Transparent")
+ frame:SetMovable(true)
+ frame:Hide()
+ frame:SetScript("OnHide", function(self) self.recapID = nil end)
+ tinsert(UISpecialFrames, frame:GetName())
+
+ frame.Title = frame:CreateFontString("ARTWORK", nil, "GameFontNormal")
+ frame.Title:Point("TOPLEFT", 12, -9)
+ frame.Title:SetText(L["Death Recap"])
+
+ frame.Unavailable = frame:CreateFontString("ARTWORK", nil, "GameFontNormal")
+ frame.Unavailable:Point("CENTER")
+ frame.Unavailable:SetText(L["Death Recap unavailable."])
+
+ frame.CloseXButton = CreateFrame("Button", "$parentCloseXButton", frame)
+ frame.CloseXButton:Size(32, 32)
+ frame.CloseXButton:Point("TOPRIGHT", 2, 1)
+ frame.CloseXButton:SetScript("OnClick", function(self) self:GetParent():Hide() end)
+ S:HandleCloseButton(frame.CloseXButton)
+
+ frame.DragButton = CreateFrame("Button", "$parentDragButton", frame)
+ frame.DragButton:Point("TOPLEFT", 0, 0)
+ frame.DragButton:Point("BOTTOMRIGHT", frame, "TOPRIGHT", 0, -32)
+ frame.DragButton:RegisterForDrag("LeftButton")
+ frame.DragButton:SetScript("OnDragStart", function(self) self:GetParent():StartMoving() end)
+ frame.DragButton:SetScript("OnDragStop", function(self) self:GetParent():StopMovingOrSizing() end)
+
+ frame.DeathRecapEntry = {}
+
+ for i = 1, 5 do
+ local button = CreateFrame("Frame", nil, frame)
+ button:Size(308, 32)
+ frame.DeathRecapEntry[i] = button
+
+ button.DamageInfo = CreateFrame("Button", nil, button)
+ button.DamageInfo:Point("TOPLEFT", 0, 0)
+ button.DamageInfo:Point("BOTTOMRIGHT", button, "BOTTOMLEFT", 80, 0)
+ button.DamageInfo:SetScript("OnEnter", Amount_OnEnter)
+ button.DamageInfo:SetScript("OnLeave", GameTooltip_Hide)
+
+ button.DamageInfo.Amount = button.DamageInfo:CreateFontString("ARTWORK", nil, "GameFontNormalRight")
+ button.DamageInfo.Amount:SetJustifyH("RIGHT")
+ button.DamageInfo.Amount:SetJustifyV("CENTER")
+ button.DamageInfo.Amount:Size(0, 32)
+ button.DamageInfo.Amount:Point("TOPRIGHT", 0, 0)
+ button.DamageInfo.Amount:SetTextColor(0.75, 0.05, 0.05, 1)
+
+ button.DamageInfo.AmountLarge = button.DamageInfo:CreateFontString("ARTWORK", nil, "NumberFont_Outline_Large")
+ button.DamageInfo.AmountLarge:SetJustifyH("RIGHT")
+ button.DamageInfo.AmountLarge:SetJustifyV("CENTER")
+ button.DamageInfo.AmountLarge:Size(0, 32)
+ button.DamageInfo.AmountLarge:Point("TOPRIGHT", 0, 0)
+ button.DamageInfo.AmountLarge:SetTextColor(1, 0.07, 0.07, 1)
+
+ button.SpellInfo = CreateFrame("Button", nil, button)
+ button.SpellInfo:Point("TOPLEFT", button.DamageInfo, "TOPRIGHT", 16, 0)
+ button.SpellInfo:Point("BOTTOMRIGHT", 0, 0)
+ button.SpellInfo:SetScript("OnEnter", Spell_OnEnter)
+ button.SpellInfo:SetScript("OnLeave", GameTooltip_Hide)
+
+ button.SpellInfo.FrameIcon = CreateFrame("Button", nil, button.SpellInfo)
+ button.SpellInfo.FrameIcon:Size(34, 34)
+ button.SpellInfo.FrameIcon:Point("LEFT", 0, 0)
+ button.SpellInfo.FrameIcon:SetTemplate("Default")
+
+ button.SpellInfo.Icon = button.SpellInfo:CreateTexture("ARTWORK")
+ button.SpellInfo.Icon:SetParent(button.SpellInfo.FrameIcon)
+ button.SpellInfo.Icon:SetTexCoord(unpack(E.TexCoords))
+ button.SpellInfo.Icon:SetInside()
+
+ button.SpellInfo.Name = button.SpellInfo:CreateFontString("ARTWORK", nil, "GameFontNormal")
+ button.SpellInfo.Name:SetJustifyH("LEFT")
+ button.SpellInfo.Name:SetJustifyV("BOTTOM")
+ button.SpellInfo.Name:Point("BOTTOMLEFT", button.SpellInfo.Icon, "RIGHT", 8, 1)
+ button.SpellInfo.Name:Point("TOPRIGHT", 0, 0)
+
+ button.SpellInfo.Caster = button.SpellInfo:CreateFontString("ARTWORK", nil, "SystemFont_Shadow_Small")
+ button.SpellInfo.Caster:SetJustifyH("LEFT")
+ button.SpellInfo.Caster:SetJustifyV("TOP")
+ button.SpellInfo.Caster:Point("TOPLEFT", button.SpellInfo.Icon, "RIGHT", 8, -2)
+ button.SpellInfo.Caster:Point("BOTTOMRIGHT", 0, 0)
+ button.SpellInfo.Caster:SetTextColor(0.5, 0.5, 0.5, 1)
+
+ if i == 1 then
+ button:Point("BOTTOMLEFT", 16, 64)
+ button.tombstone = button:CreateTexture("ARTWORK")
+ button.tombstone:Size(15, 20)
+ button.tombstone:Point("RIGHT", button.DamageInfo.Amount, "LEFT", -10, 0)
+ button.tombstone:SetTexCoord(0.658203125, 0.6875, 0.00390625, 0.08203125)
+ button.tombstone:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\media\\textures\\DeathRecap")
+ else
+ button:Point("BOTTOM", frame.DeathRecapEntry[i - 1], "TOP", 0, 14)
+ end
+ end
+
+ frame.CloseButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
+ frame.CloseButton:Size(144, 21)
+ frame.CloseButton:Point("BOTTOM", 0, 15)
+ frame.CloseButton:SetText(CLOSE)
+ frame.CloseButton:SetScript("OnClick", function(self) ElvUI_DeathRecapFrame:Hide() end)
+ S:HandleButton(frame.CloseButton)
+
+ self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+ self:RegisterEvent("PLAYER_DEAD")
+ self:RegisterEvent("PLAYER_ENTERING_WORLD", "HideDeathPopup")
+ self:RegisterEvent("RESURRECT_REQUEST", "HideDeathPopup")
+ self:RegisterEvent("PLAYER_ALIVE", "HideDeathPopup")
+ self:RegisterEvent("RAISED_AS_GHOUL", "HideDeathPopup")
+
+ self:RawHook("SetItemRef", true)
+
+ E.PopupDialogs["DEATH"] = {
+ text = DEATH_RELEASE_TIMER,
+ button1 = DEATH_RELEASE,
+ button2 = USE_SOULSTONE,
+ button3 = L["Death Recap"],
+ OnShow = function(self)
+ self.timeleft = GetReleaseTimeRemaining()
+ local text = HasSoulstone()
+ if text then
+ self.button2:SetText(text)
+ end
+
+ if IsActiveBattlefieldArena() then
+ self.text:SetText(DEATH_RELEASE_SPECTATOR)
+ elseif self.timeleft == -1 then
+ self.text:SetText(DEATH_RELEASE_NOTIMER)
+ end
+ if HasEvents() then
+ self.button3:Enable()
+ self.button3:SetScript("OnEnter", S.SetModifiedBackdrop)
+ self.button3:SetScript("OnLeave", S.SetOriginalBackdrop)
+ else
+ self.button3:Disable()
+ self.button3:SetScript("OnEnter", function(self)
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT")
+ GameTooltip:SetText(L["Death Recap unavailable."])
+ GameTooltip:Show()
+ end)
+ self.button3:SetScript("OnLeave", GameTooltip_Hide)
+ end
+ end,
+ OnHide = function(self)
+ self.button3:SetScript("OnEnter", nil)
+ self.button3:SetScript("OnLeave", nil)
+ ElvUI_DeathRecapFrame:Hide()
+ end,
+ OnAccept = function(self)
+ if IsActiveBattlefieldArena() then
+ local info = ChatTypeInfo["SYSTEM"]
+ DEFAULT_CHAT_FRAME:AddMessage(ARENA_SPECTATOR, info.r, info.g, info.b, info.id)
+ end
+ RepopMe()
+ if CannotBeResurrected() then
+ return 1
+ end
+ end,
+ OnCancel = function(self, data, reason)
+ if reason == "override" then
+ StaticPopup_Show("RECOVER_CORPSE")
+ return
+ end
+ if reason == "timeout" then
+ return
+ end
+ if reason == "clicked" then
+ if HasSoulstone() then
+ UseSoulstone()
+ else
+ RepopMe()
+ end
+ if CannotBeResurrected() then
+ return 1
+ end
+ end
+ end,
+ OnAlt = function()
+ local _, recapID = HasEvents()
+ OpenRecap(recapID)
+ end,
+ OnUpdate = function(self, elapsed)
+ if self.timeleft > 0 then
+ local text = _G[self:GetName().."Text"]
+ local timeleft = self.timeleft
+ if timeleft < 60 then
+ text:SetFormattedText(DEATH_RELEASE_TIMER, timeleft, SECONDS)
+ else
+ text:SetFormattedText(DEATH_RELEASE_TIMER, ceil(timeleft / 60), MINUTES)
+ end
+ end
+
+ if IsFalling() and not IsOutOfBounds() then
+ self.button1:Disable()
+ self.button2:Disable()
+ return
+ else
+ self.button1:Enable()
+ end
+ if HasSoulstone() then
+ self.button2:Enable()
+ else
+ self.button2:Disable()
+ end
+ end,
+ DisplayButton2 = HasSoulstone,
+
+ timeout = 0,
+ whileDead = 1,
+ interruptCinematic = 1,
+ noCancelOnReuse = 1,
+ hideOnEscape = false,
+ noCloseOnAlt = true
+ }
+end
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/DressUpFrame.lua b/ElvUI_Enhanced/Modules/Blizzard/DressUpFrame.lua
new file mode 100644
index 0000000..28f676b
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/DressUpFrame.lua
@@ -0,0 +1,110 @@
+local E, L, V, P, G = unpack(ElvUI)
+local mod = E:GetModule("Enhanced_Blizzard")
+local S = E:GetModule("Skins")
+
+function mod:UpdateDressUpFrame()
+ local mult = E.db.enhanced.blizzard.dressUpFrame.multiplier
+
+ if ElvCharacterDB.Enhanced_DressUpResize then
+ DressUpFrame:Size(384 * mult, 512 * mult)
+ S:SetNextPrevButtonDirection(DressUpFrameResizeButton, "up")
+ else
+ DressUpFrame:Size(384, 512)
+ S:SetNextPrevButtonDirection(DressUpFrameResizeButton)
+ end
+
+ DressUpFrame:GetLeft() -- update size
+ S:SetUIPanelWindowInfo(DressUpFrame, "width")
+end
+
+--[[
+local function DressUpSources(appearanceSources, mainHandEnchant, offHandEnchant)
+ if not appearanceSources then return true end
+
+ local mainHandSlotID = GetInventorySlotInfo("MAINHANDSLOT")
+ local secondaryHandSlotID = GetInventorySlotInfo("SECONDARYHANDSLOT")
+ for i = 1, #appearanceSources do
+ if i ~= mainHandSlotID and i ~= secondaryHandSlotID then
+ if appearanceSources[i] and appearanceSources[i] ~= 0 then
+ DressUpModel:TryOn(appearanceSources[i])
+ end
+ end
+ end
+
+ DressUpModel:TryOn(appearanceSources[mainHandSlotID], "MAINHANDSLOT", mainHandEnchant)
+ DressUpModel:TryOn(appearanceSources[secondaryHandSlotID], "SECONDARYHANDSLOT", offHandEnchant)
+end
+
+function mod:SelectOutfit(outfitID, loadOutfit)
+ local name
+ if outfitID then
+ name = C_TransmogCollection.GetOutfitName(outfitID)
+ end
+ if name then
+ UIDropDownMenu_SetText(self, name)
+ else
+ outfitID = nil
+ UIDropDownMenu_SetText(self, GRAY_FONT_COLOR_CODE.."TRANSMOG_OUTFIT_NONE"..FONT_COLOR_CODE_CLOSE)
+ end
+ self.selectedOutfitID = outfitID
+ if loadOutfit then
+ -- self:LoadOutfit(outfitID)
+ end
+ --self:UpdateSaveButton()
+ --self:OnSelectOutfit(outfitID)
+end
+]]
+
+function mod:DressUpFrame()
+ if not E.db.enhanced.blizzard.dressUpFrame.enable then return end
+
+ DressUpBackgroundTopLeft:SetAlpha(0)
+ DressUpBackgroundTopRight:SetAlpha(0)
+ DressUpBackgroundBotLeft:SetAlpha(0)
+ DressUpBackgroundBotRight:SetAlpha(0)
+
+ DressUpFrameCancelButton:ClearAllPoints()
+ DressUpFrameCancelButton:Point("BOTTOMRIGHT", -40, 84)
+
+ DressUpModel:ClearAllPoints()
+ DressUpModel:Point("TOPLEFT", 20, -67)
+ DressUpModel:Point("BOTTOMRIGHT", -41, 114)
+
+ local resizeButton = CreateFrame("Button", "DressUpFrameResizeButton", DressUpFrame)
+ S:HandleNextPrevButton(resizeButton, nil, nil, true)
+ resizeButton:Size(26)
+ resizeButton:Point("RIGHT", DressUpFrameCloseButton, "LEFT", 10, 0)
+ resizeButton:SetScript("OnClick", function()
+ if ElvCharacterDB.Enhanced_DressUpResize then
+ ElvCharacterDB.Enhanced_DressUpResize = nil
+ else
+ ElvCharacterDB.Enhanced_DressUpResize = true
+ end
+
+ mod:UpdateDressUpFrame()
+ end)
+
+ local _, classFileName = UnitClass("player")
+ DressUpFrame.ModelBackground = DressUpFrame:CreateTexture()
+ DressUpFrame.ModelBackground:SetAllPoints(DressUpModel)
+ DressUpFrame.ModelBackground:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\backgrounds\\DressingRoom"..classFileName)
+ DressUpFrame.ModelBackground:SetTexCoord(0.00195312, 0.935547, 0.00195312, 0.978516)
+ DressUpFrame.ModelBackground:SetDesaturated(true)
+
+--[[
+ DressUpFrame.OutfitDropDown = CreateFrame("Frame", "DressUpFrameOutfitDropDown", DressUpFrame, "UIDropDownMenuTemplate")
+ DressUpFrame.OutfitDropDown:Point("TOP", -23, -28)
+ S:HandleDropDownBox(DressUpFrame.OutfitDropDown)
+ DressUpFrame.OutfitDropDown:SetScript("OnShow", function(self)
+ mod.SelectOutfit(self, nil, true)
+ end)
+
+ DressUpFrame.SaveButton = CreateFrame("Button", nil, DressUpFrame, "UIPanelButtonTemplate")
+ DressUpFrame.SaveButton:Size(88, 22)
+ DressUpFrame.SaveButton:Point("LEFT", DressUpFrame.OutfitDropDown, "RIGHT", -13, -3)
+ DressUpFrame.SaveButton:SetText(SAVE)
+ S:HandleButton(DressUpFrame.SaveButton)
+]]
+
+ self:UpdateDressUpFrame()
+end
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/ErrorFrame.lua b/ElvUI_Enhanced/Modules/Blizzard/ErrorFrame.lua
new file mode 100644
index 0000000..7d1d3f2
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/ErrorFrame.lua
@@ -0,0 +1,38 @@
+local E, L, V, P, G = unpack(ElvUI)
+local mod = E:GetModule("Enhanced_Blizzard")
+local LSM = LibStub("LibSharedMedia-3.0")
+
+local defaultSettings = {
+ width = 512,
+ height = 60,
+ font = "PT Sans Narrow",
+ fontSize = 15,
+ fontOutline = "NONE"
+}
+
+function mod:ErrorFrameSize(db)
+ db = db or E.db.enhanced.blizzard.errorFrame
+
+ UIErrorsFrame:Size(db.width, db.height)
+ UIErrorsFrame:SetFont(LSM:Fetch("font", db.font), db.fontSize, db.fontOutline)
+
+ if not UIErrorsFrame.mover then
+ E:CreateMover(UIErrorsFrame, "UIErrorsFrameMover", L["Error Frame"], nil, nil, nil, "ALL,GENERAL", nil, "elvuiPlugins,enhanced,miscGroup,errorFrame")
+ end
+end
+
+function mod:CustomErrorFrameToggle()
+ if E.db.enhanced.blizzard.errorFrame.enable then
+ self:ErrorFrameSize()
+ E:EnableMover(UIErrorsFrame.mover:GetName())
+ else
+ self:ErrorFrameSize(defaultSettings)
+ UIErrorsFrame:Point("TOP", 0, -122)
+
+ if UIErrorsFrame.mover then
+ E:DisableMover(UIErrorsFrame.mover:GetName())
+ UIErrorsFrame.mover:ClearAllPoints()
+ UIErrorsFrame.mover:Point("TOP", 0, -122)
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/Load_Blizzard.xml b/ElvUI_Enhanced/Modules/Blizzard/Load_Blizzard.xml
new file mode 100644
index 0000000..9686b7d
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/Load_Blizzard.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/ModelFrames.lua b/ElvUI_Enhanced/Modules/Blizzard/ModelFrames.lua
new file mode 100644
index 0000000..cee5015
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/ModelFrames.lua
@@ -0,0 +1,445 @@
+local E, L, V, P, G = unpack(ElvUI)
+local MF = E:NewModule("Enhanced_ModelFrames", "AceHook-3.0", "AceEvent-3.0")
+local S = E:GetModule("Skins")
+
+local _G = _G
+local max, min = math.max, math.min
+local PI = math.pi
+
+local GetCVar = GetCVar
+local GetCursorPosition = GetCursorPosition
+local Model_RotateLeft = Model_RotateLeft
+local Model_RotateRight = Model_RotateRight
+
+local ROTATIONS_PER_SECOND = ROTATIONS_PER_SECOND
+
+local modelFrames = {
+ "CharacterModelFrame",
+ "CompanionModelFrame",
+ "DressUpModel",
+ "PetModelFrame",
+ "PetStableModel"
+}
+
+local modelSettings = {
+ ["HumanMale"] = {panMaxLeft = -0.4, panMaxRight = 0.4, panMaxTop = 1.2, panMaxBottom = -0.3, panValue = 38},
+ ["HumanFemale"] = {panMaxLeft = -0.3, panMaxRight = 0.3, panMaxTop = 1.2, panMaxBottom = -0.2, panValue = 45},
+ ["DwarfMale"] = {panMaxLeft = -0.4, panMaxRight = 0.6, panMaxTop = 0.9, panMaxBottom = -0.2, panValue = 44},
+ ["DwarfFemale"] = {panMaxLeft = -0.3, panMaxRight = 0.3, panMaxTop = 0.9, panMaxBottom = -0.2, panValue = 47},
+ ["NightElfMale"] = {panMaxLeft = -0.5, panMaxRight = 0.5, panMaxTop = 1.5, panMaxBottom = -0.4, panValue = 30},
+ ["NightElfFemale"] = {panMaxLeft = -0.4, panMaxRight = 0.4, panMaxTop = 1.4, panMaxBottom = -0.4, panValue = 33},
+ ["GnomeMale"] = {panMaxLeft = -0.3, panMaxRight = 0.3, panMaxTop = 0.5, panMaxBottom = -0.2, panValue = 52},
+ ["GnomeFemale"] = {panMaxLeft = -0.3, panMaxRight = 0.3, panMaxTop = 0.5, panMaxBottom = -0.2, panValue = 60},
+ ["DraeneiMale"] = {panMaxLeft = -0.6, panMaxRight = 0.6, panMaxTop = 1.4, panMaxBottom = -0.4, panValue = 28},
+ ["DraeneiFemale"] = {panMaxLeft = -0.3, panMaxRight = 0.3, panMaxTop = 1.4, panMaxBottom = -0.3, panValue = 31},
+
+ ["OrcMale"] = {panMaxLeft = -0.7, panMaxRight = 0.8, panMaxTop = 1.2, panMaxBottom = -0.3, panValue = 30},
+ ["OrcFemale"] = {panMaxLeft = -0.4, panMaxRight = 0.3, panMaxTop = 1.2, panMaxBottom = -0.3, panValue = 37},
+ ["ScourgeMale"] = {panMaxLeft = -0.4, panMaxRight = 0.4, panMaxTop = 1.1, panMaxBottom = -0.3, panValue = 35},
+ ["ScourgeFemale"] = {panMaxLeft = -0.3, panMaxRight = 0.4, panMaxTop = 1.1, panMaxBottom = -0.3, panValue = 36},
+ ["TaurenMale"] = {panMaxLeft = -0.7, panMaxRight = 0.9, panMaxTop = 1.1, panMaxBottom = -0.5, panValue = 31},
+ ["TaurenFemale"] = {panMaxLeft = -0.5, panMaxRight = 0.6, panMaxTop = 1.3, panMaxBottom = -0.4, panValue = 32},
+ ["TrollMale"] = {panMaxLeft = -0.5, panMaxRight = 0.6, panMaxTop = 1.3, panMaxBottom = -0.4, panValue = 27},
+ ["TrollFemale"] = {panMaxLeft = -0.4, panMaxRight = 0.4, panMaxTop = 1.5, panMaxBottom = -0.4, panValue = 31},
+ ["BloodElfMale"] = {panMaxLeft = -0.5, panMaxRight = 0.4, panMaxTop = 1.3, panMaxBottom = -0.3, panValue = 36},
+ ["BloodElfFemale"] = {panMaxLeft = -0.3, panMaxRight = 0.2, panMaxTop = 1.2, panMaxBottom = -0.3, panValue = 38},
+}
+
+local playerRaceSex
+do
+ local _
+ _, playerRaceSex = UnitRace("player")
+ if UnitSex("player") == 2 then
+ playerRaceSex = playerRaceSex.."Male"
+ else
+ playerRaceSex = playerRaceSex.."Female"
+ end
+end
+
+function MF:ModelControlButton(model)
+ model:Size(18, 18)
+
+ model.icon = model:CreateTexture("$parentIcon", "ARTWORK")
+ model.icon:SetInside()
+ model.icon:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\UI-ModelControlPanel")
+ model.icon:SetTexCoord(0.01562500, 0.26562500, 0.00781250, 0.13281250)
+
+ model:SetScript("OnMouseDown", function(self) MF:ModelControlButton_OnMouseDown(self) end)
+ model:SetScript("OnMouseUp", function(self) MF:ModelControlButton_OnMouseUp(self) end)
+ model:SetScript("OnEnter", function(self)
+ UIFrameFadeIn(self:GetParent(), 0.2, self:GetParent():GetAlpha(), 1)
+ if GetCVar("UberTooltips") == "1" then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT")
+ GameTooltip:SetText(self.tooltip, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
+ if self.tooltipText then
+ GameTooltip:AddLine(self.tooltipText, nil, nil, nil, 1, 1)
+ end
+ GameTooltip:Show()
+ end
+ end)
+ model:SetScript("OnLeave", function(self)
+ UIFrameFadeOut(self:GetParent(), 0.2, self:GetParent():GetAlpha(), 0.5)
+ GameTooltip:Hide()
+ end)
+end
+
+function MF:ModelWithControls(model)
+ model.controlFrame = CreateFrame("Frame", "$parentControlFrame", model)
+ model.controlFrame:Point("TOP", 0, -2)
+ model.controlFrame:SetAlpha(0.5)
+ model.controlFrame:Hide()
+
+ local zoomInButton = CreateFrame("Button", "$parentZoomInButton", model.controlFrame)
+ self:ModelControlButton(zoomInButton)
+ zoomInButton:Point("LEFT", 2, 0)
+ zoomInButton:RegisterForClicks("AnyUp")
+ zoomInButton.icon:SetTexCoord(0.57812500, 0.82812500, 0.14843750, 0.27343750)
+ zoomInButton.tooltip = L["Zoom In"]
+ zoomInButton.tooltipText = L["Mouse Wheel Up"]
+ zoomInButton:SetScript("OnMouseDown", function(self)
+ MF:Model_OnMouseWheel(self:GetParent():GetParent(), 1)
+ end)
+
+ local zoomOutButton = CreateFrame("Button", "$parentZoomOutButton", model.controlFrame)
+ self:ModelControlButton(zoomOutButton)
+ zoomOutButton:Point("LEFT", 2, 0)
+ zoomOutButton:RegisterForClicks("AnyUp")
+ zoomOutButton.icon:SetTexCoord(0.29687500, 0.54687500, 0.00781250, 0.13281250)
+ zoomOutButton.tooltip = L["Zoom Out"]
+ zoomOutButton.tooltipText = L["Mouse Wheel Down"]
+ zoomOutButton:SetScript("OnMouseDown", function(self)
+ MF:Model_OnMouseWheel(self:GetParent():GetParent(), -1)
+ end)
+
+ local panButton = CreateFrame("Button", "$parentPanButton", model.controlFrame)
+ self:ModelControlButton(panButton)
+ panButton:Point("LEFT", 2, 0)
+ panButton:RegisterForClicks("AnyUp")
+ panButton.icon:SetTexCoord(0.29687500, 0.54687500, 0.28906250, 0.41406250)
+ panButton.tooltip = L["Drag"]
+ panButton.tooltipText = L["Right-click on character and drag to move it within the window."]
+ panButton:SetScript("OnMouseDown", function(self)
+ MF:ModelControlButton_OnMouseDown(self)
+ MF:Model_StartPanning(self:GetParent():GetParent(), true)
+ end)
+ panButton:SetScript("OnMouseUp", function(self)
+ MF:Model_StopPanning(model)
+ MF:ModelControlButton_OnMouseUp(self)
+
+ if not model:IsMouseOver() and not model.controlFrame:IsMouseOver() then
+ model.controlFrame:Hide()
+ end
+ end)
+
+ local rotateLeftButton = CreateFrame("Button", "$parentRotateLeftButton", model.controlFrame)
+ self:ModelControlButton(rotateLeftButton)
+ rotateLeftButton:RegisterForClicks("AnyUp")
+ rotateLeftButton.icon:SetTexCoord(0.01562500, 0.26562500, 0.28906250, 0.41406250)
+ rotateLeftButton.tooltip = L["Rotate Left"]
+ rotateLeftButton.tooltipText = L["Left-click on character and drag to rotate."]
+ rotateLeftButton:SetScript("OnClick", function(self)
+ Model_RotateLeft(self:GetParent():GetParent())
+ end)
+ model.controlFrame.rotateLeftButton = rotateLeftButton
+
+ local rotateRightButton = CreateFrame("Button", "$parentRotateRightButton", model.controlFrame)
+ self:ModelControlButton(rotateRightButton)
+ rotateRightButton:RegisterForClicks("AnyUp")
+ rotateRightButton.icon:SetTexCoord(0.57812500, 0.82812500, 0.28906250, 0.41406250)
+ rotateRightButton.tooltip = L["Rotate Right"]
+ rotateRightButton.tooltipText = L["Left-click on character and drag to rotate."]
+ rotateRightButton:SetScript("OnClick", function(self)
+ Model_RotateRight(self:GetParent():GetParent())
+ end)
+ model.controlFrame.rotateRightButton = rotateRightButton
+
+ local rotateResetButton = CreateFrame("Button", "$parentrotateResetButton", model.controlFrame)
+ self:ModelControlButton(rotateResetButton)
+ rotateResetButton:RegisterForClicks("AnyUp")
+ rotateResetButton.tooltip = L["Reset Position"]
+ rotateResetButton:SetScript("OnClick", function(self)
+ MF:Model_Reset(self:GetParent():GetParent())
+ end)
+
+ if E.private.skins.blizzard.enable then
+ model.controlFrame:Size(123, 23)
+
+ S:HandleButton(zoomInButton)
+
+ S:HandleButton(zoomOutButton)
+ zoomOutButton:Point("LEFT", "$parentZoomInButton", "RIGHT", 2, 0)
+
+ S:HandleButton(panButton)
+ panButton:Point("LEFT", "$parentZoomOutButton", "RIGHT", 2, 0)
+
+ S:HandleButton(rotateLeftButton)
+ rotateLeftButton:Point("LEFT", "$parentPanButton", "RIGHT", 2, 0)
+
+ S:HandleButton(rotateRightButton)
+ rotateRightButton:Point("LEFT", "$parentRotateLeftButton", "RIGHT", 2, 0)
+
+ S:HandleButton(rotateResetButton)
+ rotateResetButton:Point("LEFT", "$parentRotateRightButton", "RIGHT", 2, 0)
+ else
+ model.controlFrame:Size(114, 23)
+ zoomOutButton:SetPoint("LEFT", "$parentZoomInButton", "RIGHT")
+ panButton:SetPoint("LEFT", "$parentZoomOutButton", "RIGHT")
+ rotateLeftButton:SetPoint("LEFT", "$parentPanButton", "RIGHT")
+ rotateRightButton:SetPoint("LEFT", "$parentRotateLeftButton", "RIGHT")
+ rotateResetButton:SetPoint("LEFT", "$parentRotateRightButton", "RIGHT")
+ end
+
+ model.controlFrame:SetScript("OnHide", function(self)
+ if self.buttonDown then
+ MF:ModelControlButton_OnMouseUp(self.buttonDown)
+ end
+ end)
+
+ self:HookScript(model, "OnUpdate", "Model_OnUpdate")
+ model:SetScript("OnMouseWheel", function(self, delta)
+ MF:Model_OnMouseWheel(self, delta)
+ end)
+ model:SetScript("OnMouseUp", function(self, button)
+ if button == "RightButton" and self.panning then
+ MF:Model_StopPanning(self)
+ elseif self.mouseDown then
+ MF:Model_OnMouseUp(self, button)
+ end
+ end)
+ model:SetScript("OnMouseDown", function(self, button)
+ if button == "RightButton" and not self.mouseDown then
+ MF:Model_StartPanning(self)
+ else
+ MF:Model_OnMouseDown(self, button)
+ end
+ end)
+ model:SetScript("OnEnter", function(self)
+ self.controlFrame:Show()
+ end)
+ model:SetScript("OnLeave", function(self)
+ if not self.controlFrame:IsMouseOver() and not ModelPanningFrame:IsShown() then
+ self.controlFrame:Hide()
+ end
+ end)
+ model:SetScript("OnHide", function(self)
+ if self.panning then
+ MF:Model_StopPanning(self)
+ end
+ self.mouseDown = false
+ self.controlFrame:Hide()
+ MF:Model_Reset(self)
+ end)
+end
+
+function MF:Model_OnMouseWheel(model, delta, maxZoom, minZoom)
+ maxZoom = maxZoom or 2.8
+ minZoom = minZoom or 0
+ local zoomLevel = model.zoomLevel or minZoom
+ zoomLevel = zoomLevel + delta * 0.5
+ zoomLevel = min(zoomLevel, maxZoom)
+ zoomLevel = max(zoomLevel, minZoom)
+ local _, y, z = model:GetPosition()
+ model:SetPosition(zoomLevel, y, z)
+ model.zoomLevel = zoomLevel
+end
+
+function MF:Model_OnMouseDown(model, button)
+ if not button or button == "LeftButton" then
+ model.mouseDown = true
+ model.rotationCursorStart = GetCursorPosition()
+ end
+end
+
+function MF:Model_OnMouseUp(model, button)
+ if not button or button == "LeftButton" then
+ model.mouseDown = false
+ end
+end
+
+function MF:Model_OnUpdate(frame, elapsedTime, rotationsPerSecond)
+ if not rotationsPerSecond then
+ rotationsPerSecond = ROTATIONS_PER_SECOND
+ end
+
+ if frame.mouseDown then
+ if frame.rotationCursorStart then
+ local cursorX = GetCursorPosition()
+ local diff = (cursorX - frame.rotationCursorStart) * 0.010
+
+ frame.rotationCursorStart = cursorX
+ frame.rotation = frame.rotation + diff
+
+ if frame.rotation < 0 then
+ frame.rotation = frame.rotation + (2 * PI)
+ end
+
+ if frame.rotation > (2 * PI) then
+ frame.rotation = frame.rotation - (2 * PI)
+ end
+
+ frame:SetRotation(frame.rotation, false)
+ end
+ elseif frame.panning then
+ local modelScale = frame:GetModelScale()
+ local cursorX, cursorY = GetCursorPosition()
+ local scale = UIParent:GetEffectiveScale()
+ ModelPanningFrame:Point("BOTTOMLEFT", cursorX / scale - 16, cursorY / scale - 16) -- half the texture size to center it on the cursor
+ -- settings
+ local settings = modelSettings[playerRaceSex]
+
+ local zoom = 1 + (frame.zoomLevel or 0)
+
+ -- Panning should require roughly the same mouse movement regardless of zoom level so the model moves at the same rate as the cursor
+ -- This formula more or less works for all zoom levels, found via trial and error
+ local transformationRatio = settings.panValue * 2 ^ (zoom * 1.25) * scale / modelScale
+
+ local dx = (cursorX - frame.cursorX) / transformationRatio
+ local dy = (cursorY - frame.cursorY) / transformationRatio
+ local cameraY = frame.cameraY + dx
+ local cameraZ = frame.cameraZ + dy
+ -- bounds
+ scale = scale * modelScale
+
+ local maxCameraY = settings.panMaxRight * zoom * scale
+ cameraY = min(cameraY, maxCameraY)
+
+ local minCameraY = settings.panMaxLeft * zoom * scale
+ cameraY = max(cameraY, minCameraY)
+
+ local maxCameraZ = settings.panMaxTop * zoom * scale
+ cameraZ = min(cameraZ, maxCameraZ)
+
+ local minCameraZ = settings.panMaxBottom * zoom * scale
+ cameraZ = max(cameraZ, minCameraZ)
+
+ frame:SetPosition(frame.cameraX, cameraY, cameraZ)
+ end
+
+ local leftButton, rightButton
+
+ if frame.controlFrame then
+ leftButton = frame.controlFrame.rotateLeftButton
+ rightButton = frame.controlFrame.rotateRightButton
+ else
+ leftButton = frame:GetName() and _G[frame:GetName().."RotateLeftButton"]
+ rightButton = frame:GetName() and _G[frame:GetName().."RotateRightButton"]
+ end
+
+ if leftButton and leftButton:GetButtonState() == "PUSHED" then
+ frame.rotation = frame.rotation + (elapsedTime * 2 * PI * rotationsPerSecond)
+
+ if frame.rotation < 0 then
+ frame.rotation = frame.rotation + (2 * PI)
+ end
+ elseif rightButton and rightButton:GetButtonState() == "PUSHED" then
+ frame.rotation = frame.rotation - (elapsedTime * 2 * PI * rotationsPerSecond)
+
+ if frame.rotation > (2 * PI) then
+ frame.rotation = frame.rotation - (2 * PI)
+ end
+ end
+
+ frame:SetRotation(frame.rotation)
+end
+
+function MF:Model_Reset(model)
+ model.rotation = 0.61
+ model:SetRotation(model.rotation)
+ model.zoomLevel = 0
+ model:SetPosition(0, 0, 0)
+end
+
+function MF:Model_StartPanning(model, usePanningFrame)
+ if usePanningFrame then
+ ModelPanningFrame.model = model
+ ModelPanningFrame:Show()
+ end
+
+ model.panning = true
+
+ local cameraX, cameraY, cameraZ = model:GetPosition()
+ model.cameraX = cameraX
+ model.cameraY = cameraY
+ model.cameraZ = cameraZ
+
+ local cursorX, cursorY = GetCursorPosition()
+ model.cursorX = cursorX
+ model.cursorY = cursorY
+end
+
+function MF:Model_StopPanning(model)
+ model.panning = false
+ ModelPanningFrame:Hide()
+end
+
+function MF:ModelControlButton_OnMouseDown(model)
+ model.icon:Point("CENTER", 1, -1)
+ model:GetParent().buttonDown = model
+end
+
+function MF:ModelControlButton_OnMouseUp(model)
+ model.icon:SetPoint("CENTER")
+ model:GetParent().buttonDown = nil
+end
+
+function MF:ADDON_LOADED(event, addon)
+ if addon == "Blizzard_InspectUI" then
+ InspectModelFrame:EnableMouse(true)
+ InspectModelFrame:EnableMouseWheel(true)
+
+ InspectModelRotateLeftButton:Kill()
+ InspectModelRotateRightButton:Kill()
+
+ self:ModelWithControls(InspectModelFrame)
+ elseif addon == "Blizzard_AuctionUI" then
+ AuctionDressUpModel:EnableMouse(true)
+ AuctionDressUpModel:EnableMouseWheel(true)
+
+ AuctionDressUpModelRotateLeftButton:Kill()
+ AuctionDressUpModelRotateRightButton:Kill()
+
+ self:ModelWithControls(AuctionDressUpModel)
+ end
+end
+
+function MF:Initialize()
+ if not E.private.enhanced.character.modelFrames then return end
+
+ for i = 1, #modelFrames do
+ local model = _G[modelFrames[i]]
+
+ model:EnableMouse(true)
+ model:EnableMouseWheel(true)
+
+ _G[modelFrames[i].."RotateLeftButton"]:Kill()
+ _G[modelFrames[i].."RotateRightButton"]:Kill()
+
+ self:ModelWithControls(model)
+ end
+
+ if E.myclass == "HUNTER" then
+ if E.private.enhanced.character.enable then
+ PetPaperDollPetInfo:Point("TOPLEFT", PetPaperDollFrame, 24, -81)
+ else
+ PetPaperDollPetInfo:Point("TOPLEFT", PetPaperDollFrame, 24, -76)
+ end
+ PetStablePetInfo:Point("TOPLEFT", PetStableModel, 5, -5)
+ end
+
+ local modelPanning = CreateFrame("Frame", "ModelPanningFrame", UIParent)
+ modelPanning:SetFrameStrata("DIALOG")
+ modelPanning:Hide()
+ modelPanning:Size(32, 32)
+
+ modelPanning.texture = modelPanning:CreateTexture(nil, "ARTWORK")
+ modelPanning.texture:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\UI-Cursor-Move")
+ modelPanning.texture:SetAllPoints()
+
+ self:RegisterEvent("ADDON_LOADED")
+end
+
+local function InitializeCallback()
+ MF:Initialize()
+end
+
+E:RegisterModule(MF:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/TakeAllMail.lua b/ElvUI_Enhanced/Modules/Blizzard/TakeAllMail.lua
new file mode 100644
index 0000000..c422625
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/TakeAllMail.lua
@@ -0,0 +1,293 @@
+local E, L, V, P, G = unpack(ElvUI)
+local TAM = E:NewModule("Enhanced_TakeAllMail", "AceEvent-3.0")
+
+local select = select
+local format = string.format
+
+local AutoLootMailItem = AutoLootMailItem
+local CheckInbox = CheckInbox
+local DeleteInboxItem = DeleteInboxItem
+local GetInboxHeaderInfo = GetInboxHeaderInfo
+local GetInboxNumItems = GetInboxNumItems
+local InboxItemCanDelete = InboxItemCanDelete
+local IsShiftKeyDown = IsShiftKeyDown
+local TakeInboxMoney = TakeInboxMoney
+
+local ERR_INV_FULL = ERR_INV_FULL
+
+local MAIL_MIN_DELAY = 0.15
+
+function TAM:GetTotalCash()
+ if GetInboxNumItems() == 0 then return 0 end
+
+ local totalCash = 0
+
+ for i = 1, GetInboxNumItems() do
+ totalCash = totalCash + select(5, GetInboxHeaderInfo(i))
+ end
+
+ return totalCash
+end
+
+function TAM:UpdateButtons()
+ if self.processing then return end
+
+ if GetInboxNumItems() == 0 then
+ self.takeAll:Disable()
+ self.takeCash:Disable()
+ else
+ self.takeAll:Enable()
+
+ if self:GetTotalCash() > 0 then
+ self.takeCash:Enable()
+ else
+ self.takeCash:Disable()
+ end
+ end
+end
+
+function TAM:Reset()
+ self.mailIndex = 1
+ self.timeUntilNextRetrieval = nil
+ self.commandPending = nil
+
+ self.collectCashOnly = nil
+ self.collectedCash = 0
+ self.collectedTotal = 0
+ self.removeEmpty = nil
+end
+
+function TAM:StartOpening(mode)
+ if GetInboxNumItems() == 0 then return end
+
+ self:Reset()
+
+ self.takeAll:Disable()
+ self.takeCash:Disable()
+
+ self:RegisterEvent("MAIL_INBOX_UPDATE", "OnEvent")
+ self:RegisterEvent("UI_ERROR_MESSAGE", "OnEvent")
+
+ if mode == 1 then
+ self.collectCashOnly = true
+ elseif mode == 2 then
+ self.removeEmpty = true
+ end
+
+ self.processing = true
+
+ self.numToOpen = GetInboxNumItems()
+ self.takeAll:SetScript("OnUpdate", function(_, elapsed) self:OnUpdate(elapsed) end)
+
+ if mode == 2 then
+ self:RemoveNextMail()
+ else
+ self:AdvanceAndProcessNextMail()
+ end
+end
+
+function TAM:StopOpening(err)
+ if self.collectedCash > 0 then
+ E:Print(L["Collected "]..E:FormatMoney(self.collectedCash))
+ end
+ if self.collectedTotal > 0 and not err then
+ E:Print(L["Collection completed."])
+ end
+
+ self:Reset()
+
+ self.takeAll:Enable()
+ self.takeCash:Enable()
+
+ self:UnregisterEvent("MAIL_INBOX_UPDATE")
+ self:UnregisterEvent("UI_ERROR_MESSAGE")
+
+ self.processing = nil
+ self.takeAll:SetScript("OnUpdate", nil)
+ self:UpdateButtons()
+end
+
+function TAM:AdvanceToNextMail()
+ local _, _, _, _, money, _, _, itemCount = GetInboxHeaderInfo(self.mailIndex)
+
+ if money > 0 or (not self.collectCashOnly and (itemCount and itemCount > 0)) then
+ return true
+ else
+ self.mailIndex = self.mailIndex + 1
+
+ if self.mailIndex > GetInboxNumItems() then
+ return false
+ end
+
+ return self:AdvanceToNextMail()
+ end
+end
+
+function TAM:AdvanceAndProcessNextMail()
+ if self:AdvanceToNextMail() then
+ self:ProcessNextMail()
+ else
+ self:StopOpening()
+ end
+end
+
+function TAM:ProcessNextMail()
+ local _, _, _, _, money, CODAmount, _, itemCount, _, _, _, _, isGM = GetInboxHeaderInfo(self.mailIndex)
+ if isGM or (CODAmount and CODAmount > 0) then
+ self.mailIndex = self.mailIndex + 1
+ self:AdvanceAndProcessNextMail()
+ return
+ end
+
+ if money > 0 then
+ TakeInboxMoney(self.mailIndex)
+
+ self.collectedCash = self.collectedCash + money
+ self.collectedTotal = self.collectedTotal + 1
+ self.timeUntilNextRetrieval = MAIL_MIN_DELAY
+ elseif not self.collectCashOnly and (itemCount and itemCount > 0) then
+ AutoLootMailItem(self.mailIndex)
+
+ self.collectedTotal = self.collectedTotal + 1
+ self.timeUntilNextRetrieval = MAIL_MIN_DELAY
+ else
+ self:AdvanceAndProcessNextMail()
+ end
+end
+
+function TAM:RemoveNextMail()
+ local numItems = GetInboxNumItems()
+
+ if numItems > 0 then
+ local money, CODAmount, itemCount, isGM, _
+
+ for i = 1, numItems do
+ _, _, _, _, money, CODAmount, _, itemCount, _, _, _, _, isGM = GetInboxHeaderInfo(i)
+
+ if not isGM and (not CODAmount or CODAmount == 0) and money == 0 and (not itemCount or itemCount == 0) then
+ if InboxItemCanDelete(i) then
+ DeleteInboxItem(i)
+ self.timeUntilNextRetrieval = MAIL_MIN_DELAY
+ break
+ end
+ end
+ end
+ else
+ return self:StopOpening()
+ end
+
+ if not self.timeUntilNextRetrieval then
+ self:StopOpening()
+ end
+end
+
+function TAM:OnUpdate(dt)
+ if not self.timeUntilNextRetrieval then return end
+
+ self.timeUntilNextRetrieval = self.timeUntilNextRetrieval - dt
+
+ if self.timeUntilNextRetrieval <= 0 then
+ if not self.commandPending then
+ self.timeUntilNextRetrieval = nil
+ if not self.removeEmpty then
+ self:AdvanceAndProcessNextMail()
+ else
+ self:RemoveNextMail()
+ end
+ else
+ self.commandPending = nil
+ self.timeUntilNextRetrieval = MAIL_MIN_DELAY
+ end
+ end
+end
+
+function TAM:OnEvent(event, errstr)
+ if event == "MAIL_SHOW" then
+ self:RegisterEvent("MAIL_CLOSED", "OnEvent")
+ self:RegisterEvent("MAIL_INBOX_UPDATE", "OnEvent")
+ self:RegisterEvent("UPDATE_PENDING_MAIL", "OnEvent")
+ self:UnregisterEvent("MAIL_SHOW")
+
+ self:UpdateButtons(true)
+ elseif event == "MAIL_CLOSED" then
+ self:RegisterEvent("MAIL_SHOW", "OnEvent")
+ self:UnregisterEvent("MAIL_CLOSED")
+ self:UnregisterEvent("MAIL_INBOX_UPDATE")
+ self:UnregisterEvent("UPDATE_PENDING_MAIL")
+
+ self:StopOpening(true)
+ elseif event == "MAIL_INBOX_UPDATE" then
+ if self.numToOpen ~= GetInboxNumItems() then
+ self.mailIndex = 1
+ end
+
+ self:UpdateButtons()
+ elseif event == "UPDATE_PENDING_MAIL" then
+ if self.processing then
+ self.commandPending = true
+ CheckInbox()
+ else
+ CheckInbox()
+ self:UpdateButtons()
+ end
+ elseif event == "UI_ERROR_MESSAGE" and errstr == ERR_INV_FULL then
+ self:StopOpening(true)
+ E:Print(L["Collection stopped, inventory is full."])
+ end
+end
+
+function TAM:Initialize()
+ if not E.db.enhanced.blizzard.takeAllMail then return end
+
+ local S = E:GetModule("Skins")
+
+ self:Reset()
+
+ self.takeAll = CreateFrame("Button", "ElvUI_MailButtonAll", InboxFrame, "UIPanelButtonTemplate")
+ self.takeAll:Size(80, 22)
+ self.takeAll:Point("BOTTOM", "MailFrame","BOTTOM", -53, 92)
+ self.takeAll:SetText(L["Take All"])
+ S:HandleButton(self.takeAll)
+
+ self.takeCash = CreateFrame("Button", "ElvUI_MailButtonCash", InboxFrame, "UIPanelButtonTemplate")
+ self.takeCash:Size(80, 22)
+ self.takeCash:Point("BOTTOM", "MailFrame","BOTTOM", 34, 92)
+ self.takeCash:SetText(L["Take Cash"])
+ S:HandleButton(self.takeCash)
+
+ self.takeAll:SetScript("OnHide", function() self:StopOpening(true) end)
+-- self.takeCash:SetScript("OnHide", function() self:StopOpening(true) end)
+
+ self.takeAll:SetScript("OnClick", function()
+ if IsShiftKeyDown() then
+ self:StartOpening(2)
+ else
+ self:StartOpening()
+ end
+ end)
+ self.takeCash:SetScript("OnClick", function() self:StartOpening(1) end)
+
+ self.takeAll:SetScript("OnEnter", function()
+ GameTooltip:SetOwner(self.takeAll, "ANCHOR_TOP")
+ GameTooltip:AddLine(format(L["%d mails\nShift-Click to remove empty mails."], GetInboxNumItems()), 1, 1, 1)
+ GameTooltip:Show()
+ end)
+ self.takeCash:SetScript("OnEnter", function()
+ GameTooltip:SetOwner(self.takeCash, "ANCHOR_TOP")
+ GameTooltip:AddLine(E:FormatMoney(self:GetTotalCash()), 1, 1, 1)
+ GameTooltip:Show()
+ end)
+
+ self.takeAll:SetScript("OnLeave", function() GameTooltip:Hide() end)
+ self.takeCash:SetScript("OnLeave", function() GameTooltip:Hide() end)
+
+ self:RegisterEvent("MAIL_SHOW", "OnEvent")
+
+ self.initialized = true
+end
+
+local function InitializeCallback()
+ TAM:Initialize()
+end
+
+E:RegisterModule(TAM:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/TimerTracker.lua b/ElvUI_Enhanced/Modules/Blizzard/TimerTracker.lua
new file mode 100644
index 0000000..dd30800
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/TimerTracker.lua
@@ -0,0 +1,453 @@
+local E, L, V, P, G = unpack(ElvUI)
+local TT = E:NewModule("Enhanced_TimerTracker", "AceHook-3.0", "AceEvent-3.0")
+
+local ipairs = ipairs
+local tonumber = tonumber
+local unpack = unpack
+local floor, fmod = math.floor, math.fmod
+
+local GetTime = GetTime
+local UnitFactionGroup = UnitFactionGroup
+
+local timerTypes = {
+ ["30-120"] = {1, 30, 120},
+ ["60-120"] = {1, 60, 120},
+ ["120-120"] = {1, 120, 120},
+ ["15-60"] = {1, 15, 60},
+ ["30-60"] = {1, 30, 60},
+ ["60-60"] = {1, 60, 60},
+}
+
+local chatMessage = {
+ -- Ущелье Песни Войны
+ ["Битва за Ущелье Песни Войны начнется через 30 секунд. Приготовьтесь!"] = timerTypes["30-120"],
+ ["Битва за Ущелье Песни Войны начнется через 1 минуту."] = timerTypes["60-120"],
+ ["Сражение в Ущелье Песни Войны начнется через 2 минуты."] = timerTypes["120-120"],
+ -- Низина Арати
+ ["Битва за Низину Арати начнется через 30 секунд. Приготовьтесь!"] = timerTypes["30-120"],
+ ["Битва за Низину Арати начнется через 1 минуту."] = timerTypes["60-120"],
+ ["Сражение в Низине Арати начнется через 2 минуты."] = timerTypes["120-120"],
+ -- Око Бури
+ ["Битва за Око Бури начнется через 30 секунд."] = timerTypes["30-120"],
+ ["Битва за Око Бури начнется через 1 минуту."] = timerTypes["60-120"],
+ ["Сражение в Око Бури начнется через 2 минуты."] = timerTypes["120-120"],
+ -- Альтеракская долина
+ ["Сражение на Альтеракской долине начнется через 30 секунд. Приготовьтесь!"] = timerTypes["30-120"],
+ ["Сражение на Альтеракской долине начнется через 1 минуту."] = timerTypes["60-120"],
+ ["Сражение на Альтеракской долине начнется через 2 минуты."] = timerTypes["120-120"],
+ -- Берег Древних
+ ["Битва за Берег Древних начнется через 30 секунд. Приготовьтесь!"] = timerTypes["30-120"],
+ ["Битва за Берег Древних начнется через 1 минуту."] = timerTypes["60-120"],
+ ["Битва за Берег Древних начнется через 2 минуты."] = timerTypes["120-120"],
+ -- Берег древних 2-й раунд
+ ["Второй раунд начнется через 30 секунд. Приготовьтесь!"] = timerTypes["30-60"],
+ ["Второй раунд битвы за Берег Древних начнется через 1 минуту."] = timerTypes["60-60"],
+ -- Другие
+ ["Битва начнется через 30 секунд!"] = timerTypes["30-120"],
+ ["Битва начнется через 1 минуту."] = timerTypes["60-120"],
+ ["Битва начнется через 2 минуты."] = timerTypes["120-120"],
+ -- Арена
+ ["15 секунд до начала боя на арене!"] = timerTypes["15-60"],
+ ["30 секунд до начала боя на арене!"] = timerTypes["30-60"],
+ ["1 минута до начала боя на арене!"] = timerTypes["60-60"],
+ ["Пятнадцать секунд до начала боя на арене!"] = timerTypes["15-60"],
+ ["Тридцать секунд до начала боя на арене !"] = timerTypes["30-60"],
+
+ -- WSG
+ ["The battle for Warsong Gulch begins in 30 seconds. Prepare yourselves!"] = timerTypes["30-120"],
+ ["The battle for Warsong Gulch begins in 1 minute."] = timerTypes["60-120"],
+ ["The battle for Warsong Gulch begins in 2 minutes."] = timerTypes["120-120"],
+ -- AB
+ ["The Battle for Arathi Basin begins in 30 seconds. Prepare yourselves!"] = timerTypes["30-120"],
+ ["The Battle for Arathi Basin begins in 1 minute."] = timerTypes["60-120"],
+ ["The battle for Arathi Basin begins in 2 minutes."] = timerTypes["120-120"],
+ -- EotS
+ ["The Battle for Eye of the Storm begins in 30 seconds."] = timerTypes["30-120"],
+ ["The Battle for Eye of the Storm begins in 1 minute."] = timerTypes["60-120"],
+ ["The battle for Eye of the Storm begins in 2 minutes."] = timerTypes["120-120"],
+ -- AV
+ ["The Battle for Alterac Valley begins in 30 seconds. Prepare yourselves!"] = timerTypes["30-120"],
+ ["The Battle for Alterac Valley begins in 1 minute."] = timerTypes["60-120"],
+ ["The Battle for Alterac Valley begins in 2 minutes."] = timerTypes["120-120"],
+ -- SotA
+ ["The battle for Strand of the Ancients begins in 30 seconds. Prepare yourselves!."] = timerTypes["30-120"],
+ ["The battle for Strand of the Ancients begins in 1 minute."] = timerTypes["60-120"],
+ ["The battle for Strand of the Ancients begins in 2 minutes."] = timerTypes["120-120"],
+ -- SotA 2 round
+ ["Round 2 begins in 30 seconds. Prepare yourselves!"] = timerTypes["30-60"],
+ ["Round 2 of the Battle for the Strand of the Ancients begins in 1 minute."] = timerTypes["60-60"],
+ -- Other
+ ["The battle will begin in 30 seconds!"] = timerTypes["30-120"],
+ ["The battle will begin in 1 minute."] = timerTypes["60-120"],
+ ["The battle will begin in two minutes."] = timerTypes["120-120"],
+ ["The battle begins in 30 seconds!"] = timerTypes["30-120"],
+ ["The battle begins in 1 minute!"] = timerTypes["60-120"],
+ ["The battle begins in 2 minutes!"] = timerTypes["120-120"],
+ -- Arena
+ ["Fifteen seconds until the Arena battle begins!"] = timerTypes["15-60"],
+ ["Thirty seconds until the Arena battle begins!"] = timerTypes["30-60"],
+ ["One minute until the Arena battle begins!"] = timerTypes["60-60"]
+}
+
+local TIMER_MINUTES_DISPLAY = "%d:%02d"
+local TIMER_TYPE_PVP = 1
+local TIMER_TYPE_CHALLENGE_MODE = 2
+
+local TIMER_DATA = {
+ [1] = {mediumMarker = 11, largeMarker = 6, updateInterval = 10},
+ [2] = {mediumMarker = 100, largeMarker = 100, updateInterval = 100}
+}
+
+local TIMER_NUMBERS_SETS = {}
+TIMER_NUMBERS_SETS["BigGold"] = {
+ texture = "Interface\\AddOns\\ElvUI_Enhanced\\media\\textures\\BigTimerNumbers",
+ w = 256, h = 170, texW = 1024, texH = 512,
+ numberHalfWidths = {
+ 35/128, -- 0
+ 14/128, -- 1
+ 33/128, -- 2
+ 32/128, -- 3
+ 36/128, -- 4
+ 32/128, -- 5
+ 33/128, -- 6
+ 29/128, -- 7
+ 31/128, -- 8
+ 31/128, -- 9
+ }
+}
+
+function TT:OnShow(timer)
+ timer.time = timer.endTime - GetTime()
+
+ if timer.time <= 0 then
+ timer:Hide()
+ timer.isFree = true
+ elseif timer.digit.startNumbers:IsPlaying() then
+ timer.digit.startNumbers:Stop()
+ timer.digit.startNumbers:Play()
+ end
+end
+
+function TT:CreateTimer(timerType, timeSeconds, totalTime)
+ if not timerType then return end
+
+ local timer
+ local isTimerRunning = false
+
+ for _, frame in ipairs(self.timerList) do
+ if frame.type == timerType and not frame.isFree then
+ timer = frame
+ isTimerRunning = true
+ break
+ end
+ end
+
+ if isTimerRunning then
+ if not timer.digit.startNumbers:IsPlaying() then
+ timer.time = timeSeconds
+ timer.endTime = GetTime() + timeSeconds
+ end
+ else
+ for _, frame in ipairs(self.timerList) do
+ if frame.isFree then
+ timer = frame
+ break
+ end
+ end
+
+ if not timer then
+ timer = CreateFrame("Frame", "ElvUI_Timer"..(#self.timerList + 1), UIParent, "ElvUI_StartTimerBar")
+ self:CreateTimerBar(timer)
+ self.timerList[#self.timerList+1] = timer
+ end
+
+ timer:ClearAllPoints()
+ timer:Point("TOP", 0, -155 - (24 * #self.timerList))
+
+ timer.isFree = false
+ timer.type = timerType
+ timer.time = timeSeconds
+ timer.endTime = GetTime() + timeSeconds
+ timer.totalTime = totalTime
+ timer.bar:SetMinMaxValues(0, totalTime)
+ timer.style = TIMER_NUMBERS_SETS["BigGold"]
+
+ timer.digit1 = timer.digit.digit1
+ timer.digit2 = timer.digit.digit2
+
+ timer.digit1:SetTexture(timer.style.texture)
+ timer.digit2:SetTexture(timer.style.texture)
+ timer.digit1:Size(timer.style.w / 2, timer.style.h / 2)
+ timer.digit2:Size(timer.style.w / 2, timer.style.h / 2)
+ timer.digit1.width = timer.style.w / 2
+ timer.digit2.width = timer.style.w / 2
+
+ timer.digit1.glow = timer.glow1
+ timer.digit2.glow = timer.glow2
+ timer.glow1:SetTexture(timer.style.texture.."Glow")
+ timer.glow2:SetTexture(timer.style.texture.."Glow")
+
+ timer.updateTime = TIMER_DATA[timer.type].updateInterval
+ timer:SetScript("OnUpdate", self.BigNumberOnUpdate)
+ timer:Show()
+ end
+
+ self:SetGoTexture(timer)
+end
+
+function TT:CreateTimerBar(timer)
+ timer.bar = CreateFrame("StatusBar", "$parentStatusBar", timer)
+ timer.bar:SetSize(195, 13)
+ timer.bar:SetPoint("TOP", 0, -2)
+ timer.bar:SetAlpha(0)
+ timer.bar:SetStatusBarTexture(E.media.glossTex)
+ E:RegisterStatusBar(timer.bar)
+ timer.bar:CreateBackdrop("Default")
+
+ timer.bar.bg = timer.bar:CreateTexture("$parentBackgrund", "BORDER")
+ timer.bar.bg:SetAllPoints()
+ timer.bar.bg:SetTexture(E.media.blankTex)
+
+ timer.timeText = timer.bar:CreateFontString("$parentTimeText", "OVERLAY", "GameFontHighlight")
+ timer.timeText:SetSize(0, 9)
+ timer.timeText:SetPoint("CENTER", 0, 0)
+
+ timer.fadeBarIn = CreateAnimationGroup(timer.bar):CreateAnimation("Fade")
+ timer.fadeBarIn:SetDuration(1.9)
+ timer.fadeBarIn:SetChange(1)
+
+ timer.fadeBarIn:SetScript("OnPlay", function()
+ timer.bar:SetAlpha(0)
+ end)
+
+ timer.fadeBarIn:SetScript("OnFinished", function()
+ timer.bar:SetAlpha(1)
+ end)
+
+ timer.fadeBarOut = CreateAnimationGroup(timer.bar):CreateAnimation("Fade")
+ timer.fadeBarOut:SetDuration(0.9)
+ timer.fadeBarOut:SetChange(-1)
+
+ timer.fadeBarOut:SetScript("OnFinished", function()
+ timer.bar:SetAlpha(0)
+ timer.time = timer.time - 0.9
+
+ timer.digit.startNumbers:Play()
+ end)
+end
+
+function TT:BigNumberOnUpdate(elapsed)
+ self.time = self.endTime - GetTime()
+ self.updateTime = self.updateTime - elapsed
+
+ local minutes, seconds = floor(self.time / 60), floor(fmod(self.time, 60))
+
+ if self.time < TIMER_DATA[self.type].mediumMarker then
+ self.anchorCenter = false
+
+ if self.time < TIMER_DATA[self.type].largeMarker then
+ TT:SwitchToLargeDisplay(self)
+ self.bar:SetAlpha(0)
+ end
+
+ self:SetScript("OnUpdate", nil)
+
+ if self.barShowing then
+ self.barShowing = false
+ self.fadeBarOut:Play()
+ else
+ self.digit.startNumbers:Play()
+ end
+ elseif not self.barShowing then
+ self.fadeBarIn:Play()
+ self.barShowing = true
+ elseif self.updateTime <= 0 then
+ self.updateTime = TIMER_DATA[self.type].updateInterval
+ end
+
+ self.bar:SetValue(self.time)
+ self.timeText:SetFormattedText(TIMER_MINUTES_DISPLAY, minutes, seconds)
+
+ local r, g, b = E:ColorGradient((self.time - 10) / self.totalTime, 1,0,0, 1,1,0, 0,1,0)
+ self.bar:SetStatusBarColor(r, g, b)
+ self.bar.bg:SetVertexColor(r * 0.25, g * 0.25, b * 0.25)
+end
+
+function TT:BarOnlyOnUpdate(elapsed)
+ self.time = self.endTime - GetTime()
+ local minutes, seconds = floor(self.time / 60), fmod(self.time, 60)
+
+ self.bar:SetValue(self.time)
+ self.timeText:SetFormattedText(TIMER_MINUTES_DISPLAY, minutes, seconds)
+
+ if self.time < 0 then
+ self:SetScript("OnUpdate", nil)
+ self.barShowing = false
+ self.isFree = true
+ self:Hide()
+ end
+
+ if not self.barShowing then
+ self.fadeBarIn:Play()
+ self.barShowing = true
+ end
+end
+
+function TT:SetTexNumbers(timer, ...)
+ local digits = {...}
+ local timeDigits = floor(timer.time)
+ local style = timer.style
+
+ local texCoW = style.w / style.texW
+ local texCoH = style.h / style.texH
+ local columns = floor(style.texW / style.w)
+
+ local digit, l, r, t, b
+ local numberOffset, numShown = 0, 0
+ local i = 1
+
+ while digits[i] do
+ if timeDigits > 0 then
+ digit = fmod(timeDigits, 10)
+
+ digits[i].hw = style.numberHalfWidths[digit+1] * digits[i].width
+ numberOffset = numberOffset + digits[i].hw
+
+ l = fmod(digit, columns) * texCoW
+ r = l + texCoW
+ t = floor(digit / columns) * texCoH
+ b = t + texCoH
+
+ digits[i]:SetTexCoord(l, r, t, b)
+ digits[i].glow:SetTexCoord(l, r, t, b)
+
+ timeDigits = floor(timeDigits / 10)
+ numShown = numShown + 1
+ else
+ digits[i]:SetTexCoord(0, 0, 0, 0)
+ digits[i].glow:SetTexCoord(0, 0, 0, 0)
+ end
+
+ i = i + 1
+ end
+
+ if numberOffset > 0 then
+ digits[1]:ClearAllPoints()
+
+ if timer.anchorCenter then
+ digits[1]:Point("CENTER", UIParent, "CENTER", numberOffset - digits[1].hw, 0)
+ else
+ digits[1]:Point("CENTER", timer, "CENTER", numberOffset - digits[1].hw, 0)
+ end
+
+ for j = 2, numShown do
+ digits[j]:ClearAllPoints()
+ digits[j]:Point("CENTER", digits[j-1], "CENTER", -(digits[j].hw + digits[j-1].hw), 0)
+ end
+ end
+end
+
+function TT:SetGoTexture(timer)
+ if timer.type == TIMER_TYPE_PVP then
+ local factionGroup = UnitFactionGroup("player")
+
+ if factionGroup and factionGroup ~= "Neutral" then
+ timer.GoTexture:SetTexture("Interface\\AddOns\\ElvUI\\media\\textures\\"..factionGroup.."-Logo")
+ timer.GoTextureGlow:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\media\\textures\\"..factionGroup.."Glow-Logo")
+ end
+ elseif timer.type == TIMER_TYPE_CHALLENGE_MODE then
+ timer.GoTexture:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\media\\textures\\Challenges-Logo")
+ timer.GoTextureGlow:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\media\\textures\\ChallengesGlow-Logo")
+ end
+end
+
+function TT:NumberAnimOnFinished(timer)
+ timer.time = timer.time - 1
+
+ if timer.time > 0 then
+ if timer.time < TIMER_DATA[timer.type].largeMarker then
+ self:SwitchToLargeDisplay(timer)
+ end
+
+ timer.digit.startNumbers:Play()
+ else
+ timer.anchorCenter = false
+ timer.isFree = true
+ timer.GoTexture.GoTextureAnim:Play()
+ timer.GoTextureGlow.GoTextureAnim:Play()
+ end
+end
+
+function TT:SwitchToLargeDisplay(timer)
+ if not timer.anchorCenter then
+ timer.anchorCenter = true
+
+ timer.digit1.width = timer.style.w
+ timer.digit2.width = timer.style.w
+
+ timer.digit1:Size(timer.style.w, timer.style.h)
+ timer.digit2:Size(timer.style.w, timer.style.h)
+ end
+end
+
+function TT:ReleaseTimers()
+ for _, timer in ipairs(self.timerList) do
+ timer.barShowing = false
+ timer.isFree = true
+ end
+end
+
+function TT:OnEvent(event, msg)
+ if event == "CHAT_MSG_BG_SYSTEM_NEUTRAL" then
+ if msg and chatMessage[msg] then
+ self:CreateTimer(unpack(chatMessage[msg]))
+ end
+ elseif event == "PLAYER_ENTERING_WORLD" then
+ self:ReleaseTimers()
+ end
+end
+
+function TT:HookDBM()
+ if not DBM then return end
+
+ if E.db.enhanced.timerTracker.dbm then
+ self:SecureHook(DBM, "CreatePizzaTimer", function(_, time, text)
+ if text == DBM_CORE_TIMER_PULL then
+ DBM.Bars:CancelBar(DBM_CORE_TIMER_PULL)
+ time = tonumber(time)
+ self:CreateTimer(2, time, time)
+ end
+ end)
+ else
+ self:Unhook(DBM, "CreatePizzaTimer")
+ end
+end
+
+function TT:ToggleState()
+ if E.db.enhanced.timerTracker.enable then
+ self.timerList = self.timerList or {}
+
+ self:RegisterEvent("CHAT_MSG_BG_SYSTEM_NEUTRAL", "OnEvent")
+ self:RegisterEvent("PLAYER_ENTERING_WORLD", "OnEvent")
+
+ self:HookDBM()
+ else
+ self:UnregisterEvent("CHAT_MSG_BG_SYSTEM_NEUTRAL")
+ self:UnregisterEvent("PLAYER_ENTERING_WORLD")
+
+ self:Unhook(DBM, "CreatePizzaTimer")
+ self:ReleaseTimers()
+ end
+end
+
+function TT:Initialize()
+ if not E.db.enhanced.timerTracker.enable then return end
+
+ self:ToggleState()
+end
+
+local function InitializeCallback()
+ TT:Initialize()
+end
+
+E:RegisterModule(TT:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Blizzard/TimerTracker.xml b/ElvUI_Enhanced/Modules/Blizzard/TimerTracker.xml
new file mode 100644
index 0000000..5083f2d
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Blizzard/TimerTracker.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local frame = self:GetParent():GetParent()
+ ElvUI[1]:GetModule("Enhanced_TimerTracker"):SetTexNumbers(frame, frame.digit.digit1, frame.digit.digit2)
+
+
+ local frame = self:GetParent():GetParent()
+ ElvUI[1]:GetModule("Enhanced_TimerTracker"):NumberAnimOnFinished(frame)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ElvUI[1]:GetModule("Enhanced_TimerTracker"):OnShow(self)
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Chat/DPSLinks.lua b/ElvUI_Enhanced/Modules/Chat/DPSLinks.lua
new file mode 100644
index 0000000..0367441
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Chat/DPSLinks.lua
@@ -0,0 +1,198 @@
+local E, L, V, P, G = unpack(ElvUI)
+local EDL = E:NewModule("Enhanced_DPSLinks", "AceHook-3.0")
+
+local find, format, gsub, split = string.find, string.format, string.gsub, string.split
+local tinsert = table.insert
+local ipairs, tonumber = ipairs, tonumber
+
+local GetTime = GetTime
+local ShowUIPanel = ShowUIPanel
+
+local ItemRefTooltip = ItemRefTooltip
+
+local channelEvents = {
+ "CHAT_MSG_CHANNEL",
+ "CHAT_MSG_GUILD",
+ "CHAT_MSG_OFFICER",
+ "CHAT_MSG_PARTY",
+ "CHAT_MSG_PARTY_LEADER",
+ "CHAT_MSG_RAID",
+ "CHAT_MSG_RAID_LEADER",
+ "CHAT_MSG_SAY",
+ "CHAT_MSG_WHISPER",
+ "CHAT_MSG_WHISPER_INFORM",
+ "CHAT_MSG_YELL",
+ "CHAT_MSG_BN_WHISPER",
+ "CHAT_MSG_BN_WHISPER_INFORM",
+}
+
+local spamFirstLines = {
+ "^Recount - (.*)$", -- Recount
+ "^Skada: (.*) for (.*):$", -- Skada enUS
+ "^Skada: (.*) por (.*):$", -- Skada esES/ptBR
+ "^Skada: (.*) für (.*):$", -- Skada deDE
+-- "^Skada: (.*) fur (.*):$", -- Skada deDE
+ "^Skada: (.*) pour (.*):$", -- Skada frFR
+-- "^Skada: (.*) per (.*):$", -- Skada itIT
+ "^(.*) 의 Skada 보고 (.*):$", -- Skada koKR
+ "^Отчёт Skada: (.*), с (.*):$", -- Skada ruRU
+ "^Skada报告(.*)的(.*):$", -- Skada zhCN
+ "^Skada:(.*)來自(.*):$", -- Skada zhTW
+ "^(.*) Done for (.*)$", -- TinyDPS
+}
+
+local spamNextLines = {
+ "^(%d+)%. (.*)$", -- Recount, Skada
+ "^ (%d+). (.*)$", -- Skada
+-- "^(.*) (.*)$", -- Additional Skada
+ "^.*%%%)$", -- Skada player details
+ "^(%d+). (.*):(.*)(%d+)(.*)(%d+)%%(.*)%((%d+)%)$", -- TinyDPS
+}
+
+function EDL:FilterLine(event, source, msg, ...)
+ for _, line in ipairs(spamNextLines) do
+ if msg:match(line) then
+ local curTime = GetTime()
+
+ for _, meter in ipairs(self.Meters) do
+ local elapsed = curTime - meter.time
+
+ if meter.src == source and meter.evt == event and elapsed < 1 then
+ local toInsert = true
+
+ for _, b in ipairs(meter.data) do
+ if b == msg then
+ toInsert = false
+ end
+ end
+
+ if toInsert then
+ tinsert(meter.data,msg)
+ end
+
+ return true, false, nil
+ end
+ end
+ end
+ end
+
+ for i, line in ipairs(spamFirstLines) do
+ local newID = 0
+
+ if msg:match(line) then
+ local curTime = GetTime()
+
+ if find(msg, "|cff(.+)|r") then
+ msg = gsub(msg, "|cff%w%w%w%w%w%w", "")
+ msg = gsub(msg, "|r", "")
+ end
+
+ for id, meter in ipairs(self.Meters) do
+ local elapsed = curTime - meter.time
+
+ if meter.src == source and meter.evt == event and elapsed < 1 then
+ newID = id
+ return true, true, format("|HEDL:%1$d|h|cFFFFFF00[%2$s]|r|h", newID or 0, msg or "nil")
+ end
+ end
+
+ tinsert(self.Meters, {src = source, evt = event, time = curTime, data = {}, title = msg})
+
+ for id, meter in ipairs(self.Meters) do
+ if meter.src == source and meter.evt == event and meter.time == curTime then
+ newID = id
+ end
+ end
+
+ return true, true, format("|HEDL:%1$d|h|cFFFFFF00[%2$s]|r|h", newID or 0, msg or "nil")
+ end
+ end
+
+ return false, false, nil
+end
+
+function EDL:ParseChatEvent(event, msg, sender, ...)
+ local isMeter, isFirstLine, newMessage = EDL:FilterLine(event, sender, msg)
+ if isMeter then
+ if isFirstLine then
+ return false, newMessage, sender, ...
+ else
+ return true
+ end
+ end
+end
+
+function EDL:SetItemRef(link, text, button, chatframe)
+ local linktype, id = split(":", link)
+
+ if linktype == "EDL" then
+ local meterID = tonumber(id)
+
+ ShowUIPanel(ItemRefTooltip)
+
+ if not ItemRefTooltip:IsShown() then
+ ItemRefTooltip:SetOwner(UIParent, "ANCHOR_PRESERVE")
+ end
+
+ ItemRefTooltip:ClearLines()
+ ItemRefTooltip:AddLine(self.Meters[meterID].title)
+ ItemRefTooltip:AddLine(format(L["Reported by %s"], self.Meters[meterID].src))
+
+ for _, message in ipairs(self.Meters[meterID].data) do
+ ItemRefTooltip:AddLine(message, 1, 1, 1)
+ end
+
+ ItemRefTooltip:Show()
+
+ return nil
+ end
+
+ return self.hooks.SetItemRef(link, text, button, chatframe)
+end
+
+function EDL:ItemRefTooltip_SetHyperlink(tt, link, ...)
+ if link:sub(0, 4) == "EDL:" then return end
+
+ return EDL.hooks[tt].SetHyperlink(tt, link, ...)
+end
+
+function EDL:UpdateSettings()
+ if E.db.enhanced.chat.dpsLinks then
+ if not self:IsHooked("SetItemRef") then
+ self:RawHook("SetItemRef", true)
+ end
+ if not self:IsHooked(ItemRefTooltip, "SetHyperlink") then
+ self:RawHook(ItemRefTooltip, "SetHyperlink", "ItemRefTooltip_SetHyperlink")
+ end
+
+ if not self.FiltersRegistered then
+ for _, event in ipairs(channelEvents) do
+ ChatFrame_AddMessageEventFilter(event, self.ParseChatEvent)
+ end
+
+ self.FiltersRegistered = true
+ end
+ else
+ self:UnhookAll()
+
+ if self.FiltersRegistered then
+ for _, event in ipairs(channelEvents) do
+ ChatFrame_RemoveMessageEventFilter(event, self.ParseChatEvent)
+ end
+
+ self.FiltersRegistered = false
+ end
+ end
+end
+
+function EDL:Initialize()
+ self.Meters = {}
+
+ self:UpdateSettings()
+end
+
+local function InitializeCallback()
+ EDL:Initialize()
+end
+
+E:RegisterModule(EDL:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Chat/Load_Chat.xml b/ElvUI_Enhanced/Modules/Chat/Load_Chat.xml
new file mode 100644
index 0000000..0137483
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Chat/Load_Chat.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Datatexts/Agility.lua b/ElvUI_Enhanced/Modules/Datatexts/Agility.lua
new file mode 100644
index 0000000..19c7d37
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Datatexts/Agility.lua
@@ -0,0 +1,30 @@
+local E, L, V, P, G = unpack(ElvUI)
+local DT = E:GetModule("DataTexts")
+local EE = E:GetModule("ElvUI_Enhanced")
+
+local select = select
+local join = string.join
+
+local UnitStat = UnitStat
+
+local AGILITY_COLON = AGILITY_COLON
+local SPELL_STAT2_NAME = SPELL_STAT2_NAME
+
+local displayNumberString = ""
+local lastPanel
+
+local function OnEvent(self, event, ...)
+ self.text:SetFormattedText(displayNumberString, AGILITY_COLON, select(2, UnitStat("player", 2)))
+ lastPanel = self
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", "%s ", hex, "%.f|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Agility", {"UNIT_STATS", "UNIT_AURA", "ACTIVE_TALENT_GROUP_CHANGED", "PLAYER_TALENT_UPDATE"}, OnEvent, nil, nil, nil, nil, EE:ColorizeSettingName(SPELL_STAT2_NAME))
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Datatexts/Ammo.lua b/ElvUI_Enhanced/Modules/Datatexts/Ammo.lua
new file mode 100644
index 0000000..a72cf7c
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Datatexts/Ammo.lua
@@ -0,0 +1,132 @@
+local E, L, V, P, G = unpack(ElvUI)
+local DT = E:GetModule("DataTexts")
+local EE = E:GetModule("ElvUI_Enhanced")
+
+local select = select
+local format, join = string.format, string.join
+
+local ContainerIDToInventoryID = ContainerIDToInventoryID
+local GetAuctionItemSubClasses = GetAuctionItemSubClasses
+local GetContainerItemID = GetContainerItemID
+local GetContainerItemLink = GetContainerItemLink
+local GetContainerNumFreeSlots = GetContainerNumFreeSlots
+local GetContainerNumSlots = GetContainerNumSlots
+local GetInventoryItemCount = GetInventoryItemCount
+local GetInventoryItemLink = GetInventoryItemLink
+local GetInventorySlotInfo = GetInventorySlotInfo
+local GetItemCount = GetItemCount
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+
+local NUM_BAG_SLOTS = NUM_BAG_SLOTS
+local NUM_BAG_FRAMES = NUM_BAG_FRAMES
+local INVTYPE_AMMO = INVTYPE_AMMO
+
+local quiver = select(1, GetAuctionItemSubClasses(8))
+local pouch = select(2, GetAuctionItemSubClasses(8))
+local soulBag = select(2, GetAuctionItemSubClasses(3))
+
+local iconString = "|T%s:16:16:0:0:64:64:4:55:4:55|t"
+local displayString = ""
+
+local lastPanel
+
+local function OnEvent(self)
+ local name, count, link
+ if E.myclass == "WARLOCK" then
+ name = GetItemInfo(6265)
+ count = GetItemCount(6265)
+ if count > 0 then
+ self.text:SetFormattedText(displayString, name, count)
+ else
+ self.text:SetFormattedText(displayString, name, 0)
+ end
+ else
+ link = GetInventoryItemLink("player", GetInventorySlotInfo("AmmoSlot"))
+ count = GetInventoryItemCount("player", GetInventorySlotInfo("AmmoSlot"))
+ if link and (count > 0) then
+ name = GetItemInfo(link)
+ self.text:SetFormattedText(displayString, name, count)
+ else
+ self.text:SetFormattedText(displayString, INVTYPE_AMMO, 0)
+ end
+ end
+
+ lastPanel = self
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+ DT.tooltip:AddLine(INVTYPE_AMMO)
+
+ local r, g, b
+ local item, link, count
+ local _, name, quality, subclass, equipLoc, texture
+ local free, total, used
+
+ for i = 0, NUM_BAG_FRAMES do
+ for j = 1, GetContainerNumSlots(i) do
+ item = GetContainerItemID(i, j)
+ if item then
+ link = GetContainerItemLink(i, j)
+ name, _, quality, _, _, _, _, _, equipLoc, texture = GetItemInfo(link)
+ count = GetItemCount(link)
+
+ if equipLoc == "INVTYPE_AMMO" then
+ r, g, b = GetItemQualityColor(quality)
+ DT.tooltip:AddDoubleLine(join("", format(iconString, texture), " ", name), count, r, g, b)
+ end
+ end
+ end
+ end
+
+ DT.tooltip:AddLine(" ")
+
+ for i = 1, NUM_BAG_SLOTS do
+ link = GetInventoryItemLink("player", ContainerIDToInventoryID(i))
+ if link then
+ name, _, quality, _, _, _, subclass, _, _, texture = GetItemInfo(link)
+
+ if subclass == quiver or subclass == pouch or subclass == soulBag then
+ r, g, b = GetItemQualityColor(quality)
+
+ free, total = GetContainerNumFreeSlots(i), GetContainerNumSlots(i)
+ used = total - free
+
+ DT.tooltip:AddLine(subclass)
+ DT.tooltip:AddDoubleLine(join("", format(iconString, texture), " ", name), format("%d / %d", used, total), r, g, b)
+ end
+ end
+ end
+
+ DT.tooltip:Show()
+end
+
+local function OnClick(_, btn)
+ if btn == "LeftButton" then
+ if not E.bags then
+ for i = 1, NUM_BAG_SLOTS do
+ local link = GetInventoryItemLink("player", ContainerIDToInventoryID(i))
+ if link then
+ local subclass = select(7, GetItemInfo(link))
+ if subclass == quiver or subclass == pouch or subclass == soulBag then
+ ToggleBag(i)
+ end
+ end
+ end
+ else
+ OpenAllBags()
+ end
+ end
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", "%s: ", hex, "%d|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext(INVTYPE_AMMO, {"PLAYER_ENTERING_WORLD", "BAG_UPDATE", "UNIT_INVENTORY_CHANGED"}, OnEvent, nil, OnClick, OnEnter, nil, EE:ColorizeSettingName(L["Ammo/Shard Counter"]))
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Datatexts/CombatIndicator.lua b/ElvUI_Enhanced/Modules/Datatexts/CombatIndicator.lua
new file mode 100644
index 0000000..2beacee
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Datatexts/CombatIndicator.lua
@@ -0,0 +1,19 @@
+local E, L, V, P, G = unpack(ElvUI)
+local DT = E:GetModule("DataTexts")
+local EE = E:GetModule("ElvUI_Enhanced")
+
+local function OnEvent(self, event, ...)
+ if event == "PLAYER_REGEN_ENABLED" then
+ self.text:SetText(L["Out of Combat"])
+ self.text:SetTextColor(1, 1, 1)
+ return
+ elseif event == "PLAYER_REGEN_DISABLED" then
+ self.text:SetText(L["In Combat"])
+ self.text:SetTextColor(1, 0, 0)
+ return
+ end
+ self.text:SetText(L["Out of Combat"])
+ self.text:SetTextColor(1, 1, 1)
+end
+
+DT:RegisterDatatext("Combat Indicator", {"PLAYER_ENTERING_WORLD", "PLAYER_REGEN_ENABLED", "PLAYER_REGEN_DISABLED"}, OnEvent, nil, nil, nil, nil, EE:ColorizeSettingName(L["Combat Indicator"]))
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Datatexts/Intellect.lua b/ElvUI_Enhanced/Modules/Datatexts/Intellect.lua
new file mode 100644
index 0000000..dbcd061
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Datatexts/Intellect.lua
@@ -0,0 +1,30 @@
+local E, L, V, P, G = unpack(ElvUI)
+local DT = E:GetModule("DataTexts")
+local EE = E:GetModule("ElvUI_Enhanced")
+
+local select = select
+local join = string.join
+
+local UnitStat = UnitStat
+
+local INTELLECT_COLON = INTELLECT_COLON
+local SPELL_STAT4_NAME = SPELL_STAT4_NAME
+
+local displayNumberString = ""
+local lastPanel
+
+local function OnEvent(self)
+ self.text:SetFormattedText(displayNumberString, INTELLECT_COLON, select(2, UnitStat("player", 4)))
+ lastPanel = self
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", "%s ", hex, "%.f|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Intellect", {"UNIT_STATS", "UNIT_AURA", "ACTIVE_TALENT_GROUP_CHANGED", "PLAYER_TALENT_UPDATE"}, OnEvent, nil, nil, nil, nil, EE:ColorizeSettingName(SPELL_STAT4_NAME))
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Datatexts/ItemLevel.lua b/ElvUI_Enhanced/Modules/Datatexts/ItemLevel.lua
new file mode 100644
index 0000000..4b0b1d0
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Datatexts/ItemLevel.lua
@@ -0,0 +1,107 @@
+local E, L, V, P, G = unpack(ElvUI)
+local DT = E:GetModule("DataTexts")
+local EE = E:GetModule("ElvUI_Enhanced")
+
+local select = select
+local floor = math.floor
+local join = string.join
+
+local GetInventoryItemLink = GetInventoryItemLink
+local GetInventorySlotInfo = GetInventorySlotInfo
+local GetItemQualityColor = GetItemQualityColor
+local GetItemInfo = GetItemInfo
+
+local displayString = ""
+local lastPanel
+
+local slots = {
+ {"HeadSlot", HEADSLOT},
+ {"NeckSlot", NECKSLOT},
+ {"ShoulderSlot", SHOULDERSLOT},
+ {"BackSlot", BACKSLOT},
+ {"ChestSlot", CHESTSLOT},
+ {"WristSlot", WRISTSLOT},
+ {"HandsSlot", HANDSSLOT},
+ {"WaistSlot", WAISTSLOT},
+ {"LegsSlot", LEGSSLOT},
+ {"FeetSlot", FEETSLOT},
+ {"Finger0Slot", FINGER0SLOT_UNIQUE},
+ {"Finger1Slot", FINGER1SLOT_UNIQUE},
+ {"Trinket0Slot", TRINKET0SLOT_UNIQUE},
+ {"Trinket1Slot", TRINKET1SLOT_UNIQUE},
+ {"MainHandSlot", MAINHANDSLOT},
+ {"SecondaryHandSlot", SECONDARYHANDSLOT},
+ {"RangedSlot", RANGEDSLOT}
+}
+
+local levelColors = {
+ [0] = {1, 0, 0},
+ [1] = {0, 1, 0},
+ [2] = {1, 1, 0.5}
+}
+
+local function GetItemLvL()
+ local total, item = 0, 0
+ local itemLink, itemLevel
+
+ for i = 1, #slots do
+ itemLink = GetInventoryItemLink("player", GetInventorySlotInfo(slots[i][1]))
+ if itemLink then
+ itemLevel = select(4, GetItemInfo(itemLink))
+ if itemLevel and itemLevel > 0 then
+ item = item + 1
+ total = total + itemLevel
+ end
+ end
+ end
+
+ if total < 1 then
+ return "0"
+ end
+
+ return floor(total / item)
+end
+
+local function OnEvent(self)
+ self.text:SetFormattedText(displayString, L["Item Level"], GetItemLvL())
+ lastPanel = self
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ local avgEquipItemLevel = GetItemLvL()
+
+ DT.tooltip:AddDoubleLine(L["Item Level"], avgEquipItemLevel, nil, nil, nil, 0, 1, 0)
+ DT.tooltip:AddLine(" ")
+
+ local _, quality, itemLevel
+ local color, itemLink
+ local r, g, b
+
+ for i = 1, #slots do
+ itemLink = GetInventoryItemLink("player", GetInventorySlotInfo(slots[i][1]))
+ if itemLink then
+ _, _, quality, itemLevel = GetItemInfo(itemLink)
+ r, g, b = GetItemQualityColor(quality)
+
+ if itemLevel and avgEquipItemLevel then
+ color = levelColors[(itemLevel < avgEquipItemLevel - 5 and 0 or (itemLevel > avgEquipItemLevel + 5 and 1 or 2))]
+ DT.tooltip:AddDoubleLine(slots[i][2], itemLevel, r, g, b, color[1], color[2], color[3])
+ end
+ end
+ end
+
+ DT.tooltip:Show()
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", "%s: ", hex, "%d|r")
+
+ if lastPanel then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Item Level", {"PLAYER_ENTERING_WORLD", "PLAYER_EQUIPMENT_CHANGED", "UNIT_INVENTORY_CHANGED"}, OnEvent, nil, nil, OnEnter, nil, EE:ColorizeSettingName(L["Item Level"]))
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Datatexts/Load_Datatexts.xml b/ElvUI_Enhanced/Modules/Datatexts/Load_Datatexts.xml
new file mode 100644
index 0000000..fa8b7ae
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Datatexts/Load_Datatexts.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Datatexts/Mail.lua b/ElvUI_Enhanced/Modules/Datatexts/Mail.lua
new file mode 100644
index 0000000..40e6b86
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Datatexts/Mail.lua
@@ -0,0 +1,73 @@
+local E, L, V, P, G = unpack(ElvUI)
+local DT = E:GetModule("DataTexts")
+local EE = E:GetModule("ElvUI_Enhanced")
+
+local GetInboxHeaderInfo = GetInboxHeaderInfo
+local GetInboxNumItems = GetInboxNumItems
+local GetLatestThreeSenders = GetLatestThreeSenders
+local HasNewMail = HasNewMail
+
+local MAIL_LABEL = MAIL_LABEL
+local HAVE_MAIL_FROM = HAVE_MAIL_FROM
+
+local Mail_Icon = "|TInterface\\MINIMAP\\TRACKING\\Mailbox.blp:14:14|t"
+local Read
+
+local function MakeIconString()
+ local str = ""
+ str = str..Mail_Icon
+
+ return str
+end
+
+local unreadMail
+local function OnEvent(self, event, ...)
+ local newMail = false
+ if event == "UPDATE_PENDING_MAIL" or event == "PLAYER_ENTERING_WORLD" or event == "PLAYER_LOGIN" then
+ newMail = HasNewMail()
+ if unreadMail ~= newMail then
+ unreadMail = newMail
+ end
+ self:UnregisterEvent("PLAYER_ENTERING_WORLD")
+ self:UnregisterEvent("PLAYER_LOGIN")
+ end
+ if event == "MAIL_INBOX_UPDATE" or event == "MAIL_SHOW" or event == "MAIL_CLOSED" then
+ for i = 1, GetInboxNumItems() do
+ local _, _, _, _, _, _, _, _, wasRead = GetInboxHeaderInfo(i)
+ if not wasRead then
+ newMail = true
+ break
+ end
+ end
+ end
+
+ if newMail then
+ self.text:SetText(MakeIconString()..L["New Mail"])
+ self.text:SetTextColor(0, 1, 0)
+ Read = false
+ else
+ self.text:SetText(L["No Mail"])
+ self.text:SetTextColor(1, 1, 1)
+ Read = true
+ end
+end
+
+local function OnUpdate(self)
+ OnEvent(self, "UPDATE_PENDING_MAIL")
+ self:SetScript("OnUpdate", nil)
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ local sender1, sender2, sender3 = GetLatestThreeSenders()
+ if not Read then
+ DT.tooltip:AddLine(HAVE_MAIL_FROM)
+ if sender1 then DT.tooltip:AddLine(" "..sender1) end
+ if sender2 then DT.tooltip:AddLine(" "..sender2) end
+ if sender3 then DT.tooltip:AddLine(" "..sender3) end
+ end
+ DT.tooltip:Show()
+end
+
+DT:RegisterDatatext("Mail", {"PLAYER_ENTERING_WORLD", "MAIL_INBOX_UPDATE", "UPDATE_PENDING_MAIL", "MAIL_CLOSED", "PLAYER_LOGIN", "MAIL_SHOW"}, OnEvent, OnUpdate, nil, OnEnter, nil, EE:ColorizeSettingName(MAIL_LABEL))
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Datatexts/Range.lua b/ElvUI_Enhanced/Modules/Datatexts/Range.lua
new file mode 100644
index 0000000..223cedc
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Datatexts/Range.lua
@@ -0,0 +1,60 @@
+local E, L, V, P, G = unpack(ElvUI)
+local DT = E:GetModule("DataTexts")
+local EE = E:GetModule("ElvUI_Enhanced")
+local LRC = LibStub("LibRangeCheck-2.0")
+
+local join = string.join
+
+local UnitName = UnitName
+
+local int = 1
+local updateTargetRange = false
+local forceUpdate = false
+local displayString = ""
+
+local curMin, curMax
+local lastPanel
+
+local function OnUpdate(self, t)
+ if not updateTargetRange then return end
+
+ int = int - t
+ if int > 0 then return end
+ int = 0.25
+
+ local min, max = LRC:GetRange("target");
+ if not forceUpdate and (min == curMin and max == curMax) then return end
+
+ curMin = min
+ curMax = max
+
+ if min and max then
+ self.text:SetFormattedText(displayString, L["Distance"], min, max)
+ else
+ self.text:SetText("")
+ end
+ forceUpdate = false
+
+ lastPanel = self
+end
+
+local function OnEvent(self)
+ updateTargetRange = UnitName("target") ~= nil
+ int = 0
+ if updateTargetRange then
+ forceUpdate = true
+ else
+ self.text:SetText("")
+ end
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", "%s: ", hex, "%d|r - ", hex, "%d|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Target Range", {"PLAYER_TARGET_CHANGED"}, OnEvent, OnUpdate, nil, nil, nil, EE:ColorizeSettingName(L["Target Range"]))
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Datatexts/Reincarnation.lua b/ElvUI_Enhanced/Modules/Datatexts/Reincarnation.lua
new file mode 100644
index 0000000..67cdafa
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Datatexts/Reincarnation.lua
@@ -0,0 +1,109 @@
+local E, L, V, P, G = unpack(ElvUI)
+local DT = E:GetModule("DataTexts")
+local EE = E:GetModule("ElvUI_Enhanced")
+
+if E.myclass ~= "SHAMAN" then return end
+
+local floor = math.floor
+local format, join = string.format, string.join
+
+local GetItemCount = GetItemCount
+local GetItemInfo = GetItemInfo
+local GetSpellCooldown = GetSpellCooldown
+local GetTime = GetTime
+local IsInInstance = IsInInstance
+local IsSpellKnown = IsSpellKnown
+
+local READY = READY
+local SPELL_FAILED_NOT_KNOWN = SPELL_FAILED_NOT_KNOWN
+local TIME_REMAINING = TIME_REMAINING
+
+local iconString = "|T%s:20:20:0:0:64:64:4:55:4:55|t"
+local tex = "Interface\\Icons\\Spell_Nature_Reincarnation"
+local displayString = ""
+
+local lastPanel
+
+local function OnUpdate(self)
+ local isKnown = IsSpellKnown(20608, false)
+ if not isKnown then return end
+
+ local start, duration = GetSpellCooldown(20608)
+ if start > 0 and duration > 0 then
+ self.text:SetFormattedText(displayString, format(iconString, tex), format("%d:%02d", floor((duration - (GetTime() - start)) / 60), floor((duration - (GetTime() - start)) % 60)))
+ else
+ self.text:SetFormattedText(displayString, format(iconString, tex), READY.."!")
+ end
+end
+
+local function OnEvent(self, event)
+ local isKnown = IsSpellKnown(20608, false)
+
+ if not isKnown then
+ self.text:SetFormattedText(displayString, format(iconString, tex), SPELL_FAILED_NOT_KNOWN)
+ else
+ if event == "SPELL_UPDATE_COOLDOWN" then
+ self:SetScript("OnUpdate", OnUpdate)
+ elseif not self.text:GetText() then
+ local start, duration = GetSpellCooldown(20608)
+ if start > 0 and duration > 0 then
+ self.text:SetFormattedText(displayString, format(iconString, tex), format("%d:%02d", floor((duration - (GetTime() - start)) / 60), floor((duration - (GetTime() - start)) % 60)))
+ else
+ self.text:SetFormattedText(displayString, format(iconString, tex), READY.."!")
+ end
+ end
+ end
+
+ lastPanel = self
+end
+
+local function OnClick(self)
+ local isKnown = IsSpellKnown(20608, false)
+ if not isKnown then return end
+
+ local _, instanceType = IsInInstance()
+ local start, duration = GetSpellCooldown(20608)
+ local message = L["Reincarnation"].." - "..TIME_REMAINING.." "..format("%d:%02d", floor((duration - (GetTime() - start)) / 60), floor((duration - (GetTime() - start)) % 60))
+ local message2 = L["Reincarnation"].." - "..READY.."!"
+
+ if start > 0 and duration > 0 then
+ if instanceType == "raid" then
+ SendChatMessage(message , "RAID", nil, nil)
+ elseif instanceType == "party" then
+ SendChatMessage(message , "PARTY", nil, nil)
+ end
+ else
+ if instanceType == "raid" then
+ SendChatMessage(message2 , "RAID", nil, nil)
+ elseif instanceType == "party" then
+ SendChatMessage(message2 , "PARTY", nil, nil)
+ end
+ end
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ DT.tooltip:AddLine(L["Reincarnation"])
+ DT.tooltip:AddLine(" ")
+
+ local name, _, _, _, _, _, _, _, _, texture = GetItemInfo(17030)
+ local count = GetItemCount(17030)
+
+ if name then
+ DT.tooltip:AddDoubleLine(join("", format(iconString, texture), " ", name), count, 1, 1, 1)
+ end
+
+ DT.tooltip:Show()
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", "%s ", hex, "%s|r")
+
+ if lastPanel ~= nil
+ then OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Reincarnation", {"PLAYER_ENTERING_WORLD", "SPELL_UPDATE_COOLDOWN"}, OnEvent, OnUpdate, OnClick, OnEnter, nil, EE:ColorizeSettingName(L["Reincarnation"]))
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Datatexts/Spirit.lua b/ElvUI_Enhanced/Modules/Datatexts/Spirit.lua
new file mode 100644
index 0000000..21020eb
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Datatexts/Spirit.lua
@@ -0,0 +1,30 @@
+local E, L, V, P, G = unpack(ElvUI)
+local DT = E:GetModule("DataTexts")
+local EE = E:GetModule("ElvUI_Enhanced")
+
+local select = select
+local join = string.join
+
+local UnitStat = UnitStat
+
+local SPIRIT_COLON = SPIRIT_COLON
+local SPELL_STAT5_NAME = SPELL_STAT5_NAME
+
+local displayNumberString = ""
+local lastPanel
+
+local function OnEvent(self)
+ self.text:SetFormattedText(displayNumberString, SPIRIT_COLON, select(2, UnitStat("player", 5)))
+ lastPanel = self
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", "%s ", hex, "%.f|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Spirit", {"UNIT_STATS", "UNIT_AURA", "ACTIVE_TALENT_GROUP_CHANGED", "PLAYER_TALENT_UPDATE"}, OnEvent, nil, nil, nil, nil, EE:ColorizeSettingName(SPELL_STAT5_NAME))
diff --git a/ElvUI_Enhanced/Modules/Datatexts/Stamina.lua b/ElvUI_Enhanced/Modules/Datatexts/Stamina.lua
new file mode 100644
index 0000000..5fa2444
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Datatexts/Stamina.lua
@@ -0,0 +1,30 @@
+local E, L, V, P, G = unpack(ElvUI)
+local DT = E:GetModule("DataTexts")
+local EE = E:GetModule("ElvUI_Enhanced")
+
+local select = select
+local join = string.join
+
+local UnitStat = UnitStat
+
+local STAMINA_COLON = STAMINA_COLON
+local SPELL_STAT3_NAME = SPELL_STAT3_NAME
+
+local displayNumberString = ""
+local lastPanel
+
+local function OnEvent(self)
+ self.text:SetFormattedText(displayNumberString, STAMINA_COLON, select(2, UnitStat("player", 3)))
+ lastPanel = self
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", "%s ", hex, "%.f|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Stamina", {"UNIT_STATS", "UNIT_AURA", "ACTIVE_TALENT_GROUP_CHANGED", "PLAYER_TALENT_UPDATE"}, OnEvent, nil, nil, nil, nil, EE:ColorizeSettingName(SPELL_STAT3_NAME))
diff --git a/ElvUI_Enhanced/Modules/Datatexts/Strength.lua b/ElvUI_Enhanced/Modules/Datatexts/Strength.lua
new file mode 100644
index 0000000..af00f38
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Datatexts/Strength.lua
@@ -0,0 +1,30 @@
+local E, L, V, P, G = unpack(ElvUI)
+local DT = E:GetModule("DataTexts")
+local EE = E:GetModule("ElvUI_Enhanced")
+
+local select = select
+local join = string.join
+
+local UnitStat = UnitStat
+
+local STRENGTH_COLON = STRENGTH_COLON
+local SPELL_STAT1_NAME = SPELL_STAT1_NAME
+
+local displayNumberString = ""
+local lastPanel
+
+local function OnEvent(self)
+ self.text:SetFormattedText(displayNumberString, STRENGTH_COLON, select(2, UnitStat("player", 1)))
+ lastPanel = self
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", "%s ", hex, "%.f|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Strength", {"UNIT_STATS", "UNIT_AURA", "ACTIVE_TALENT_GROUP_CHANGED", "PLAYER_TALENT_UPDATE"}, OnEvent, nil, nil, nil, nil, EE:ColorizeSettingName(SPELL_STAT1_NAME))
diff --git a/ElvUI_Enhanced/Modules/Load_Modules.xml b/ElvUI_Enhanced/Modules/Load_Modules.xml
new file mode 100644
index 0000000..9261ad8
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Load_Modules.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ElvUI_Enhanced/Modules/Maps/FogClear.lua b/ElvUI_Enhanced/Modules/Maps/FogClear.lua
new file mode 100644
index 0000000..da48bb0
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Maps/FogClear.lua
@@ -0,0 +1,1230 @@
+local E, L, V, P, G = unpack(ElvUI)
+local FC = E:NewModule("Enhanced_FogClear", "AceHook-3.0")
+
+local _G = _G
+local pairs = pairs
+local ceil, fmod, floor = math.ceil, math.fmod, math.floor
+local format, len, lower, sub = string.format, string.len, string.lower, string.sub
+local tinsert, twipe = table.insert, table.wipe
+
+local GetMapInfo = GetMapInfo
+local GetMapOverlayInfo = GetMapOverlayInfo
+local GetNumMapOverlays = GetNumMapOverlays
+
+local worldMapCache = {}
+local discoveredOverlays = {}
+
+local errata = {
+ -- Eastern Kingdoms
+ ["Alterac"] = {
+ ["CHILLWINDPOINT"] = 272313469278,
+ ["CORRAHNSDAGGER"] = 408440570051,
+ ["CRUSHRIDGEHOLD"] = 174296645912,
+ ["DALARAN"] = 281347928364,
+ ["DANDREDSFOLD"] = 289642781,
+ ["GALLOWSCORNER"] = 299999895752,
+ ["GAVINSNAZE"] = 513484700832,
+ ["GROWLESSCAVE"] = 399764531390,
+ ["LORDAMEREINTERNMENTCAMP"] = 432764364106,
+ ["MISTYSHORE"] = 140865986780,
+ ["RUINSOFALTERAC"] = 211810516223,
+ ["SOFERASNAZE"] = 330123510015,
+ ["STRAHNBRAD"] = 113318867314,
+ ["THEHEADLAND"] = 506061853861,
+ ["THEUPLANDS"] = 83162767595,
+ },
+--[[
+ ["AlteracValley"] = {
+ ["DUNBALDAR"] = 14323794190,
+ ["FROSTWOLFKEEP"] = 403071863019,
+ ["ICEBLOODGARRISON"] = 185035174188,
+ },
+]]
+ ["Arathi"] = {
+ ["BOULDERFISTHALL"] = 389147765975,
+ ["BOULDERGOR"] = 155936085237,
+ ["CIRCLEOFEASTBINDING"] = 120844425376,
+ ["CIRCLEOFINNERBINDING"] = 333160047826,
+ ["CIRCLEOFOUTERBINDING"] = 315045866666,
+ ["CIRCLEOFWESTBINDING"] = 58126977214,
+ ["DABYRIESFARMSTEAD"] = 177662544052,
+ ["FALDIRSCOVE"] = 455446060288,
+ ["GOSHEKFARM"] = 296909737190,
+ ["HAMMERFALL"] = 129536092365,
+ ["NORTHFOLDMANOR"] = 96838336742,
+ ["REFUGEPOINT"] = 200104182959,
+ ["STROMGARDEKEEP"] = 308277385456,
+ ["THANDOLSPAN"] = 442754101448,
+ ["THORADINSWALL"] = 148267843774,
+ ["WITHERBARKVILLAGE"] = 358142396631,
+ },
+ ["Badlands"] = {
+ ["AGMONDSEND"] = 418047605001,
+ ["ANGORFORTRESS"] = 159254782147,
+ ["APOCRYPHANSREST"] = 332878053632,
+ ["CAMPBOFF"] = 366671585535,
+ ["CAMPCAGG"] = 459574345984,
+ ["CAMPKOSH"] = 52117598428,
+ ["DUSTWINDGULCH"] = 224934442229,
+ ["HAMMERTOESDIGSITE"] = 129315835080,
+ ["KARGATH"] = 158914052352,
+ ["LETHLORRAVINE"] = 118752746866,
+ ["MIRAGEFLATS"] = 412472312064,
+ ["THEDUSTBOWL"] = 213841628430,
+ ["THEMAKERSTERRACE"] = 7924298997,
+ ["VALLEYOFFANGS"] = 275244095718,
+ },
+ ["BlastedLands"] = {
+ ["ALTAROFSTORMS"] = 143132880057,
+ ["DARKPORTAL"] = 278574362889,
+ ["DREADMAULHOLD"] = 16484847811,
+ ["DREADMAULPOST"] = 209758391541,
+ ["GARRISONARMORY"] = 10158809258,
+ ["NETHERGARDEKEEP"] = 32798603449,
+ ["RISEOFTHEDEFILER"] = 132495066282,
+ ["SERPENTSCOIL"] = 150849366241,
+ ["THETAINTEDSCAR"] = 191348803968,
+ },
+ ["BurningSteppes"] = {
+ ["ALTAROFSTORMS"] = 117075833057,
+ ["BLACKROCKMOUNTAIN"] = 108629614848,
+ ["BLACKROCKPASS"] = 300191897870,
+ ["BLACKROCKSTRONGHOLD"] = 122757063925,
+ ["DRACODAR"] = 277084433823,
+ ["DREADMAULROCK"] = 181130200284,
+ ["MORGANSVIGIL"] = 334676375846,
+ ["PILLAROFASH"] = 306412009792,
+ ["RUINSOFTHAURISSAN"] = 106838652174,
+ ["TERRORWINGPATH"] = 50149559576,
+ },
+ ["DeadwindPass"] = {
+ ["DEADMANSCROSSING"] = 81865848188,
+ ["KARAZHAN"] = 362133312812,
+ ["THEVICE"] = 321495775502,
+ },
+ ["DunMorogh"] = {
+ ["AMBERSTILLRANCH"] = 301248675968,
+ ["ANVILMAR"] = 432880674032,
+ ["BREWNALLVILLAGE"] = 267626073203,
+ ["CHILLBREEZEVALLEY"] = 318115020980,
+ ["COLDRIDGEPASS"] = 413700063382,
+ ["FROSTMANEHOLD"] = 308391572605,
+ ["GNOMERAGON"] = 197742728372,
+ ["GOLBOLARQUARRY"] = 313096574117,
+ ["HELMSBEDLAKE"] = 293859403931,
+ ["ICEFLOWLAKE"] = 179609718912,
+ ["IRONFORGE"] = 175436407099,
+ ["KHARANOS"] = 316085051592,
+ ["MISTYPINEREFUGE"] = 237823497344,
+ ["NORTHERNGATEOUTPOST"] = 186553373824,
+ ["SHIMMERRIDGE"] = 175383967872,
+ ["SOUTHERNGATEOUTPOST"] = 300404564096,
+ ["THEGRIZZLEDDEN"] = 334263149768,
+ ["THETUNDRIDHILLS"] = 346292355227,
+ },
+ ["Duskwood"] = {
+ ["ADDLESSTEAD"] = 367277631763,
+ ["BRIGHTWOODGROVE"] = 126156624092,
+ ["DARKSHIRE"] = 174608113979,
+ ["MANORMISTMANTLE"] = 129533918408,
+ ["RAVENHILL"] = 324377134275,
+ ["RAVENHILLCEMETARY"] = 160076968286,
+ ["THEDARKENEDBANK"] = 33379535758,
+ ["THEHUSHEDBANK"] = 141754181792,
+ ["THEROTTINGORCHARD"] = 396776151290,
+ ["THEYORGENFARMSTEAD"] = 410578577643,
+ ["TRANQUILGARDENSCEMETARY"] = 379754606812,
+ ["TWILIGHTGROVE"] = 85138510184,
+ ["VULGOLOGREMOUND"] = 373917250815,
+ },
+ ["EasternPlaguelands"] = {
+ ["BLACKWOODLAKE"] = 190484578560,
+ ["CORINSCROSSING"] = 370935070976,
+ ["CROWNGUARDTOWER"] = 407222092032,
+ ["DARROWSHIRE"] = 501730168064,
+ ["EASTWALLTOWER"] = 235739021568,
+ ["LAKEMERELDAR"] = 442878866688,
+ ["LIGHTSHOPECHAPEL"] = 298114613504,
+ ["NORTHDALE"] = 114435555584,
+ ["NORTHPASSTOWER"] = 93863543040,
+ ["PLAGUEWOOD"] = 65644298624,
+ ["PestilentScar"] = 289455505664,
+ ["QUELLITHIENLODGE"] = 15443689728,
+ ["STRATHOLME"] = 172215552,
+ ["ScarletEnclave"] = 234829056284,
+ ["TERRORDALE"] = 81656021248,
+ ["THEFUNGALVALE"] = 256877265152,
+ ["THEMARRISSTEAD"] = 363057119488,
+ ["THENOXIOUSGLADE"] = 155344699648,
+ ["THEUNDERCROFT"] = 488701623552,
+ ["THONDRORILRIVER"] = 224412434688,
+ ["TYRSHAND"] = 482830652672,
+ ["TheInfectisScar"] = 347216281856,
+ ["ZULMASHAR"] = 9202565376,
+ },
+ ["Elwynn"] = {
+ ["BRACKWELLPUMPKINPATCH"] = 450503107840,
+ ["CRYSTALLAKE"] = 356925010145,
+ ["EASTVALELOGGINGCAMP"] = 355073214720,
+ ["FARGODEEPMINE"] = 459811307776,
+ ["FORESTSEDGE"] = 351243949312,
+ ["GOLDSHIRE"] = 290172662000,
+ ["JERODSLANDING"] = 463228613888,
+ ["NORTHSHIREVALLEY"] = 158239817984,
+ ["RIDGEPOINTTOWER"] = 467807741234,
+ ["STONECAIRNLAKE"] = 204626723126,
+ ["STORMWIND"] = 415205,
+ ["TOWEROFAZORA"] = 314110634239,
+ },
+ ["EversongWoods"] = {
+ ["AzurebreezeCoast"] = 245514895616,
+ ["DuskwitherGrounds"] = 272291332352,
+ ["EastSanctum"] = 400988307712,
+ ["ElrendarFalls"] = 429031424128,
+ ["FairbreezeVilliage"] = 414869356800,
+ ["FarstriderRetreat"] = 386022899968,
+ ["GoldenboughPass"] = 503839850752,
+ ["LakeElrendar"] = 506344969344,
+ ["NorthSanctum"] = 320353861888,
+ ["RuinsofSilvermoon"] = 146351063296,
+ ["RunestoneFalithas"] = 532972482816,
+ ["RunestoneShandor"] = 530915178752,
+ ["SatherilsHaven"] = 412656861440,
+ ["SilvermoonCity"] = 93877436928,
+ ["StillwhisperPond"] = 337652220160,
+ ["SunsailAnchorage"] = 434034049280,
+ ["SunstriderIsle"] = 5573706240,
+ ["TheGoldenStrand"] = 445795005568,
+ ["TheLivingWood"] = 451507642496,
+ ["TheScortchedGrove"] = 544654622976,
+ ["ThuronsLivery"] = 328056570112,
+ ["TorWatha"] = 338908513536,
+ ["TranquilShore"] = 320200769792,
+ ["WestSanctum"] = 342830088320,
+ ["Zebwatha"] = 510608475264,
+ },
+ ["Ghostlands"] = {
+ ["AmaniPass"] = 249735598484,
+ ["BleedingZiggurat"] = 255743754496,
+ ["DawnstarSpire"] = 603193771,
+ ["Deatholme"] = 402753099264,
+ ["ElrendarCrossing"] = 342098432,
+ ["FarstriderEnclave"] = 146629984685,
+ ["GoldenmistVillage"] = 46662144,
+ ["HowlingZiggurat"] = 235506435328,
+ ["IsleofTribulations"] = 613679360,
+ ["SanctumoftheMoon"] = 135511933184,
+ ["SanctumoftheSun"] = 161531560192,
+ ["SuncrownVillage"] = 482607616,
+ ["ThalassiaPass"] = 436321130752,
+ ["Tranquillien"] = 2530738432,
+ ["WindrunnerSpire"] = 308206108928,
+ ["WindrunnerVillage"] = 125691232512,
+ ["ZebNowa"] = 254965890560,
+ },
+ ["Hilsbrad"] = {
+ ["AZURELOADMINE"] = 295462707365,
+ ["DARROWHILL"] = 165790510285,
+ ["DUNGAROK"] = 316348321008,
+ ["DURNHOLDEKEEP"] = 81165399424,
+ ["EASTERNSTRAND"] = 364548260070,
+ ["HILLSBRADFIELDS"] = 166637882673,
+ ["NETHANDERSTEAD"] = 253970596055,
+ ["PURGATIONISLE"] = 517657956477,
+ ["SOUTHPOINTTOWER"] = 206160758048,
+ ["SOUTHSHORE"] = 216260688107,
+ ["TARRENMILL"] = 534042844,
+ ["WESTERNSTRAND"] = 395355254045,
+ },
+ ["Hinterlands"] = {
+ ["AERIEPEAK"] = 263080588543,
+ ["AGOLWATHA"] = 176486026445,
+ ["HIRIWATHA"] = 328744509665,
+ ["JINTHAALOR"] = 358085850347,
+ ["PLAGUEMISTRAVINE"] = 160153432209,
+ ["QUELDANILLODGE"] = 198890949817,
+ ["SERADANE"] = 20935101715,
+ ["SHADRAALOR"] = 415789933763,
+ ["SHAOLWATHA"] = 257223243032,
+ ["SKULKROCK"] = 249645122720,
+ ["THEALTAROFZUL"] = 392307053768,
+ ["THECREEPINGRUIN"] = 279600867508,
+ ["THEOVERLOOKCLIFFS"] = 326070753450,
+ ["VALORWINDLAKE"] = 324604700842,
+ },
+ ["LochModan"] = {
+ ["GRIZZLEPAWRIDGE"] = 333184342311,
+ ["IRONBANDSEXCAVATIONSITE"] = 345176801625,
+ ["MOGROSHSTRONGHOLD"] = 52108176699,
+ ["NORTHGATEPASS"] = 13016281318,
+ ["SILVERSTREAMMINE"] = 12051560683,
+ ["STONESPLINTERVALLEY"] = 373887890687,
+ ["STONEWROUGHTDAM"] = 12166806818,
+ ["THEFARSTRIDERLODGE"] = 214247447922,
+ ["THELOCH"] = 93785057600,
+ ["THELSAMAR"] = 218197367040,
+ ["VALLEYOFKINGS"] = 397399025859,
+ },
+ ["Redridge"] = {
+ ["ALTHERSMILL"] = 138931353835,
+ ["GALARDELLVALLEY"] = 173558458618,
+ ["LAKEEVERSTILL"] = 257837780503,
+ ["LAKERIDGEHIGHWAY"] = 357752408494,
+ ["LAKESHIRE"] = 211614371156,
+ ["REDRIDGECANYONS"] = 77436540269,
+ ["RENDERSCAMP"] = 290717971,
+ ["RENDERSVALLEY"] = 388128570833,
+ ["STONEWATCH"] = 231379087615,
+ ["STONEWATCHFALLS"] = 344221501760,
+ ["THREECORNERS"] = 304943036781,
+ },
+ ["SearingGorge"] = {
+ ["BLACKCHARCAVE"] = 393070488851,
+ ["DUSTFIREVALLEY"] = 9032807884,
+ ["FIREWATCHRIDGE"] = 32301824405,
+ ["GRIMSILTDIGSITE"] = 322640769329,
+ ["TANNERCAMP"] = 437584632113,
+ ["THECAULDRON"] = 182798587305,
+ ["THESEAOFCINDERS"] = 416871113064,
+ },
+ ["Silverpine"] = {
+ ["AMBERMILL"] = 281838600432,
+ ["BERENSPERIL"] = 446117892336, -- 448265375984
+ ["DEEPELEMMINE"] = 280739621024,
+ ["FENRISISLE"] = 80078920954,
+ ["MALDENSORCHARD"] = 487751936,
+ ["NORTHTIDESHOLLOW"] = 137777774772,
+ ["OLSENSFARTHING"] = 270983685285,
+ ["PYREWOODVILLAGE"] = 479298974860,
+ ["SHADOWFANGKEEP"] = 385855160540,
+ ["THEDEADFIELD"] = 70214915247,
+ ["THEDECREPITFERRY"] = 155098211508,
+ ["THEGREYMANEWALL"] = 480360226002,
+ ["THESEPULCHER"] = 180757889234,
+ ["THESHININGSTRAND"] = 14440165632,
+ ["THESKITTERINGDARK"] = 40028509369,
+ },
+ ["Stranglethorn"] = {
+ ["BALALRUINS"] = 99037036634,
+ ["BALIAMAHRUINS"] = 138901860462,
+ ["BLOODSAILCOMPOUND"] = 305146281125,
+ ["BOOTYBAY"] = 465143201937,
+ ["CRYSTALVEINMINE"] = 296714625144,
+ ["GROMGOLBASECAMP"] = 142006658158,
+ ["JAGUEROISLE"] = 529684095101,
+ ["KALAIRUINS"] = 94802902111,
+ ["KURZENSCOMPOUND"] = 407001243,
+ ["LAKENAZFERITI"] = 63697974400,
+ ["MISTVALEVALLEY"] = 395430720637,
+ ["MIZJAHRUINS"] = 140986398825,
+ ["MOSHOGGOGREMOUND"] = 101384895616,
+ ["NEKMANIWELLSPRING"] = 385694682202,
+ ["NESINGWARYSEXPEDITION"] = 28199467148,
+ ["REBELCAMP"] = 297887914,
+ ["RUINSOFABORAZ"] = 360070610015,
+ ["RUINSOFJUBUWAL"] = 323517266030,
+ ["RUINSOFZULKUNDA"] = 3426889853,
+ ["RUINSOFZULMAMWE"] = 228046533802,
+ ["THEARENA"] = 203183809736,
+ ["THEVILEREEF"] = 96796327102,
+ ["VENTURECOBASECAMP"] = 69125403753,
+ ["WILDSHORE"] = 453359368357,
+ ["ZIATAJAIRUINS"] = 248416171136,
+ ["ZULGURUB"] = 9096622325,
+ ["ZUULDAIARUINS"] = 45260852339,
+ },
+ ["Sunwell"] = {
+ ["SunsReachHarbor"] = 270847607296,
+ ["SunsReachSanctum"] = 4558684672,
+ },
+ ["SwampOfSorrows"] = {
+ ["FALLOWSANCTUARY"] = 516212077,
+ ["ITHARIUSSCAVE"] = 281320609008,
+ ["MISTYREEDSTRAND"] = 782921984,
+ ["MISTYVALLEY"] = 150324167925,
+ ["POOLOFTEARS"] = 234668444972,
+ ["SORROWMURK"] = 129608561879,
+ ["SPLINTERSPEARJUNCTION"] = 253538582803,
+ ["STAGALBOG"] = 406453479769,
+ ["STONARD"] = 254769687912,
+ ["THEHARBORAGE"] = 155872081131,
+ ["THESHIFTINGMIRE"] = 118411734331,
+ },
+ ["Tirisfal"] = {
+ ["AGAMANDMILLS"] = 149601601792,
+ ["BALNIRFARMSTEAD"] = 350700621016,
+ ["BRIGHTWATERLAKE"] = 149862777033, -- 149865922761
+ ["BRILL"] = 321612152960,
+ ["BULWARK"] = 389426656486,
+ ["COLDHEARTHMANOR"] = 351610732694,
+ ["CRUSADEROUTPOST"] = 311039230125,
+ ["DEATHKNELL"] = 352425555189,
+ ["GARRENSHAUNT"] = 156213932206,
+ ["MONASTARY"] = 135000159443,
+ ["NIGHTMAREVALE"] = 375116733683,
+ ["RUINSOFLORDAERON"] = 388106530107,
+ ["SCARLETWATCHPOST"] = 112391871663,
+ ["SOLLIDENFARMSTEAD"] = 268686225664,
+ ["STILLWATERPOND"] = 297840804026,
+ ["VENOMWEBVALE"] = 220911065325,
+ },
+ ["WesternPlaguelands"] = {
+ ["CAERDARROW"] = 443010946218,
+ ["DALSONSTEARS"] = 284941244636,
+ ["DARROWMERELAKE"] = 368822204786,
+ ["FELSTONEFIELD"] = 334248408224,
+ ["GAHRRONSWITHERING"] = 268980925620,
+ ["HEARTHGLEN"] = 17502077268,
+ ["NORTHRIDGELUMBERCAMP"] = 176494399708,
+ ["RUINSOFANDORHOL"] = 381451213085,
+ ["SORROWHILL"] = 496441178412,
+ ["THEBULWARK"] = 314750199009,
+ ["THEWEEPINGCAVE"] = 213194580128,
+ ["THEWRITHINGHAUNT"] = 347291711658,
+ ["THONDRORILRIVER"] = 92960805069,
+ },
+ ["Westfall"] = {
+ ["ALEXSTONFARMSTEAD"] = 279386999089,
+ ["DEMONTSPLACE"] = 402871477448,
+ ["FURLBROWSPUMPKINFARM"] = 12217179346,
+ ["GOLDCOASTQUARRY"] = 109752615137,
+ ["JANGOLODEMINE"] = 31460646103,
+ ["MOONBROOK"] = 355741147356,
+ ["SALDEANSFARM"] = 113224403169,
+ ["SENTINELHILL"] = 259235496131,
+ ["THEDAGGERHILLS"] = 449179729152,
+ ["THEDEADACRE"] = 271132639432,
+ ["THEDUSTPLAINS"] = 405349313824,
+ ["THEJANSENSTEAD"] = 511910053,
+ ["THEMOLSENFARM"] = 159257933025,
+ ["WESTFALLLIGHTHOUSE"] = 501652584728,
+ },
+ ["Wetlands"] = {
+ ["ANGERFANGENCAMPMENT"] = 234439763169,
+ ["BLACKCHANNELMARSH"] = 263147666672,
+ ["BLUEGILLMARSH"] = 152564857057,
+ ["DIREFORGEHILL"] = 124012194048,
+ ["DUNMODR"] = 22969241805,
+ ["GRIMBATOL"] = 247601668446,
+ ["IRONBEARDSTOMB"] = 123846452424,
+ ["MENETHILHARBOR"] = 337168695471,
+ ["MOSSHIDEFEN"] = 284020692173,
+ ["RAPTORRIDGE"] = 189637230782,
+ ["SALTSPRAYGLEN"] = 44272173256,
+ ["SUNDOWNMARSH"] = 88143544620,
+ ["THEGREENBELT"] = 134696124601,
+ ["THELGANROCK"] = 398851242214,
+ ["WHELGARSEXCAVATIONSITE"] = 220376261827,
+ },
+
+ -- Kalimdor
+ ["Ashenvale"] = {
+ ["ASTRANAAR"] = 269794600141,
+ ["BOUGHSHADOW"] = 163032801426,
+ ["FALLENSKYLAKE"] = 457987798251,
+ ["FELFIREHILL"] = 370115083509,
+ ["FIRESCARSHRINE"] = 348090711205,
+ ["IRISLAKE"] = 234486969544,
+ ["LAKEFALATHIM"] = 147240193152,
+ ["MAESTRASPOST"] = 41017459927,
+ ["MYSTRALLAKE"] = 372961952019,
+ ["NIGHTRUN"] = 277651651809,
+ ["RAYNEWOODRETREAT"] = 256096064692,
+ ["SATYRNAAR"] = 242319811869,
+ ["THEHOWLINGVALE"] = 151883277522,
+ ["THERUINSOFSTARDUST"] = 400778483867,
+ ["THESHRINEOFAESSINA"] = 278208384220,
+ ["THEZORAMSTRAND"] = 30084945141,
+ ["THISTLEFURVILLAGE"] = 169864269055,
+ ["WARSONGLUMBERCAMP"] = 334768537800,
+ },
+ ["Aszhara"] = {
+ ["BAYOFSTORMS"] = 216324681998,
+ ["BITTERREACHES"] = 43625145589,
+ ["FORLORNRIDGE"] = 396411272412,
+ ["HALDARRENCAMPMENT"] = 355489437896,
+ ["JAGGEDREEF"] = 383953466,
+ ["LAKEMENNAR"] = 460945826107,
+ ["LEGASHENCAMPMENT"] = 47746003179,
+ ["RAVENCRESTMONUMENT"] = 536376112368,
+ ["RUINSOFELDARATH"] = 237546791177,
+ ["SHADOWSONGSHRINE"] = 453155934433,
+ ["SOUTHRIDGEBEACH"] = 379438985586,
+ ["TEMPLEOFARKKORAN"] = 164996784318,
+ ["THALASSIANBASECAMP"] = 128298675440,
+ ["THERUINEDREACHES"] = 580235952523,
+ ["THESHATTEREDSTRAND"] = 208729753760,
+ ["TIMBERMAWHOLD"] = 114079054059,
+ ["TOWEROFELDARA"] = 115748269176,
+ ["URSOLAN"] = 102448192657,
+ ["VALORMOK"] = 245975137495,
+ },
+ ["AzuremystIsle"] = {
+ ["AmmenFord"] = 300114247936,
+ ["AmmenVale"] = 112222274011,
+ ["AzureWatch"] = 267763581184,
+ ["BristlelimbVillage"] = 389950996736,
+ ["Emberglade"] = 26281771264,
+ ["FairbridgeStrand"] = 373424384,
+ ["GreezlesCamp"] = 376341528832,
+ ["MoongrazeWoods"] = 196965826816,
+ ["OdesyusLanding"] = 406243770624,
+ ["PodCluster"] = 327786168576,
+ ["PodWreckage"] = 375220600960,
+ ["SiltingShore"] = 3526623488,
+ ["SilvermystIsle"] = 478913198336,
+ ["StillpineHold"] = 52996342016,
+ ["TheExodar"] = 91346174464,
+ ["ValaarsBerth"] = 325528584448,
+ ["WrathscalePoint"] = 452276247808,
+ },
+ ["Barrens"] = {
+ ["AGAMAGOR"] = 251612292296,
+ ["BAELMODAN"] = 514774401152,
+ ["BLACKTHORNRIDGE"] = 496420126875,
+ ["BOULDERLODEMINE"] = 582072440,
+ ["BRAMBLESCAR"] = 320438703229,
+ ["CAMPTAURAJO"] = 376192496785,
+ ["DREADMISTPEAK"] = 68085195904,
+ ["FARWATCHPOST"] = 56426140772,
+ ["FIELDOFGIANTS"] = 432016611538,
+ ["GROLDOMFARM"] = 68161752189,
+ ["HONORSSTAND"] = 139907432576,
+ ["LUSHWATEROASIS"] = 190435222703,
+ ["NORTHWATCHFOLD"] = 330191462550,
+ ["RAPTORGROUNDS"] = 316211837043,
+ ["RATCHET"] = 203520341117,
+ ["RAZORFENDOWNS"] = 594206117019,
+ ["RAZORFENKRAUL"] = 576957055104,
+ ["THECROSSROADS"] = 127153630363,
+ ["THEDRYHILLS"] = 31471060168,
+ ["THEFORGOTTENPOOLS"] = 123883091064,
+ ["THEMERCHANTCOAST"] = 265823555679,
+ ["THEMORSHANRAMPART"] = 432115840,
+ ["THESLUDGEFEN"] = 478273706,
+ ["THESTAGNANTOASIS"] = 227064021147,
+ ["THORNHILL"] = 128297599116,
+ },
+ ["BloodmystIsle"] = {
+ ["AmberwebPass"] = 66618654976,
+ ["Axxarien"] = 146340577536,
+ ["BlacksiltShore"] = 457599863296,
+ ["Bladewood"] = 224797131008,
+ ["BloodWatch"] = 277483880704,
+ ["BloodscaleIsle"] = 275678232815,
+ ["BristlelimbEnclave"] = 440806932736,
+ ["KesselsCrossing"] = 566404199909,
+ ["Middenvale"] = 436373553408,
+ ["Mystwood"] = 518941500672,
+ ["Nazzivian"] = 434054103296,
+ ["RagefeatherRidge"] = 126132420864,
+ ["RuinsofLorethAran"] = 232511504640,
+ ["TalonStand"] = 84441039104,
+ ["TelathionsCamp"] = 232117108864,
+ ["TheBloodcursedReef"] = 58746732800,
+ ["TheBloodwash"] = 29307961600,
+ ["TheCrimsonReach"] = 93997760768,
+ ["TheCryoCore"] = 306323915008,
+ ["TheFoulPool"] = 146260885760,
+ ["TheHiddenReef"] = 42091151616,
+ ["TheLostFold"] = 505186294016,
+ ["TheVectorCoil"] = 255596083712,
+ ["TheWarpPiston"] = 31611683072,
+ ["VeridianPoint"] = 668205312,
+ ["VindicatorsRest"] = 260089053440,
+ ["WrathscaleLair"] = 363552047360,
+ ["WyrmscarIsland"] = 88689869056,
+ },
+ ["Darkshore"] = {
+ ["AMETHARAN"] = 328904946878,
+ ["AUBERDINE"] = 174279842966,
+ ["BASHALARAN"] = 194730200244,
+ ["CLIFFSPRINGRIVER"] = 101325142246,
+ ["GROVEOFTHEANCIENTS"] = 442701621448,
+ ["REMTRAVELSEXCAVATION"] = 521005096111,
+ ["RUINSOFMATHYSTRA"] = 534994115,
+ ["THEMASTERSGLAIVE"] = 547953473711,
+ ["TOWEROFALTHALAXX"] = 91758988458,
+ },
+ ["Desolace"] = {
+ ["ETHELRETHOR"] = 65824614605,
+ ["GELKISVILLAGE"] = 457721497795,
+ ["KODOGRAVEYARD"] = 262399060243,
+ ["KOLKARVILLAGE"] = 231491203292,
+ ["KORMEKSHUT"] = 194929393834,
+ ["MAGRAMVILLAGE"] = 392534717645,
+ ["MANNOROCCOVEN"] = 408440561949,
+ ["NIJELSPOINT"] = 581167304,
+ ["RANAZJARISLE"] = 6695260260,
+ ["SARGERON"] = 36089091357,
+ ["SHADOWBREAKRAVINE"] = 477465087181,
+ ["SHADOWPREYVILLAGE"] = 417860917478,
+ ["TETHRISARAN"] = 452084941,
+ ["THUNDERAXEFORTRESS"] = 109990604990,
+ ["VALLEYOFSPEARS"] = 231077082357,
+ },
+ ["Durotar"] = {
+ ["DRYGULCHRAVINE"] = 84199768274,
+ ["ECHOISLES"] = 459063673032,
+ ["KOLKARCRAG"] = 511534293152,
+ ["ORGRIMMAR"] = 256016829,
+ ["RAZORHILL"] = 182989330652,
+ ["RAZORMANEGROUNDS"] = 203253061862,
+ ["SENJINVILLAGE"] = 412814080160,
+ ["SKULLROCK"] = 35920132224,
+ ["THUNDERRIDGE"] = 64767598782,
+ ["TIRAGARDEKEEP"] = 307574788286,
+ ["VALLEYOFTRIALS"] = 343969848535,
+ },
+ ["Dustwallow"] = {
+ ["ALCAZISLAND"] = 23240838344,
+ ["BACKBAYWETLANDS"] = 203188075920,
+ ["BRACKENWALLVILLAGE"] = 241449240,
+ ["THEDENOFFLAME"] = 336350931199,
+ ["THERAMOREISLE"] = 241078318310,
+ ["THEWYRMBOG"] = 409480708381,
+ ["WITCHHILL"] = 442821882,
+ },
+ ["Felwood"] = {
+ ["BLOODVENOMFALLS"] = 282700432619,
+ ["DEADWOODVILLAGE"] = 572732349615,
+ ["EMERALDSANCTUARY"] = 461060079801,
+ ["FELPAWVILLAGE"] = 506610928,
+ ["IRONTREEWOODS"] = 58422680791,
+ ["JADEFIREGLEN"] = 499638234277,
+ ["JADEFIRERUN"] = 31484717251,
+ ["JAEDENAR"] = 355692839157,
+ ["MORLOSARAN"] = 547054845073,
+ ["RUINSOFCONSTELLAS"] = 409407220971,
+ ["SHATTERSCARVALE"] = 132392362219,
+ ["TALONBRANCHGLADE"] = 97211532448,
+ },
+ ["Feralas"] = {
+ ["CAMPMOJACHE"] = 250904477851,
+ ["DIREMAUL"] = 216298360038,
+ ["DREAMBOUGH"] = 476181654,
+ ["FERALSCARVALE"] = 353770785907,
+ ["FRAYFEATHERHIGHLANDS"] = 414965737582,
+ ["GORDUNNIOUTPOST"] = 152121283724,
+ ["GRIMTOTEMCOMPOUND"] = 179968347256,
+ ["ISLEOFDREAD"] = 402854810839,
+ ["LOWERWILDS"] = 213388546273,
+ ["ONEIROS"] = 75678988398,
+ ["RUINSOFISILDIEN"] = 344163870910,
+ ["RUINSOFRAVENWIND"] = 319974590,
+ ["SARDORISLE"] = 251473875124,
+ ["THEFORGOTTENCOAST"] = 275301859473,
+ ["THETWINCOLOSSALS"] = 80865383709,
+ ["THEWRITHINGDEEP"] = 320623309040,
+ },
+ ["Moonglade"] = {
+ ["LAKEELUNEARA"] = 95819397675,
+ },
+ ["Mulgore"] = {
+ ["BAELDUNDIGSITE"] = 230048321746,
+ ["BLOODHOOFVILLAGE"] = 325728805120,
+ ["PALEMANEROCK"] = 329956668544,
+ ["RAVAGEDCARAVAN"] = 279668973696,
+ ["REDCLOUDMESA"] = 456623640022,
+ ["REDROCKS"] = 17706490061,
+ ["THEGOLDENPLAINS"] = 86348382423,
+ ["THEROLLINGPLAINS"] = 382800689408,
+ ["THEVENTURECOMINE"] = 256108637409,
+ ["THUNDERBLUFF"] = 63612109080,
+ ["THUNDERHORNWATERWELL"] = 260243090560,
+ ["WILDMANEWATERWELL"] = 305266873,
+ ["WINDFURYRIDGE"] = 414318797,
+ ["WINTERHOOFWATERWELL"] = 396691112106,
+ },
+ ["Silithus"] = {
+ ["HIVEASHI"] = 13163102720,
+ ["HIVEREGAL"] = 306273714688,
+ ["HIVEZORA"] = 154721059200,
+ ["SOUTHWINDVILLAGE"] = 70317900160,
+ ["THECRYSTALVALE"] = 25879151936,
+ ["THESCARABWALL"] = 443577270560,
+ ["TWILIGHTBASECAMP"] = 211888111936,
+ },
+ ["StonetalonMountains"] = {
+ ["BOULDERSLIDERAVINE"] = 602969058449,
+ ["CAMPAPARAJE"] = 613859558590,
+ ["GRIMTOTEMPOST"] = 553677611233,
+ ["MALAKAJIN"] = 625613035645,
+ ["MIRKFALLONLAKE"] = 156101729480,
+ ["SISHIRCANYON"] = 465428411517,
+ ["STONETALONPEAK"] = 259208462,
+ ["SUNROCKRETREAT"] = 344005433494,
+ ["THECHARREDVALE"] = 251476151526,
+ ["WEBWINDERPATH"] = 303274757408,
+ ["WINDSHEARCRAG"] = 212107283776,
+ },
+ ["Tanaris"] = {
+ ["ABYSSALSANDS"] = 208686731479,
+ ["BROKENPILLAR"] = 251751747694,
+ ["CAVERNSOFTIME"] = 275466311835,
+ ["DUNEMAULCOMPOUND"] = 310652323021,
+ ["EASTMOONRUINS"] = 371929012384,
+ ["GADGETZAN"] = 98152125615,
+ ["LANDSENDBEACH"] = 549148849357,
+ ["LOSTRIGGERCOVE"] = 236882950304,
+ ["NOONSHADERUINS"] = 112228179064,
+ ["SANDSORROWWATCH"] = 107687886019,
+ ["SOUTHBREAKSHORE"] = 315129773271,
+ ["SOUTHMOONRUINS"] = 385812220099,
+ ["STEAMWHEEDLEPORT"] = 81151547547,
+ ["THEGAPINGCHASM"] = 399902984412,
+ ["THENOXIOUSLAIR"] = 213939069108,
+ ["THISTLESHRUBVALLEY"] = 307303278777,
+ ["VALLEYOFTHEWATCHERS"] = 466309251222,
+ ["WATERSPRINGFIELD"] = 180922536101,
+ ["ZALASHJISDEN"] = 158480871534,
+ ["ZULFARRAK"] = 266517714,
+ },
+ ["Teldrassil"] = {
+ ["BANETHILHOLLOW"] = 302122223776,
+ ["DARNASSUS"] = 265320399163,
+ ["DOLANAAR"] = 347303182526,
+ ["GNARLPINEHOLD"] = 476053635257,
+ ["LAKEALAMETH"] = 408479261952,
+ ["POOLSOFARLITHRIEN"] = 336432658560,
+ ["RUTTHERANVILLAGE"] = 588928618624,
+ ["SHADOWGLEN"] = 164797580513,
+ ["STARBREEZEVILLAGE"] = 314121068744,
+ ["THEORACLEGLADE"] = 136650670250,
+ ["WELLSPRINGLAKE"] = 100253565108,
+ },
+ ["ThousandNeedles"] = {
+ ["CAMPETHOK"] = 317745,
+ ["DARKCLOUDPINNACLE"] = 140931960013,
+ ["FREEWINDPOST"] = 283842377938,
+ ["HIGHPERCH"] = 166462683326,
+ ["SPLITHOOFCRAG"] = 206568623314,
+ ["THEGREATLIFT"] = 75377070290,
+ ["THESCREECHINGCANYON"] = 214936305914,
+ ["THESHIMMERINGFLATS"] = 322762552640,
+ ["WINDBREAKCANYON"] = 268951580912,
+ },
+ ["UngoroCrater"] = {
+ ["FIREPLUMERIDGE"] = 191511148839,
+ ["GOLAKKAHOTSPRINGS"] = 162262246715,
+ ["IRONSTONEPLATEAU"] = 72551265565,
+ ["LAKKARITARPITS"] = 6610495034,
+ ["TERRORRUN"] = 395302958425,
+ ["THEMARSHLANDS"] = 258285604150,
+ ["THESLITHERINGSCAR"] = 408407012697,
+ },
+ ["Winterspring"] = {
+ ["DARKWHISPERGORGE"] = 473989068031,
+ ["EVERLOOK"] = 115424305317,
+ ["FROSTFIREHOTSPRINGS"] = 184916521200,
+ ["FROSTSABERROCK"] = 7902253306,
+ ["FROSTWHISPERGORGE"] = 404275495112,
+ ["ICETHISTLEHILLS"] = 260486370429,
+ ["LAKEKELTHERIL"] = 213021549783,
+ ["MAZTHORIL"] = 277542523065,
+ ["OWLWINGTHICKET"] = 365694169253,
+ ["STARFALLVILLAGE"] = 147513835705,
+ ["THEHIDDENGROVE"] = 29573178543,
+ ["TIMBERMAWPOST"] = 261159510246,
+ ["WINTERFALLVILLAGE"] = 170298307729,
+ },
+
+ -- Outland
+ ["BladesEdgeMountains"] = {
+ ["BashirLanding"] = 442761472,
+ ["BladedGulch"] = 158493573376,
+ ["BladesipreHold"] = 173202205952,
+ ["BloodmaulCamp"] = 102437748992,
+ ["BloodmaulOutpost"] = 398717134080,
+ ["BrokenWilds"] = 117806727424,
+ ["CircleofWrath"] = 225946370304,
+ ["DeathsDoor"] = 267899014400,
+ ["ForgeCampAnger"] = 158454776224,
+ ["ForgeCampTerror"] = 446827852288,
+ ["ForgeCampWrath"] = 189245161728,
+ ["Grishnath"] = 30364926208,
+ ["GruulsLayer"] = 87525949696,
+ ["JaggedRidge"] = 444997040384,
+ ["MokNathalVillage"] = 319591547136,
+ ["RavensWood"] = 59280458240,
+ ["RazorRidge"] = 357041520896,
+ ["RidgeofMadness"] = 277606721792,
+ ["RuuanWeald"] = 105729491200,
+ ["Skald"] = 76941623552,
+ ["Sylvanaar"] = 376113002752,
+ ["TheCrystalpine"] = 613679360,
+ ["ThunderlordStronghold"] = 292482855168,
+ ["VeilLashh"] = 459845910784,
+ ["VeilRuuan"] = 162725495040,
+ ["VekhaarStand"] = 436598997248,
+ ["VortexPinnacle"] = 221365352704,
+ },
+ ["Hellfire"] = {
+ ["DenofHaalesh"] = 442572734720,
+ ["ExpeditionArmory"] = 443729313280,
+ ["FalconWatch"] = 350232074752,
+ ["FallenSkyRidge"] = 152507252992,
+ ["ForgeCampRage"] = 27345289728,
+ ["HellfireCitadel"] = 225840670976,
+ ["HonorHold"] = 320467108096,
+ ["MagharPost"] = 118327869696,
+ ["PoolsofAggonar"] = 48660742400,
+ ["RuinsofShanaar"] = 311411730688,
+ ["TempleofTelhamat"] = 163249127936,
+ ["TheLegionFront"] = 138046603520,
+ ["TheStairofDestiny"] = 168277049600,
+ ["Thrallmar"] = 165846188288,
+ ["ThroneofKiljaeden"] = 6942884352,
+ ["VoidRidge"] = 395876499712,
+ ["WarpFields"] = 438409892096,
+ ["ZethGor"] = 462317402534,
+ },
+ ["Nagrand"] = {
+ ["BurningBladeRUins"] = 359322171648,
+ ["ClanWatch"] = 390326386944,
+ ["ForgeCampFear"] = 266326151680,
+ ["ForgeCampHate"] = 165526372608,
+ ["Garadar"] = 153997279488,
+ ["Halaa"] = 207583707392,
+ ["KilsorrowFortress"] = 459073111296,
+ ["LaughingSkullRuins"] = 56202887424,
+ ["OshuGun"] = 358806272512,
+ ["RingofTrials"] = 287248220416,
+ ["SouthwindCleft"] = 277435646208,
+ ["SunspringPost"] = 213904523520,
+ ["Telaar"] = 419165372672,
+ ["ThroneoftheElements"] = 57437061376,
+ ["TwilightRidge"] = 114901385472,
+ ["WarmaulHill"] = 34524627200,
+ ["WindyreedPass"] = 85452914944,
+ ["WindyreedVillage"] = 250880459008,
+ ["ZangarRidge"] = 58272776448,
+ },
+ ["Netherstorm"] = {
+ ["Area52"] = 416864665856,
+ ["ArklonRuins"] = 426619699456,
+ ["CelestialRidge"] = 186432880896,
+ ["EcoDomeFarfield"] = 11152916736,
+ ["EtheriumStagingGrounds"] = 223842926848,
+ ["ForgeBaseOG"] = 23871095040,
+ ["KirinVarVillage"] = 562080924928,
+ ["ManaforgeBanar"] = 301875989760,
+ ["ManaforgeCoruu"] = 525434277120,
+ ["ManaforgeDuro"] = 361265103104,
+ ["ManafrogeAra"] = 166609551616,
+ ["Netherstone"] = 21906063616,
+ ["NetherstormBridge"] = 315818770688,
+ ["RuinedManaforge"] = 148714553600,
+ ["RuinsofEnkaat"] = 323461841152,
+ ["RuinsofFarahlon"] = 52984807936,
+ ["SocretharsSeat"] = 41042575616,
+ ["SunfuryHold"] = 484733838592,
+ ["TempestKeep"] = 305564877209,
+ ["TheHeap"] = 488803357952,
+ ["TheScrapField"] = 280620171520,
+ ["TheStormspire"] = 144194142464,
+ },
+ ["ShadowmoonValley"] = {
+ ["AltarofShatar"] = 100403511552,
+ ["CoilskarPoint"] = 8955363840,
+ ["EclipsePoint"] = 333219994112,
+ ["IlladarPoint"] = 275028115712,
+ ["LegionHold"] = 166539559424,
+ ["NetherwingCliffs"] = 331293655296,
+ ["NetherwingLedge"] = 478350114284,
+ ["ShadowmoonVilliage"] = 37703123456,
+ ["TheBlackTemple"] = 135927431564,
+ ["TheDeathForge"] = 138817306880,
+ ["TheHandofGuldan"] = 97050427904,
+ ["TheWardensCage"] = 277517593088,
+ ["WildhammerStronghold"] = 246063488512,
+ },
+ ["TerokkarForest"] = {
+ ["AllerianStronghold"] = 297930064128,
+ ["AuchenaiGrounds"] = 466263189760,
+ ["BleedingHollowClanRuins"] = 323304668416,
+ ["BonechewerRuins"] = 295825572096,
+ ["CarrionHill"] = 292453351680,
+ ["CenarionThicket"] = 329515264,
+ ["FirewingPoint"] = 160635027841,
+ ["GrangolvarVilliage"] = 183760060928,
+ ["RaastokGlade"] = 165886034176,
+ ["RazorthornShelf"] = 20902576384,
+ ["RefugeCaravan"] = 288094421120,
+ ["RingofObservance"] = 370766250240,
+ ["SethekkTomb"] = 310568550656,
+ ["ShattrathCity"] = 4404544000,
+ ["SkethylMountains"] = 374133293568,
+ ["SmolderingCaravan"] = 494258045184,
+ ["StonebreakerHold"] = 177583948032,
+ ["TheBarrierHills"] = 4416864512,
+ ["Tuurem"] = 36984848640,
+ ["VeilRhaze"] = 388927586560,
+ ["WrithingMound"] = 351551095040,
+ },
+ ["Zangarmarsh"] = {
+ ["AngoroshGrounds"] = 53779628288,
+ ["AngoroshStronghold"] = 130154752,
+ ["BloodscaleEnclave"] = 443006845184,
+ ["CenarionRefuge"] = 345399099700,
+ ["CoilfangReservoir"] = 97121730816,
+ ["FeralfenVillage"] = 356811883008,
+ ["MarshlightLake"] = 163293954304,
+ ["OreborHarborage"] = 27189051648,
+ ["QuaggRidge"] = 349114293504,
+ ["Sporeggar"] = 216917082624,
+ ["Telredor"] = 120856248576,
+ ["TheDeadMire"] = 138190258462,
+ ["TheHewnBog"] = 54990995712,
+ ["TheLagoon"] = 325880905984,
+ ["TheSpawningGlen"] = 364031246592,
+ ["TwinspireRuins"] = 267720589568,
+ ["UmbrafenVillage"] = 495750167808,
+ ["ZabraJin"] = 249291866368,
+ },
+
+ -- Northrend
+ ["BoreanTundra"] = {
+ ["AmberLedge"] = 150664861940,
+ ["BorGorokOutpost"] = 329461132,
+ ["Coldarra"] = 52819404,
+ ["DeathsStand"] = 195088899361,
+ ["GarroshsLanding"] = 255711373579,
+ ["Kaskala"] = 230314799489,
+ ["RiplashStrand"] = 411550615934,
+ ["SteeljawsCaravan"] = 71283571956,
+ ["TempleCityOfEnKilah"] = 16853012770,
+ ["TheDensOfDying"] = 12505531595,
+ ["TheGeyserFields"] = 503667063,
+ ["TorpsFarm"] = 254762307770,
+ ["ValianceKeep"] = 283947350275,
+ ["WarsongStronghold"] = 254822078724,
+ },
+ ["CrystalsongForest"] = {
+ ["ForlornWoods"] = 135950880,
+ ["SunreaversCommand"] = 43512087998,
+ ["TheAzureFront"] = 261993439648,
+ ["TheDecrepitFlow"] = 227616,
+ ["TheGreatTree"] = 97710772476,
+ ["TheUnboundThicket"] = 113267668470,
+ ["VioletStand"] = 188978871560,
+ ["WindrunnersOverlook"] = 411708978734,
+ },
+ ["Dragonblight"] = {
+ ["AgmarsHammer"] = 218240346348,
+ ["Angrathar"] = 220449074,
+ ["ColdwindHeights"] = 422800597,
+ ["EmeraldDragonshrine"] = 389264140484,
+ ["GalakrondsRest"] = 127155799298,
+ ["IcemistVillage"] = 177308255467,
+ ["LakeIndule"] = 336309039460,
+ ["LightsRest"] = 8253626667,
+ ["Naxxramas"] = 172523536695,
+ ["NewHearthglen"] = 385043666134,
+ ["ObsidianDragonshrine"] = 111937793328,
+ ["RubyDragonshrine"] = 223730683068,
+ ["ScarletPoint"] = 8113195243,
+ ["TheCrystalVice"] = 510921957,
+ ["TheForgottenShore"] = 357214484781,
+ ["VenomSpite"] = 284161167586,
+ ["WestwindRefugeeCamp"] = 200834067685,
+ ["WyrmrestTemple"] = 235624826173,
+ },
+ ["GrizzlyHills"] = {
+ ["AmberpineLodge"] = 262220843286,
+ ["BlueSkyLoggingGrounds"] = 138756205817,
+ ["CampOneqwah"] = 147677521220,
+ ["ConquestHold"] = 329656867148,
+ ["DrakTheronKeep"] = 49392416126,
+ ["DrakilJinRuins"] = 44660191583,
+ ["DunArgol"] = 276525629895,
+ ["GraniteSprings"] = 222272127332,
+ ["GrizzleMaw"] = 201165344038,
+ ["RageFangShrine"] = 316007623131,
+ ["ThorModan"] = 533977417,
+ ["UrsocsDen"] = 34707083592,
+ ["VentureBay"] = 495014067474,
+ ["Voldrune"] = 452230110491,
+ },
+ ["HowlingFjord"] = {
+ ["AncientLift"] = 377242188977,
+ ["ApothecaryCamp"] = 39832528135,
+ ["BaelgunsExcavationSite"] = 351765054708,
+ ["Baleheim"] = 183140267182,
+ ["CampWinterHoof"] = 371410143,
+ ["CauldrosIsle"] = 173386418357,
+ ["EmberClutch"] = 218266599637,
+ ["ExplorersLeagueOutpost"] = 361390891240,
+ ["FortWildervar"] = 513999099,
+ ["GiantsRun"] = 600099114,
+ ["Gjalerbron"] = 236123378,
+ ["Halgrind"] = 223754853563,
+ ["IvaldsRuin"] = 240145081537,
+ ["Kamagua"] = 298604307789,
+ ["NewAgamand"] = 386982531356,
+ ["Nifflevar"] = 258322153650,
+ ["ScalawagPoint"] = 440410573150,
+ ["Skorn"] = 116324016366,
+ ["SteelGate"] = 107607138526,
+ ["TheTwistedGlade"] = 61643901194,
+ ["UtgardeKeep"] = 232428796152,
+ ["VengeanceLanding"] = 27540146399,
+ ["WestguardKeep"] = 193368125787,
+ },
+ ["IcecrownGlacier"] = {
+ ["Aldurthar"] = 40101076341,
+ ["ArgentTournamentGround"] = 32858407226,
+ ["Corprethar"] = 421265625396,
+ ["IcecrownCitadel"] = 500774938932,
+ ["Jotunheim"] = 131020056969,
+ ["OnslaughtHarbor"] = 179315159244,
+ ["Scourgeholme"] = 287412829429,
+ ["SindragosasFall"] = 33942756652,
+ ["TheBombardment"] = 194911653112,
+ ["TheBrokenFront"] = 353846402331,
+ ["TheConflagration"] = 327834355939,
+ ["TheFleshwerks"] = 312687750363,
+ ["TheShadowVault"] = 16443129055,
+ ["Valhalas"] = 53914878190,
+ ["ValleyofEchoes"] = 419509265677,
+ ["Ymirheim"] = 296818523359,
+ },
+ ["SholazarBasin"] = {
+ ["KartaksHold"] = 402733176137,
+ ["RainspeakerCanopy"] = 262440987855,
+ ["RiversHeart"] = 364375254484,
+ ["TheAvalanche"] = 99409470786,
+ ["TheGlimmeringPillar"] = 36830518566,
+ ["TheLifebloodPillar"] = 144407119160,
+ ["TheMakersOverlook"] = 254142609641,
+ ["TheMakersPerch"] = 145135755513,
+ ["TheMosslightPillar"] = 381456540911,
+ ["TheSavageThicket"] = 55176303909,
+ ["TheStormwrightsShelf"] = 62422024460,
+ ["TheSuntouchedPillar"] = 199802286535,
+ },
+ ["TheStormPeaks"] = {
+ ["BorsBreath"] = 402767678786,
+ ["BrunnhildarVillage"] = 397640247601,
+ ["DunNiffelem"] = 306521177397,
+ ["EngineoftheMakers"] = 318159113426,
+ ["Frosthold"] = 460775977204,
+ ["GarmsBane"] = 505073040568,
+ ["NarvirsCradle"] = 154843462836,
+ ["Nidavelir"] = 221304266973,
+ ["SnowdriftPlains"] = 153715187917,
+ ["SparksocketMinefield"] = 502765134075,
+ ["TempleofLife"] = 121930791094,
+ ["TempleofStorms"] = 323447066793,
+ ["TerraceoftheMakers"] = 131303036267,
+ ["Thunderfall"] = 192857739570,
+ ["Ulduar"] = 228861297,
+ ["Valkyrion"] = 341552822500,
+ },
+ ["ZulDrak"] = {
+ ["AltarOfHarKoa"] = 371000083721,
+ ["AltarOfMamToth"] = 95092536631,
+ ["AltarOfQuetzLun"] = 270145978629,
+ ["AltarOfRhunok"] = 136817459447,
+ ["AltarOfSseratus"] = 180690870509,
+ ["AmphitheaterOfAnguish"] = 308467202314,
+ ["DrakSotraFields"] = 384741680414,
+ ["GunDrak"] = 659858768,
+ ["Kolramas"] = 469623872814,
+ ["LightsBreach"] = 389958387009,
+ ["ThrymsEnd"] = 265214505232,
+ ["Voltarus"] = 205267438810,
+ ["Zeramas"] = 442389233971,
+ ["ZimTorga"] = 259274311929,
+ },
+
+ ["*"] = {},
+}
+
+local function UpdateOverlayTextures(frame, frameName, textureCache, scale, r, g, b, alpha)
+ local mapFileName = GetMapInfo()
+
+ if not mapFileName then
+ for i = 1, #textureCache do
+ textureCache[i]:Hide()
+ end
+
+ return
+ end
+
+ local pathPrefix = "Interface\\WorldMap\\"..mapFileName.."\\"
+ local overlayMap = errata[mapFileName]
+ local numOverlays = GetNumMapOverlays()
+ local pathLen = len(pathPrefix) + 1
+
+ if not overlayMap then
+ overlayMap = {}
+ end
+
+ for i = 1, numOverlays do
+ local texName, texWidth, texHeight, offsetX, offsetY = GetMapOverlayInfo(i)
+
+ if texName then
+ texName = sub(texName, pathLen)
+
+ if lower(texName) ~= "pixelfix" then
+ discoveredOverlays[texName] = true
+
+ if not overlayMap[texName] then
+ local texID = texWidth + texHeight * 2^10 + offsetX * 2^20 + offsetY * 2^30
+
+ if texID ~= 0 and texID ~= 131200 then
+ overlayMap[texName] = texID
+ end
+ end
+ end
+ end
+ end
+
+ local textureCount = 0
+ local numTextures = #textureCache
+
+ for texName, texID in pairs(overlayMap) do
+ local textureName = pathPrefix .. texName
+ local textureWidth, textureHeight, offsetX, offsetY = fmod(texID, 2^10), fmod(floor(texID / 2^10), 2^10), fmod(floor(texID / 2^20), 2^10), floor(texID / 2^30)
+
+ local numTexturesWide = ceil(textureWidth / 256)
+ local numTexturesTall = ceil(textureHeight / 256)
+
+ local neededTextures = textureCount + (numTexturesWide * numTexturesTall)
+
+ if neededTextures > numTextures then
+ for j = numTextures + 1, neededTextures do
+ tinsert(textureCache, (frame:CreateTexture(format(frameName, j), "ARTWORK")))
+ end
+
+ numTextures = neededTextures
+ FC.NUM_WORLDMAP_OVERLAYS = numTextures
+ NUM_WORLDMAP_OVERLAYS = numTextures
+ end
+
+ local texture, texturePixelWidth, textureFileWidth, texturePixelHeight, textureFileHeight
+
+ for j = 1, numTexturesTall do
+ if j < numTexturesTall then
+ texturePixelHeight = 256
+ textureFileHeight = 256
+ else
+ texturePixelHeight = fmod(textureHeight, 256)
+ textureFileHeight = 16
+
+ if texturePixelHeight == 0 then
+ texturePixelHeight = 256
+ end
+
+ while textureFileHeight < texturePixelHeight do
+ textureFileHeight = textureFileHeight * 2
+ end
+ end
+
+ for k = 1, numTexturesWide do
+ textureCount = textureCount + 1
+ texture = textureCache[textureCount]
+
+ if k < numTexturesWide then
+ texturePixelWidth = 256
+ textureFileWidth = 256
+ else
+ texturePixelWidth = fmod(textureWidth, 256)
+ textureFileWidth = 16
+
+ if texturePixelWidth == 0 then
+ texturePixelWidth = 256
+ end
+
+ while textureFileWidth < texturePixelWidth do
+ textureFileWidth = textureFileWidth * 2
+ end
+ end
+
+ texture:Size(texturePixelWidth * scale, texturePixelHeight * scale)
+ texture:Point("TOPLEFT", (offsetX + (256 * (k - 1))) * scale, -(offsetY + (256 * (j - 1))) * scale)
+ texture:SetTexCoord(0, texturePixelWidth / textureFileWidth, 0, texturePixelHeight / textureFileHeight)
+ texture:SetTexture(format("%s%d", textureName, ((j - 1) * numTexturesWide) + k))
+
+ if discoveredOverlays[texName] then
+ texture:SetDrawLayer("ARTWORK")
+ texture:SetVertexColor(1, 1, 1)
+ texture:SetAlpha(1)
+ else
+ texture:SetDrawLayer("BORDER")
+ texture:SetVertexColor(r, g, b)
+ texture:SetAlpha(alpha * 1)
+ end
+
+ texture:Show()
+ end
+ end
+ end
+
+ for i = textureCount + 1, numTextures do
+ textureCache[i]:Hide()
+ end
+
+ twipe(discoveredOverlays)
+end
+
+function FC:UpdateWorldMapOverlays()
+ if not WorldMapFrame:IsShown() then return end
+
+ if NUM_WORLDMAP_OVERLAYS > self.NUM_WORLDMAP_OVERLAYS then
+ for i = self.NUM_WORLDMAP_OVERLAYS + 1, NUM_WORLDMAP_OVERLAYS do
+ tinsert(worldMapCache, i, _G[format("WorldMapOverlay%d", i)])
+ end
+
+ self.NUM_WORLDMAP_OVERLAYS = NUM_WORLDMAP_OVERLAYS
+ end
+
+ local color = E.db.enhanced.map.fogClear.color
+ UpdateOverlayTextures(WorldMapDetailFrame, "WorldMapOverlay%d", worldMapCache, 1, color.r, color.g, color.b, color.a)
+end
+
+function FC:UpdateFog()
+ if E.db.enhanced.map.fogClear.enable then
+ self:SecureHook("WorldMapFrame_Update", "UpdateWorldMapOverlays")
+
+ twipe(worldMapCache)
+ self.NUM_WORLDMAP_OVERLAYS = 0
+
+ if WorldMapFrame:IsShown() then
+ self:UpdateWorldMapOverlays()
+ end
+ else
+ self:UnhookAll()
+
+ for i = 1, NUM_WORLDMAP_OVERLAYS do
+ local tex = _G[format("WorldMapOverlay%d", i)]
+ tex:SetDrawLayer("ARTWORK")
+ tex:SetVertexColor(1, 1, 1)
+ tex:SetAlpha(1)
+ end
+
+ for i = 1, #worldMapCache do
+ worldMapCache[i]:Hide()
+ end
+
+ if WorldMapFrame:IsShown() then
+ WorldMapFrame_Update()
+ end
+ end
+end
+
+function FC:Initialize()
+ local _, _, _, enabled, _, reason = GetAddOnInfo("Mapster")
+ if reason ~= "MISSED" and enabled then return end
+
+ if not E.db.enhanced.map.fogClear.enable then return end
+
+ self:UpdateFog()
+end
+
+local function InitializeCallback()
+ FC:Initialize()
+end
+
+E:RegisterModule(FC:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Maps/Load_Maps.xml b/ElvUI_Enhanced/Modules/Maps/Load_Maps.xml
new file mode 100644
index 0000000..01440b0
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Maps/Load_Maps.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Maps/MinimapButtonGrabber.lua b/ElvUI_Enhanced/Modules/Maps/MinimapButtonGrabber.lua
new file mode 100644
index 0000000..ca02e90
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Maps/MinimapButtonGrabber.lua
@@ -0,0 +1,469 @@
+local E, L, V, P, G = unpack(ElvUI)
+local MBG = E:NewModule("Enhanced_MinimapButtonGrabber", "AceHook-3.0", "AceTimer-3.0")
+
+local pairs, ipairs = pairs, ipairs
+local select = select
+local unpack = unpack
+local ceil = math.ceil
+local find, len, sub = string.find, string.len, string.sub
+local tinsert = table.insert
+
+local UIFrameFadeIn = UIFrameFadeIn
+local UIFrameFadeOut = UIFrameFadeOut
+
+local ignoreButtons = {
+ ["ElvConfigToggle"] = true,
+
+ ["BattlefieldMinimap"] = true,
+ ["ButtonCollectFrame"] = true,
+ ["GameTimeFrame"] = true,
+ ["MiniMapBattlefieldFrame"] = true,
+ ["MiniMapLFGFrame"] = true,
+ ["MiniMapMailFrame"] = true,
+ ["MiniMapPing"] = true,
+ ["MiniMapRecordingButton"] = true,
+ ["MiniMapTracking"] = true,
+ ["MiniMapTrackingButton"] = true,
+ ["MiniMapVoiceChatFrame"] = true,
+ ["MiniMapWorldMapButton"] = true,
+ ["Minimap"] = true,
+ ["MinimapBackdrop"] = true,
+ ["MinimapToggleButton"] = true,
+ ["MinimapZoneTextButton"] = true,
+ ["MinimapZoomIn"] = true,
+ ["MinimapZoomOut"] = true,
+ ["TimeManagerClockButton"] = true,
+}
+
+local genericIgnores = {
+ "GuildInstance",
+
+ -- GatherMate
+ "GatherMatePin",
+ -- Gatherer
+ "GatherNote",
+ -- GuildMap3
+ "GuildMap3Mini",
+ -- HandyNotes
+ "HandyNotesPin",
+ -- LibRockConfig
+ "LibRockConfig-1.0_MinimapButton",
+ -- Nauticus
+ "NauticusMiniIcon",
+ "WestPointer",
+ -- QuestPointer
+ "poiMinimap",
+ -- Spy
+ "Spy_MapNoteList_mini",
+}
+
+local partialIgnores = {
+ "Node",
+ "Note",
+ "Pin",
+}
+
+local whiteList = {
+ "LibDBIcon",
+}
+
+local buttonFunctions = {
+ "SetParent",
+ "SetFrameStrata",
+ "SetFrameLevel",
+ "ClearAllPoints",
+ "SetPoint",
+ "SetScale",
+ "SetSize",
+ "SetWidth",
+ "SetHeight"
+}
+
+local function OnEnter()
+ UIFrameFadeIn(MBG.frame, 0.1, MBG.frame:GetAlpha(), MBG.maxAlpha)
+end
+
+local function OnLeave()
+ UIFrameFadeOut(MBG.frame, 0.1, MBG.frame:GetAlpha(), 0)
+end
+
+function MBG:LockButton(button)
+ for _, func in ipairs(buttonFunctions) do
+ button[func] = E.noop
+ end
+end
+
+function MBG:UnlockButton(button)
+ for _, func in ipairs(buttonFunctions) do
+ button[func] = nil
+ end
+end
+
+function MBG:CheckVisibility()
+ local updateLayout
+
+ for _, button in ipairs(self.skinnedButtons) do
+ if button:IsVisible() and button.__hidden then
+ button.__hidden = false
+ updateLayout = true
+ elseif not button:IsVisible() and not button.__hidden then
+ button.__hidden = true
+ updateLayout = true
+ end
+ end
+
+ return updateLayout
+end
+
+function MBG:GetVisibleList()
+ local t = {}
+
+ for _, button in ipairs(self.skinnedButtons) do
+ if button:IsVisible() then
+ tinsert(t, button)
+ end
+ end
+
+ return t
+end
+
+function MBG:GrabMinimapButtons()
+ for _, frame in ipairs(self.minimapFrames) do
+ for i = 1, frame:GetNumChildren() do
+ local object = select(i, frame:GetChildren())
+
+ if object and object:IsObjectType("Button") then
+ self:SkinMinimapButton(object)
+ end
+ end
+ end
+
+ if AtlasButtonFrame then self:SkinMinimapButton(AtlasButton) end
+ if FishingBuddyMinimapFrame then self:SkinMinimapButton(FishingBuddyMinimapButton) end
+ if HealBot_MMButton then self:SkinMinimapButton(HealBot_MMButton) end
+
+ if self.needUpdate or self:CheckVisibility() then
+ self:UpdateLayout()
+ end
+end
+
+function MBG:SkinMinimapButton(button)
+ if not button or button.isSkinned then return end
+
+ local name = button:GetName()
+ if not name then return end
+
+ if button:IsObjectType("Button") then
+ local validIcon
+
+ for i = 1, #whiteList do
+ if sub(name, 1, len(whiteList[i])) == whiteList[i] then
+ validIcon = true
+ break
+ end
+ end
+
+ if not validIcon then
+ if ignoreButtons[name] then return end
+
+ for i = 1, #genericIgnores do
+ if sub(name, 1, len(genericIgnores[i])) == genericIgnores[i] then return end
+ end
+
+ for i = 1, #partialIgnores do
+ if find(name, partialIgnores[i]) then return end
+ end
+ end
+
+ button:SetPushedTexture(nil)
+ button:SetHighlightTexture(nil)
+ button:SetDisabledTexture(nil)
+ end
+
+ for i = 1, button:GetNumRegions() do
+ local region = select(i, button:GetRegions())
+
+ if region:GetObjectType() == "Texture" then
+ local texture = region:GetTexture()
+
+ if texture and (find(texture, "Border") or find(texture, "Background") or find(texture, "AlphaMask")) then
+ region:SetTexture(nil)
+ else
+ if name == "BagSync_MinimapButton" then
+ region:SetTexture("Interface\\AddOns\\BagSync\\media\\icon")
+ elseif name == "DBMMinimapButton" then
+ region:SetTexture("Interface\\Icons\\INV_Helmet_87")
+ elseif name == "OutfitterMinimapButton" then
+ if region:GetTexture() == "Interface\\Addons\\Outfitter\\Textures\\MinimapButton" then
+ region:SetTexture(nil)
+ end
+ elseif name == "SmartBuff_MiniMapButton" then
+ region:SetTexture("Interface\\Icons\\Spell_Nature_Purge")
+ elseif name == "VendomaticButtonFrame" then
+ region:SetTexture("Interface\\Icons\\INV_Misc_Rabbit_2")
+ end
+
+ region:ClearAllPoints()
+ region:SetInside()
+ region:SetTexCoord(unpack(E.TexCoords))
+ button:HookScript("OnLeave", function() region:SetTexCoord(unpack(E.TexCoords)) end)
+
+ region:SetDrawLayer("ARTWORK")
+ region.SetPoint = E.noop
+ end
+ end
+ end
+
+ button:SetParent(self.frame)
+ button:SetFrameLevel(self.frame:GetFrameLevel() + 5)
+ button:SetTemplate()
+
+ self:LockButton(button)
+
+ button:SetScript("OnDragStart", nil)
+ button:SetScript("OnDragStop", nil)
+
+ if E.db.enhanced.minimap.buttonGrabber.mouseover then
+ button:HookScript("OnEnter", OnEnter)
+ button:HookScript("OnLeave", OnLeave)
+ end
+
+ button.__hidden = button:IsVisible() and true or false
+ button.isSkinned = true
+ tinsert(self.skinnedButtons, button)
+
+ self.needUpdate = true
+end
+
+function MBG:UpdateLayout()
+ if #self.skinnedButtons == 0 then return end
+
+ local db = E.db.enhanced.minimap.buttonGrabber
+ local spacing = (db.backdrop and (E.Border + db.backdropSpacing) or E.Spacing)
+
+ local visibleButtons = self:GetVisibleList()
+
+ if #visibleButtons == 0 then
+ self.frame:Size(db.buttonSize + (spacing * 2))
+ self.frame.backdrop:Hide()
+ return
+ end
+
+ local numButtons = #visibleButtons
+ local buttonsPerRow = db.buttonsPerRow
+ local numColumns = ceil(numButtons / buttonsPerRow)
+
+ if buttonsPerRow > numButtons then
+ buttonsPerRow = numButtons
+ end
+
+ local barWidth = (db.buttonSize * buttonsPerRow) + (db.buttonSpacing * (buttonsPerRow - 1)) + spacing * 2
+ local barHeight = (db.buttonSize * numColumns) + (db.buttonSpacing * (numColumns - 1)) + spacing * 2
+
+ self.frame:Size(barWidth, barHeight)
+ self.frame.mover:Size(barWidth, barHeight)
+
+ if db.backdrop then
+ self.frame.backdrop:Show()
+ else
+ self.frame.backdrop:Hide()
+ end
+
+ local verticalGrowth = (db.growFrom == "TOPLEFT" or db.growFrom == "TOPRIGHT") and "DOWN" or "UP"
+ local horizontalGrowth = (db.growFrom == "TOPLEFT" or db.growFrom == "BOTTOMLEFT") and "RIGHT" or "LEFT"
+
+ for i, button in ipairs(visibleButtons) do
+ self:UnlockButton(button)
+
+ button:Size(db.buttonSize)
+ button:ClearAllPoints()
+
+ if i == 1 then
+ local x, y
+ if db.growFrom == "TOPLEFT" then
+ x, y = spacing, -spacing
+ elseif db.growFrom == "TOPRIGHT" then
+ x, y = -spacing, -spacing
+ elseif db.growFrom == "BOTTOMLEFT" then
+ x, y = spacing, spacing
+ else
+ x, y = -spacing, spacing
+ end
+
+ button:Point(db.growFrom, self.frame, db.growFrom, x, y)
+ elseif (i - 1) % buttonsPerRow == 0 then
+ if verticalGrowth == "DOWN" then
+ button:Point("TOP", visibleButtons[i - buttonsPerRow], "BOTTOM", 0, -db.buttonSpacing)
+ else
+ button:Point("BOTTOM", visibleButtons[i - buttonsPerRow], "TOP", 0, db.buttonSpacing)
+ end
+ elseif horizontalGrowth == "RIGHT" then
+ button:Point("LEFT", visibleButtons[i - 1], "RIGHT", db.buttonSpacing, 0)
+ elseif horizontalGrowth == "LEFT" then
+ button:Point("RIGHT", visibleButtons[i - 1], "LEFT", -db.buttonSpacing, 0)
+ end
+
+ self:LockButton(button)
+ end
+
+ self.needUpdate = false
+end
+
+function MBG:UpdatePosition()
+ local db = E.db.enhanced.minimap.buttonGrabber.insideMinimap
+
+ if db.enable then
+ self.frame:ClearAllPoints()
+ self.frame:Point(db.position, Minimap, db.position, db.xOffset, db.yOffset)
+
+ E:DisableMover(self.frame.mover:GetName())
+ else
+ self.frame:ClearAllPoints()
+ self.frame:SetAllPoints(self.frame.mover)
+
+ E:EnableMover(self.frame.mover:GetName())
+ end
+end
+
+function MBG:UpdateAlpha()
+ self.maxAlpha = E.db.enhanced.minimap.buttonGrabber.alpha
+
+ if not E.db.enhanced.minimap.buttonGrabber.mouseover then
+ self.frame:SetAlpha(self.maxAlpha)
+ end
+end
+
+function MBG:ToggleMouseover()
+ local mouseover = E.db.enhanced.minimap.buttonGrabber.mouseover
+ local enter = mouseover and OnEnter or nil
+ local leave = mouseover and OnLeave or nil
+
+ self.frame:SetAlpha(mouseover and 0 or E.db.enhanced.minimap.buttonGrabber.alpha)
+ self.frame:SetScript("OnEnter", enter)
+ self.frame:SetScript("OnLeave", leave)
+
+ if #self.skinnedButtons > 0 then
+ for _, button in ipairs(self.skinnedButtons) do
+ button:SetScript("OnEnter", enter)
+ button:SetScript("OnLeave", leave)
+ end
+ end
+end
+
+local addonFixes = {
+ ["Atlas"] = function()
+ function AtlasButton_Toggle()
+ if AtlasButton:IsVisible() then
+ AtlasButton:Hide()
+ AtlasOptions.AtlasButtonShown = false
+ else
+ AtlasButton:Show()
+ AtlasOptions.AtlasButtonShown = true
+ end
+
+ AtlasOptions_Init()
+ end
+ end,
+ ["DBM-Core"] = function()
+ local button = DBMMinimapButton
+ if not button then return end
+
+ if button:GetScript("OnMouseDown") then
+ button:SetScript("OnMouseDown", nil)
+ button:SetScript("OnMouseUp", nil)
+ end
+ end,
+ ["Enchantrix"] = function()
+ if not Enchantrix or EnxMiniMapIcon then return end
+
+ local settings = Enchantrix.Settings
+ local oldButton = Enchantrix.MiniIcon
+
+ local newButton = CreateFrame("Button", "EnxMiniMapIcon", Minimap)
+ newButton:Size(20)
+ newButton:SetToplevel(true)
+ newButton:SetFrameStrata("LOW")
+ newButton:Point("RIGHT", Minimap, "LEFT", 0,0)
+ newButton:RegisterForClicks("LeftButtonUp", "RightButtonUp")
+
+ newButton.icon = oldButton.icon
+ newButton.icon:SetTexCoord(0.2, 0.84, 0.13, 0.87)
+ newButton.icon:SetParent(newButton)
+ newButton.icon:SetPoint("TOPLEFT", newButton, "TOPLEFT", 0, 0)
+
+ newButton.mask = oldButton.mask
+ newButton.mask:SetParent(newButton)
+ newButton.mask:SetPoint("TOPLEFT", newButton, "TOPLEFT", -8, 8)
+
+ newButton:SetScript("OnClick", oldButton:GetScript("OnClick"))
+
+ oldButton:SetMovable(false)
+ oldButton:SetParent(UIParent)
+ oldButton:Point("TOPRIGHT", UIParent)
+ oldButton:Hide()
+
+ oldButton:SetScript("OnMouseDown", nil)
+ oldButton:SetScript("OnMouseUp", nil)
+ oldButton:SetScript("OnDragStart", nil)
+ oldButton:SetScript("OnDragStop", nil)
+ oldButton:SetScript("OnClick", nil)
+ oldButton:SetScript("OnUpdate", nil)
+
+ Enchantrix.MiniIcon = newButton
+
+ function Enchantrix.MiniIcon.Reposition()
+ if settings.GetSetting("miniicon.enable") then
+ newButton:Show()
+ else
+ newButton:Hide()
+ end
+ end
+ end
+}
+
+function MBG:Initialize()
+ if not E.private.enhanced.minimapButtonGrabber then return end
+
+ local db = E.db.enhanced.minimap.buttonGrabber
+ local spacing = (db.backdrop and (E.Border + db.backdropSpacing) or E.Spacing)
+
+ self.skinnedButtons = {}
+ self.minimapFrames = {Minimap, MinimapBackdrop}
+
+ self.frame = CreateFrame("Frame", "ElvUI_MinimapButtonGrabber", UIParent)
+ self.frame:Size(db.buttonSize + (spacing * 2))
+ self.frame:Point("TOPRIGHT", MMHolder, "BOTTOMRIGHT", 0, 1)
+ self.frame:SetFrameStrata("LOW")
+ self.frame:SetClampedToScreen(true)
+ self.frame:CreateBackdrop()
+
+ self.frame.backdrop:SetPoint("TOPLEFT", self.frame, "TOPLEFT", E.Spacing, -E.Spacing)
+ self.frame.backdrop:SetPoint("BOTTOMRIGHT", self.frame, "BOTTOMRIGHT", -E.Spacing, E.Spacing)
+ self.frame.backdrop:Hide()
+
+ E:CreateMover(self.frame, "MinimapButtonGrabberMover", L["Minimap Button Grabber"], nil, nil, nil, "ALL,GENERAL")
+
+ if self.frame.mover:GetScript("OnSizeChanged") then
+ self.frame.mover:SetScript("OnSizeChanged", nil)
+ end
+
+ self.initialized = true
+
+ self:ToggleMouseover()
+ self:UpdateAlpha()
+ self:UpdatePosition()
+ self:GrabMinimapButtons()
+
+ self:ScheduleRepeatingTimer("GrabMinimapButtons", 5)
+
+ local AddonsCompat = E:GetModule("Enhanced_AddonsCompat")
+ for addon, func in pairs(addonFixes) do
+ AddonsCompat:AddAddon(addon, func)
+ end
+end
+
+local function InitializeCallback()
+ MBG:Initialize()
+end
+
+E:RegisterModule(MBG:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Maps/MinimapLocation.lua b/ElvUI_Enhanced/Modules/Maps/MinimapLocation.lua
new file mode 100644
index 0000000..7badbbc
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Maps/MinimapLocation.lua
@@ -0,0 +1,209 @@
+local E, L, V, P, G = unpack(ElvUI)
+local ML = E:NewModule("Enhanced_MinimapLocation", "AceHook-3.0")
+local M = E:GetModule("Minimap")
+
+local utf8sub = string.utf8sub
+
+local GetMinimapZoneText = GetMinimapZoneText
+local GetPlayerMapPosition = GetPlayerMapPosition
+local InCombatLockdown = InCombatLockdown
+local UIFrameFade = UIFrameFade
+
+local init = false
+local cluster, panel, location, xMap, yMap
+
+local digits = {
+ [0] = {.5, "%.0f"},
+ [1] = {.2, "%.1f"},
+ [2] = {.03, "%.2f"}
+}
+
+local function UpdateLocation(self, elapsed)
+ location.elapsed = (location.elapsed or 0) + elapsed
+ if location.elapsed < digits[E.db.enhanced.minimap.locationdigits][1] then return end
+
+ xMap.pos, yMap.pos = GetPlayerMapPosition("player")
+ xMap.text:SetFormattedText(digits[E.db.enhanced.minimap.locationdigits][2], xMap.pos * 100)
+ yMap.text:SetFormattedText(digits[E.db.enhanced.minimap.locationdigits][2], yMap.pos * 100)
+
+ location.elapsed = 0
+end
+
+local function CreateEnhancedMaplocation()
+ cluster = MinimapCluster
+
+ panel = CreateFrame("Frame", "EnhancedLocationPanel", MinimapCluster)
+ panel:SetFrameStrata("BACKGROUND")
+ panel:Point("CENTER", E.UIParent, "CENTER", 0, 0)
+ panel:Size(206, 22)
+
+ xMap = CreateFrame("Frame", "MapCoordinatesX", panel)
+ xMap:SetTemplate("Transparent")
+ xMap:Point("LEFT", panel, "LEFT", 0, 0)
+ xMap:Size(40, 22)
+
+ xMap.text = xMap:CreateFontString(nil, "OVERLAY")
+ xMap.text:FontTemplate()
+ xMap.text:SetAllPoints(xMap)
+
+ yMap = CreateFrame("Frame", "MapCoordinatesY", panel)
+ yMap:SetTemplate("Transparent")
+ yMap:Point("RIGHT", panel, "RIGHT", 0, 0)
+ yMap:Size(40, 22)
+
+ yMap.text = yMap:CreateFontString(nil, "OVERLAY")
+ yMap.text:FontTemplate()
+ yMap.text:SetAllPoints(yMap)
+
+ location = CreateFrame("Frame", "EnhancedLocationText", panel)
+ location:SetTemplate("Transparent")
+ location:Size(40, 22)
+ location:Point("LEFT", xMap, "RIGHT", E.PixelMode and -1 or 1, 0)
+ location:Point("RIGHT", yMap, "LEFT", E.PixelMode and 1 or -1, 0)
+
+ location.text = location:CreateFontString(nil, "OVERLAY")
+ location.text:FontTemplate()
+ location.text:SetAllPoints(location)
+end
+
+local function FadeFrame(frame, direction, startAlpha, endAlpha, time, func)
+ UIFrameFade(frame, {
+ mode = direction,
+ finishedFunc = func,
+ startAlpha = startAlpha,
+ endAlpha = endAlpha,
+ timeToFade = time
+ })
+end
+
+local function FadeInMinimap()
+ if not InCombatLockdown() then
+ FadeFrame(cluster, "IN", 0, 1, .5, function()
+ if not InCombatLockdown() then
+ cluster:Show()
+ end
+ end)
+ end
+end
+
+local function ShowMinimap()
+ if E.db.enhanced.minimap.fadeindelay == 0 then
+ FadeInMinimap()
+ else
+ E:Delay(E.db.enhanced.minimap.fadeindelay, FadeInMinimap)
+ end
+end
+
+local function HideMinimap()
+ cluster:Hide()
+end
+
+local function Update_ZoneText()
+ if E.db.enhanced.minimap.showlocationdigits then
+ xMap.text:FontTemplate(E.LSM:Fetch("font", E.db.general.minimap.locationFont), E.db.general.minimap.locationFontSize, E.db.general.minimap.locationFontOutline)
+ yMap.text:FontTemplate(E.LSM:Fetch("font", E.db.general.minimap.locationFont), E.db.general.minimap.locationFontSize, E.db.general.minimap.locationFontOutline)
+ end
+
+ location.text:FontTemplate(E.LSM:Fetch("font", E.db.general.minimap.locationFont), E.db.general.minimap.locationFontSize, E.db.general.minimap.locationFontOutline)
+ location.text:SetTextColor(M:GetLocTextColor())
+ location.text:SetText(utf8sub(GetMinimapZoneText(), 1, 25))
+end
+
+local function UpdateSettings()
+ if not init then
+ init = true
+ CreateEnhancedMaplocation()
+ end
+
+ if E.db.enhanced.minimap.hideincombat then
+ M:RegisterEvent("PLAYER_REGEN_DISABLED", HideMinimap)
+ M:RegisterEvent("PLAYER_REGEN_ENABLED", ShowMinimap)
+ else
+ M:UnregisterEvent("PLAYER_REGEN_DISABLED")
+ M:UnregisterEvent("PLAYER_REGEN_ENABLED")
+ end
+
+ local holder = MMHolder
+ panel:Point("BOTTOMLEFT", holder, "TOPLEFT", 0, -(E.PixelMode and 1 or -1))
+ panel:Size(E:Scale(holder:GetWidth()) + (E.PixelMode and 1 or -1), 22)
+
+ local point, relativeTo, relativePoint = holder:GetPoint()
+ if E.db.general.minimap.locationText == "ABOVE" then
+ holder:Point(point, relativeTo, relativePoint, 0, -21)
+ holder:Height(holder:GetHeight() + 22)
+
+ if E.db.enhanced.minimap.showlocationdigits then
+ panel:SetScript("OnUpdate", UpdateLocation)
+ location:ClearAllPoints()
+ location:Point("LEFT", xMap, "RIGHT", E.PixelMode and -1 or 1, 0)
+ location:Point("RIGHT", yMap, "LEFT", E.PixelMode and 1 or -1, 0)
+ location:Size(40, 22)
+ xMap:Show()
+ yMap:Show()
+ else
+ panel:SetScript("OnUpdate", nil)
+ location:ClearAllPoints()
+ location:Point("LEFT", panel, "LEFT", 0, 0)
+ location:Size(panel:GetWidth(), 22)
+ xMap:Hide()
+ yMap:Hide()
+ end
+
+ panel:Show()
+ else
+ holder:Point(point, relativeTo, relativePoint, 0, 0)
+ panel:SetScript("OnUpdate", nil)
+ panel:Hide()
+ end
+
+ if MinimapMover then
+ MinimapMover:Size(holder:GetSize())
+ end
+end
+
+function ML:UpdateSettings()
+ if not E.private.general.minimap.enable then return end
+
+ if E.db.enhanced.minimap.location then
+ if not self:IsHooked(M, "Update_ZoneText") then
+ self:SecureHook(M, "Update_ZoneText", Update_ZoneText)
+ end
+ if not self:IsHooked(M, "UpdateSettings") then
+ self:SecureHook(M, "UpdateSettings", UpdateSettings)
+ end
+
+ M:UpdateSettings()
+ M:Update_ZoneText()
+ elseif init then
+ self:UnhookAll()
+
+ local mmholder = MMHolder
+ local point, relativeTo, relativePoint = MMHolder:GetPoint()
+ mmholder:Point(point, relativeTo, relativePoint, 0, 0)
+
+ if E.db.datatexts.minimapPanels then
+ mmholder:Height(Minimap:GetHeight() + (LeftMiniPanel and (LeftMiniPanel:GetHeight() + E.Border) or 24) + E.Spacing * 3)
+ else
+ mmholder:Height(Minimap:GetHeight() + E.Border + E.Spacing * 3)
+ end
+
+ if MinimapMover then
+ MinimapMover:Size(mmholder:GetSize())
+ end
+
+ panel:Hide()
+ end
+end
+
+function ML:Initialize()
+ if not (E.private.general.minimap.enable and E.db.enhanced.minimap.location) then return end
+
+ self:SecureHook(M, "Update_ZoneText", Update_ZoneText)
+ self:SecureHook(M, "UpdateSettings", UpdateSettings)
+end
+
+local function InitializeCallback()
+ ML:Initialize()
+end
+
+E:RegisterModule(ML:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Maps/WorldMapBlips.lua b/ElvUI_Enhanced/Modules/Maps/WorldMapBlips.lua
new file mode 100644
index 0000000..35b17b4
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Maps/WorldMapBlips.lua
@@ -0,0 +1,70 @@
+local E, L, V, P, G = unpack(ElvUI)
+local WMB = E:NewModule("Enhanced_WorldMapBlips")
+
+local _G = _G
+
+local UnitClass = UnitClass
+local UnitInParty = UnitInParty
+
+local BLIP_TEX_COORDS = { 0.5, 0.625, 0, 0.25 }
+
+local BLIP_RAID_Y_OFFSET = 0.5
+
+local function OnShowParty(self)
+ local _, class = UnitClass(self.unit)
+ if not class then return end
+
+ if self.class ~= class then
+ self.class = class
+ self.icon:SetTexCoord(unpack(BLIP_TEX_COORDS))
+ end
+end
+
+local function OnShowRaid(self)
+ if not self.unit then return end -- players in the battleground not in your raid
+
+ local _, class = UnitClass(self.unit)
+ if not class then return end
+
+ local inParty = UnitInParty(self.unit)
+
+ if self.class ~= class or self.inParty ~= inParty then
+ self.class = class
+ self.inParty = inParty
+
+ if inParty then
+ self.icon:SetTexCoord(unpack(BLIP_TEX_COORDS))
+ else
+ self.icon:SetTexCoord(BLIP_TEX_COORDS[1], BLIP_TEX_COORDS[2], BLIP_TEX_COORDS[3] + BLIP_RAID_Y_OFFSET, BLIP_TEX_COORDS[4] + BLIP_RAID_Y_OFFSET)
+ end
+ end
+end
+
+function WMB:Initialize()
+ local _, _, _, enabled, _, reason = GetAddOnInfo("Mapster")
+ if reason ~= "MISSED" and enabled then return end
+
+ local frame
+
+ for i = 1, MAX_PARTY_MEMBERS do
+ frame = _G["WorldMapParty"..i]
+ frame.icon:SetTexture("Interface\\Addons\\ElvUI_Enhanced\\Media\\Textures\\PartyRaidBlips")
+ frame:Size(24)
+ frame:HookScript("OnShow", OnShowParty)
+ end
+
+ for i = 1, MAX_RAID_MEMBERS do
+ frame = _G["WorldMapRaid"..i]
+ frame.icon:SetTexture("Interface\\Addons\\ElvUI_Enhanced\\Media\\Textures\\PartyRaidBlips")
+ frame:Size(24)
+ frame:HookScript("OnShow", OnShowRaid)
+ end
+
+ Minimap:SetClassBlipTexture("Interface\\Addons\\ElvUI_Enhanced\\Media\\Textures\\PartyRaidBlips")
+end
+
+local function InitializeCallback()
+ WMB:Initialize()
+end
+
+E:RegisterModule(WMB:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/AddonsCompatibility.lua b/ElvUI_Enhanced/Modules/Misc/AddonsCompatibility.lua
new file mode 100644
index 0000000..df2df95
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/AddonsCompatibility.lua
@@ -0,0 +1,330 @@
+local E, L, V, P, G = unpack(ElvUI)
+local AC = E:NewModule("Enhanced_AddonsCompat", "AceEvent-3.0")
+
+local pairs, ipairs = pairs, ipairs
+local type = type
+local tinsert, tremove = table.insert, table.remove
+
+local GetAddOnInfo = GetAddOnInfo
+local GetNumAddOns = GetNumAddOns
+local IsAddOnLoadOnDemand = IsAddOnLoadOnDemand
+local IsAddOnLoaded = IsAddOnLoaded
+
+local externalFixes = {}
+
+local addonFixes = {
+ -- Cromulent 1.5.2
+ ["Cromulent"] = function()
+ local WORLDMAP_SETTINGS = WORLDMAP_SETTINGS
+ local WORLDMAP_WINDOWED_SIZE = WORLDMAP_WINDOWED_SIZE
+ local WORLDMAP_QUESTLIST_SIZE = WORLDMAP_QUESTLIST_SIZE
+
+ local _, fontSize = CromulentZoneInfo.text:GetFont()
+ local fontSizeWindowed = fontSize / WORLDMAP_WINDOWED_SIZE + 10
+ local fontSizeQuestlist = fontSize / WORLDMAP_QUESTLIST_SIZE + 5
+
+ local function UpdateFontSize()
+ if CromulentZoneInfo:IsShown() then
+ if WORLDMAP_SETTINGS.size == WORLDMAP_WINDOWED_SIZE then
+ CromulentZoneInfo.text:FontTemplate(nil, fontSizeWindowed, "OUTLINE")
+ elseif WORLDMAP_SETTINGS.size == WORLDMAP_QUESTLIST_SIZE then
+ CromulentZoneInfo.text:FontTemplate(nil, fontSizeQuestlist, "OUTLINE")
+ else
+ CromulentZoneInfo.text:FontTemplate(nil, fontSize, "OUTLINE")
+ end
+ end
+ end
+
+ UpdateFontSize()
+ hooksecurefunc(WorldMapFrameAreaFrame, "SetScale", UpdateFontSize)
+ end,
+
+ -- GroupCalendar 4.6.1
+ ["GroupCalendar"] = function()
+ local DT = E:GetModule("DataTexts")
+ if DT.RegisteredDataTexts and DT.RegisteredDataTexts["Time"] then
+ DT.RegisteredDataTexts["Time"].onClick = function(_, btn)
+ if btn == "RightButton" then
+ if not IsAddOnLoaded("Blizzard_TimeManager") then
+ LoadAddOn("Blizzard_TimeManager")
+ end
+ TimeManagerClockButton_OnClick(TimeManagerClockButton)
+ elseif GroupCalendar and GroupCalendar.ToggleCalendarDisplay then
+ GroupCalendar.ToggleCalendarDisplay()
+ else
+ GameTimeFrame:Click()
+ end
+ end
+ end
+ end,
+
+ -- CLCRet 1.3.03.025
+ -- https://www.curseforge.com/wow/addons/clcret/files/439502
+ ["CLCRet"] = function()
+ local UnitAffectingCombat = UnitAffectingCombat
+ local UnitCanAttack = UnitCanAttack
+ local UnitClassification = UnitClassification
+ local UnitExists = UnitExists
+ local UnitIsDead = UnitIsDead
+
+ local db = clcret.db.profile
+
+ function clcret:Enable()
+ self.addonEnabled = true
+ self.frame:Show()
+ end
+ function clcret:Disable()
+ self.addonEnabled = false
+ self.frame:Hide()
+ end
+
+ function clcret:PLAYER_REGEN_ENABLED()
+ if not self.addonEnabled then return end
+ self.frame:Hide()
+ end
+ function clcret:PLAYER_REGEN_DISABLED()
+ if not self.addonEnabled then return end
+ self.frame:Hide()
+ end
+ function clcret:PLAYER_TARGET_CHANGED()
+ if not self.addonEnabled then return end
+
+ if db.show == "boss" then
+ if UnitClassification("target") ~= "worldboss" then
+ self.frame:Hide()
+ return
+ end
+ end
+
+ if UnitExists("target") and UnitCanAttack("player", "target") and (not UnitIsDead("target")) then
+ self.frame:Show()
+ else
+ self.frame:Hide()
+ end
+ end
+
+ hooksecurefunc(clcret, "UpdateShowMethod", function(self)
+ if db.show == "combat" and self.addonEnabled then
+ if UnitAffectingCombat("player") then
+ self.frame:Show()
+ else
+ self.frame:Hide()
+ end
+ elseif db.show ~= "valid" and db.show ~= "boss" and self.addonEnabled then
+ self.frame:Show()
+ end
+ end)
+ end,
+
+ -- DrDamage 1.7.8
+ -- https://www.wowace.com/projects/dr-damage/files/426084
+ ["DrDamage"] = function()
+ if not E.private.actionbar.enable then return end
+
+ local HasAction = HasAction
+ local SecureButton_GetEffectiveButton = SecureButton_GetEffectiveButton
+ local SecureButton_GetModifiedAttribute = SecureButton_GetModifiedAttribute
+
+ local AB = E:GetModule("ActionBars")
+
+ local DrD_ProcessButton = function(button, func, spell, uid, mana, disable)
+ if not button then return end
+ if not spell and not uid and not mana then
+ local frame = button.drd
+ if frame then frame:SetText(nil) end
+ frame = button.drd2
+ if frame then frame:SetText(nil) end
+ end
+ if not DrDamage.db.profile.ABText or disable then return end
+ if button:IsVisible() then
+ local id, name, rank = func(button)
+ if id and (not HasAction(id) or uid and uid ~= id) then return end
+ DrDamage:CheckAction(button, spell, id, name, rank, mana)
+ end
+ end
+
+ local updateFunc = function(button)
+ return SecureButton_GetModifiedAttribute(button, "action", SecureButton_GetEffectiveButton(button))
+ end
+
+ hooksecurefunc(DrDamage, "UpdateAB", function(self, spell, uid, disable, mana)
+ for _, bar in pairs(AB.handledBars) do
+ for _, button in ipairs(bar.buttons) do
+ DrD_ProcessButton(button, updateFunc, spell, uid, mana, disable)
+ end
+ end
+ end)
+ end,
+
+ -- All Stats 1.1
+ -- https://www.curseforge.com/wow/addons/all-stats/files/430951
+ ["AllStats"] = function()
+ if E.private.enhanced.character.modelFrames and not E.private.enhanced.character.enable then
+ CharacterModelFrame:Size(237, 324)
+ end
+ end,
+
+ -- https://github.com/ElvUI-WotLK/ElvUI_Enhanced/issues/100
+ ["OmniBar"] = function()
+ hooksecurefunc("OmniBar_CreateIcon", function(self)
+ E:RegisterCooldown(self.icons[#self.icons].cooldown)
+ end)
+
+ for _, icon in ipairs(OmniBar.icons) do
+ E:RegisterCooldown(icon.cooldown)
+ end
+ end,
+
+ -- BlizzMove r18
+ -- https://www.curseforge.com/wow/addons/blizzmove/files/456128
+ -- https://github.com/ElvUI-WotLK/ElvUI_Enhanced/issues/96
+ ["BlizzMove"] = function()
+ if E.private.enhanced.character.enable then
+ local MouseIsOver = MouseIsOver
+
+ local origOnMouseWheel
+
+ local function onMouseWheel(self, delta)
+ if CharacterStatsPane:IsShown() and MouseIsOver(CharacterStatsPane) then
+ CharacterStatsPane:GetScript("OnMouseWheel")(CharacterStatsPane, delta)
+ elseif PaperDollTitlesPane:IsShown() and MouseIsOver(PaperDollTitlesPane) then
+ PaperDollTitlesPane:GetScript("OnMouseWheel")(PaperDollTitlesPane, delta)
+ elseif PaperDollEquipmentManagerPane:IsShown() and MouseIsOver(PaperDollEquipmentManagerPane) then
+ PaperDollEquipmentManagerPane:GetScript("OnMouseWheel")(PaperDollEquipmentManagerPane, delta)
+ else
+ origOnMouseWheel(self, delta)
+ end
+ end
+
+ local f = CreateFrame("Frame")
+ f:RegisterEvent("PLAYER_ENTERING_WORLD")
+ f:SetScript("OnEvent", function(self)
+ self:UnregisterEvent("PLAYER_ENTERING_WORLD")
+
+ origOnMouseWheel = PaperDollFrame:GetScript("OnMouseWheel")
+
+ if PaperDollFrame.frameToMove and PaperDollFrame.frameToMove.EnableMouse then
+ PaperDollFrame:SetScript("OnMouseWheel", onMouseWheel)
+ end
+
+ hooksecurefunc(BlizzMove, "Toggle", function(self, handler)
+ if handler == PaperDollFrame then
+ if not handler:GetScript("OnDragStart") then
+ PaperDollFrame:SetScript("OnMouseWheel", nil)
+ else
+ PaperDollFrame:SetScript("OnMouseWheel", onMouseWheel)
+ end
+ end
+ end)
+ end)
+ end
+ end,
+
+ -- InspectEquip 1.7.7
+ ["InspectEquip"] = function()
+ if E.private.enhanced.character.enable then
+ PaperDollFrame:HookScript("OnShow", InspectEquip.PaperDollFrame_OnShow)
+ PaperDollFrame:HookScript("OnHide", InspectEquip.PaperDollFrame_OnHide)
+ end
+ end,
+}
+
+function AC:AddAddon(addon, func)
+ if type(addon) ~= "string" then
+ error(string.format("bad argument #1 to 'AddAddon' (string expected, got %s)", addon ~= nil and type(addon) or "no value"), 2)
+ elseif func and type(func) ~= "function" then
+ error(string.format("bad argument #2 to 'AddAddon' (function expected, got %s)", func ~= nil and type(func) or "no value"), 2)
+ end
+
+ if not self.initialized then
+ self.preinitList = self.preinitList or {}
+ self.preinitList[addon] = func
+ return
+ end
+
+ if not self.addonList[addon] then return end
+
+ if IsAddOnLoaded(addon) then
+ self:ApplyFix(addon, func)
+ elseif IsAddOnLoadOnDemand(addon) then
+ if not addonFixes[addon] then
+ externalFixes[addon] = externalFixes[addon] or {}
+ tinsert(externalFixes[addon], func)
+ end
+
+ tinsert(self.addonQueue, addon)
+ self:RegisterEvent("ADDON_LOADED")
+ end
+end
+
+function AC:ApplyFix(addon, func)
+ if func then
+ func()
+
+ if addonFixes[addon] then
+ addonFixes[addon] = nil
+ end
+ else
+ if addonFixes[addon] then
+ addonFixes[addon]()
+ addonFixes[addon] = nil
+ end
+
+ if externalFixes[addon] then
+ for i = 1, #externalFixes[addon] do
+ externalFixes[addon][i]()
+ end
+
+ externalFixes[addon] = nil
+ end
+ end
+end
+
+function AC:ADDON_LOADED(_, addonName)
+ if not (addonFixes[addonName] or externalFixes[addonName]) then return end
+
+ for i, addon in ipairs(self.addonQueue) do
+ if addon == addonName then
+ self:ApplyFix(addon)
+
+ tremove(self.addonQueue, i)
+
+ if #self.addonQueue == 0 then
+ self:UnregisterEvent("ADDON_LOADED")
+ end
+
+ break
+ end
+ end
+end
+
+function AC:Initialize()
+ self.addonQueue = {}
+ self.addonList = {}
+
+ for i = 1, GetNumAddOns() do
+ local name, _, _, enabled = GetAddOnInfo(i)
+
+ if enabled or IsAddOnLoadOnDemand(i) then
+ self.addonList[name] = true
+ end
+ end
+
+ self.initialized = true
+
+ for addon, func in pairs(addonFixes) do
+ self:AddAddon(addon, func)
+ end
+
+ if self.preinitList then
+ for addon, func in pairs(self.preinitList) do
+ self:AddAddon(addon, func)
+ end
+ end
+end
+
+local function InitializeCallback()
+ AC:Initialize()
+end
+
+E:RegisterModule(AC:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/AlreadyKnown.lua b/ElvUI_Enhanced/Modules/Misc/AlreadyKnown.lua
new file mode 100644
index 0000000..f0aaaf6
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/AlreadyKnown.lua
@@ -0,0 +1,275 @@
+local E, L, V, P, G = unpack(ElvUI)
+local AK = E:NewModule("Enhanced_AlreadyKnown", "AceHook-3.0", "AceEvent-3.0")
+
+local _G = _G
+local match = string.match
+local ceil, fmod = math.ceil, math.fmod
+
+local FauxScrollFrame_GetOffset = FauxScrollFrame_GetOffset
+local GetAuctionItemClasses = GetAuctionItemClasses
+local GetAuctionItemInfo = GetAuctionItemInfo
+local GetAuctionItemLink = GetAuctionItemLink
+local GetBuybackItemInfo = GetBuybackItemInfo
+local GetBuybackItemLink = GetBuybackItemLink
+local GetCurrentGuildBankTab = GetCurrentGuildBankTab
+local GetGuildBankItemInfo = GetGuildBankItemInfo
+local GetGuildBankItemLink = GetGuildBankItemLink
+local GetItemInfo = GetItemInfo
+local GetMerchantItemInfo = GetMerchantItemInfo
+local GetMerchantItemLink = GetMerchantItemLink
+local GetMerchantNumItems = GetMerchantNumItems
+local GetNumAuctionItems = GetNumAuctionItems
+local GetNumBuybackItems = GetNumBuybackItems
+local IsAddOnLoaded = IsAddOnLoaded
+local SetItemButtonTextureVertexColor = SetItemButtonTextureVertexColor
+
+local BUYBACK_ITEMS_PER_PAGE = BUYBACK_ITEMS_PER_PAGE
+local ITEM_SPELL_KNOWN = ITEM_SPELL_KNOWN
+local MERCHANT_ITEMS_PER_PAGE = MERCHANT_ITEMS_PER_PAGE
+
+local knownColor = {r = 0.1, g = 1.0, b = 0.2}
+
+local function MerchantFrame_UpdateMerchantInfo()
+ local numItems = GetMerchantNumItems()
+
+ for i = 1, BUYBACK_ITEMS_PER_PAGE do
+ local index = (MerchantFrame.page - 1) * MERCHANT_ITEMS_PER_PAGE + i
+ if index > numItems then return end
+
+ local button = _G["MerchantItem"..i.."ItemButton"]
+
+ if button and button:IsShown() then
+ local _, _, _, _, numAvailable, isUsable = GetMerchantItemInfo(index)
+
+ if isUsable and AK:IsAlreadyKnown(GetMerchantItemLink(index)) then
+ local r, g, b = knownColor.r, knownColor.g, knownColor.b
+
+ if numAvailable == 0 then
+ r, g, b = r * 0.5, g * 0.5, b * 0.5
+ end
+
+ SetItemButtonTextureVertexColor(button, r, g, b)
+ end
+ end
+ end
+end
+
+local function MerchantFrame_UpdateBuybackInfo()
+ local numItems = GetNumBuybackItems()
+
+ for i = 1, BUYBACK_ITEMS_PER_PAGE do
+ if i > numItems then return end
+
+ local button = _G["MerchantItem"..i.."ItemButton"]
+
+ if button and button:IsShown() then
+ local _, _, _, _, _, isUsable = GetBuybackItemInfo(i)
+
+ if isUsable and AK:IsAlreadyKnown(GetBuybackItemLink(i)) then
+ SetItemButtonTextureVertexColor(button, knownColor.r, knownColor.g, knownColor.b)
+ end
+ end
+ end
+end
+
+local function AuctionFrameBrowse_Update()
+ local numItems = GetNumAuctionItems("list")
+ local offset = FauxScrollFrame_GetOffset(BrowseScrollFrame)
+
+ for i = 1, NUM_BROWSE_TO_DISPLAY do
+ local index = offset + i
+ if index > numItems then return end
+
+ local texture = _G["BrowseButton"..i.."ItemIconTexture"]
+
+ if texture and texture:IsShown() then
+ local _, _, _, _, canUse = GetAuctionItemInfo("list", index)
+
+ if canUse and AK:IsAlreadyKnown(GetAuctionItemLink("list", index)) then
+ texture:SetVertexColor(knownColor.r, knownColor.g, knownColor.b)
+ end
+ end
+ end
+end
+
+local function AuctionFrameBid_Update()
+ local numItems = GetNumAuctionItems("bidder")
+ local offset = FauxScrollFrame_GetOffset(BidScrollFrame)
+
+ for i = 1, NUM_BIDS_TO_DISPLAY do
+ local index = offset + i
+ if index > numItems then return end
+
+ local texture = _G["BidButton"..i.."ItemIconTexture"]
+
+ if texture and texture:IsShown() then
+ local _, _, _, _, canUse = GetAuctionItemInfo("bidder", index)
+
+ if canUse and AK:IsAlreadyKnown(GetAuctionItemLink("bidder", index)) then
+ texture:SetVertexColor(knownColor.r, knownColor.g, knownColor.b)
+ end
+ end
+ end
+end
+
+local function AuctionFrameAuctions_Update()
+ local numItems = GetNumAuctionItems("owner")
+ local offset = FauxScrollFrame_GetOffset(AuctionsScrollFrame)
+
+ for i = 1, NUM_AUCTIONS_TO_DISPLAY do
+ local index = offset + i
+ if index > numItems then return end
+
+ local texture = _G["AuctionsButton"..i.."ItemIconTexture"]
+
+ if texture and texture:IsShown() then
+ local _, _, _, _, canUse, _, _, _, _, _, _, _, saleStatus = GetAuctionItemInfo("owner", index)
+
+ if canUse and AK:IsAlreadyKnown(GetAuctionItemLink("owner", index)) then
+ local r, g, b = knownColor.r, knownColor.g, knownColor.b
+ if saleStatus == 1 then
+ r, g, b = r * 0.5, g * 0.5, b * 0.5
+ end
+
+ texture:SetVertexColor(r, g, b)
+ end
+ end
+ end
+end
+
+local function GuildBankFrame_Update()
+ if GuildBankFrame.mode ~= "bank" then return end
+
+ local tab = GetCurrentGuildBankTab()
+
+ for i = 1, MAX_GUILDBANK_SLOTS_PER_TAB do
+ local button = _G["GuildBankColumn"..ceil((i - 0.5) / NUM_SLOTS_PER_GUILDBANK_GROUP).."Button"..fmod(i, NUM_SLOTS_PER_GUILDBANK_GROUP)]
+
+ if button and button:IsShown() then
+ local texture, _, locked = GetGuildBankItemInfo(tab, i)
+
+ if texture and not locked then
+ if AK:IsAlreadyKnown(GetGuildBankItemLink(tab, i)) then
+ SetItemButtonTextureVertexColor(button, knownColor.r, knownColor.g, knownColor.b)
+ else
+ SetItemButtonTextureVertexColor(button, 1, 1, 1)
+ end
+ end
+ end
+ end
+end
+
+function AK:IsAlreadyKnown(itemLink)
+ if not itemLink then return end
+
+ local itemID = match(itemLink, "item:(%d+):")
+ if self.knownTable[itemID] then return true end
+
+ local _, _, _, _, _, itemType = GetItemInfo(itemLink)
+ if not self.knowableTypes[itemType] then return end
+
+ self.scantip:ClearLines()
+ self.scantip:SetHyperlink(itemLink)
+
+ for i = 2, self.scantip:NumLines() do
+ local text = _G["ElvUI_MerchantAlreadyKnownTextLeft"..i]:GetText()
+
+ if text == ITEM_SPELL_KNOWN then
+ self.knownTable[itemID] = true
+ return true
+ end
+ end
+end
+
+function AK:ADDON_LOADED(_, addon)
+ if addon == "Blizzard_AuctionUI" and not self.auctionHooked then
+ self:SetHooks()
+ elseif addon == "Blizzard_GuildBankUI" and not self.guildBankHooked then
+ self:SetHooks()
+ end
+
+ if self.auctionHooked and self.guildBankHooked then
+ self:UnregisterEvent("ADDON_LOADED")
+ end
+end
+
+function AK:SetHooks()
+ if not self:IsHooked("MerchantFrame_UpdateMerchantInfo") then
+ self:SecureHook("MerchantFrame_UpdateMerchantInfo", MerchantFrame_UpdateMerchantInfo)
+ end
+ if not self:IsHooked("MerchantFrame_UpdateBuybackInfo") then
+ self:SecureHook("MerchantFrame_UpdateBuybackInfo", MerchantFrame_UpdateBuybackInfo)
+ end
+
+ if not self.auctionHooked and IsAddOnLoaded("Blizzard_AuctionUI") then
+ if not self:IsHooked("AuctionFrameBrowse_Update") then
+ self:SecureHook("AuctionFrameBrowse_Update", AuctionFrameBrowse_Update)
+ end
+ if not self:IsHooked("AuctionFrameBid_Update") then
+ self:SecureHook("AuctionFrameBid_Update", AuctionFrameBid_Update)
+ end
+ if not self:IsHooked("AuctionFrameAuctions_Update") then
+ self:SecureHook("AuctionFrameAuctions_Update", AuctionFrameAuctions_Update)
+ end
+
+ self.auctionHooked = true
+ end
+
+ if not self.guildBankHooked and IsAddOnLoaded("Blizzard_GuildBankUI") then
+ if not self:IsHooked("GuildBankFrame_Update") then
+ self:SecureHook("GuildBankFrame_Update", GuildBankFrame_Update)
+ end
+
+ self.guildBankHooked = true
+ end
+end
+
+function AK:IsLoadeble()
+ return not (IsAddOnLoaded("RecipeKnown") or IsAddOnLoaded("AlreadyKnown"))
+end
+
+function AK:ToggleState()
+ if not self:IsLoadeble() then return end
+
+ if not self.initialized then
+ self.scantip = CreateFrame("GameTooltip", "ElvUI_MerchantAlreadyKnown", nil, "GameTooltipTemplate")
+ self.scantip:SetOwner(UIParent, "ANCHOR_NONE")
+
+ self.knownTable = {}
+
+ local _, _, _, consumable, glyph, _, recipe, _, miscallaneous = GetAuctionItemClasses()
+ self.knowableTypes = {
+ [consumable] = true,
+ [glyph] = true,
+ [recipe] = true,
+ [miscallaneous] = true
+ }
+
+ self.initialized = true
+ end
+
+ if E.db.enhanced.general.alreadyKnown then
+ self:SetHooks()
+
+ if not (IsAddOnLoaded("Blizzard_AuctionUI") and IsAddOnLoaded("Blizzard_GuildBankUI")) then
+ self:RegisterEvent("ADDON_LOADED")
+ end
+ else
+ self:UnhookAll()
+
+ self.auctionHooked = nil
+ self.guildBankHooked = nil
+ end
+end
+
+function AK:Initialize()
+ if not E.db.enhanced.general.alreadyKnown then return end
+
+ self:ToggleState()
+end
+
+local function InitializeCallback()
+ AK:Initialize()
+end
+
+E:RegisterModule(AK:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/EquipmentInfo.lua b/ElvUI_Enhanced/Modules/Misc/EquipmentInfo.lua
new file mode 100644
index 0000000..468c5e2
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/EquipmentInfo.lua
@@ -0,0 +1,246 @@
+local E, L, V, P, G = unpack(ElvUI)
+local EI = E:NewModule("Enhanced_EquipmentInfo", "AceHook-3.0", "AceEvent-3.0")
+
+local _G = _G
+local format = string.format
+local pairs = pairs
+
+local GetInventoryItemDurability = GetInventoryItemDurability
+local GetInventoryItemID = GetInventoryItemID
+local GetInventorySlotInfo = GetInventorySlotInfo
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+local InCombatLockdown = InCombatLockdown
+local IsAddOnLoaded = IsAddOnLoaded
+
+local slots = {
+ ["HeadSlot"] = true,
+ ["NeckSlot"] = false,
+ ["ShoulderSlot"] = true,
+ ["BackSlot"] = false,
+ ["ChestSlot"] = true,
+-- ["ShirtSlot"] = false,
+-- ["TabardSlot"] = false,
+ ["WristSlot"] = true,
+ ["HandsSlot"] = true,
+ ["WaistSlot"] = true,
+ ["LegsSlot"] = true,
+ ["FeetSlot"] = true,
+ ["Finger0Slot"] = false,
+ ["Finger1Slot"] = false,
+ ["Trinket0Slot"] = false,
+ ["Trinket1Slot"] = false,
+ ["MainHandSlot"] = true,
+ ["SecondaryHandSlot"] = true,
+ ["RangedSlot"] = true,
+-- ["AmmoSlot"] = false,
+}
+
+function EI:UpdatePaperDoll(unit)
+ if not self.initialized then return end
+
+ if unit == "player" and InCombatLockdown() then
+ self:RegisterEvent("PLAYER_REGEN_ENABLED", "OnEvent")
+ return
+ elseif unit ~= "player" then
+ if InspectFrame then
+ unit = InspectFrame.unit
+
+ if not unit then return end
+ else
+ return
+ end
+ end
+
+ local baseName = unit == "player" and "Character" or "Inspect"
+ local frame, slotID, itemID
+ local _, rarity, itemLevel
+ local current, maximum, r, g, b
+
+ for slotName, durability in pairs(slots) do
+ frame = _G[format("%s%s", baseName, slotName)]
+
+ if frame then
+ slotID = GetInventorySlotInfo(slotName)
+
+ frame.ItemLevel:SetText()
+
+ if E.db.enhanced.equipment.itemlevel.enable then
+ itemID = GetInventoryItemID(unit, slotID)
+
+ if itemID then
+ _, _, rarity, itemLevel = GetItemInfo(itemID)
+
+ if itemLevel then
+ frame.ItemLevel:SetText(itemLevel)
+
+ if E.db.enhanced.equipment.itemlevel.qualityColor then
+ frame.ItemLevel:SetTextColor()
+ if rarity and rarity > 1 then
+ frame.ItemLevel:SetTextColor(GetItemQualityColor(rarity))
+ else
+ frame.ItemLevel:SetTextColor(1, 1, 1)
+ end
+ else
+ frame.ItemLevel:SetTextColor(1, 1, 1)
+ end
+ end
+ end
+ end
+
+ if unit == "player" and durability then
+ frame.DurabilityInfo:SetText()
+
+ if E.db.enhanced.equipment.durability.enable then
+ current, maximum = GetInventoryItemDurability(slotID)
+
+ if current and maximum and (not E.db.enhanced.equipment.durability.onlydamaged or current < maximum) then
+ r, g, b = E:ColorGradient((current / maximum), 1, 0, 0, 1, 1, 0, 0, 1, 0)
+ frame.DurabilityInfo:SetFormattedText("%s%.0f%%|r", E:RGBToHex(r, g, b), (current / maximum) * 100)
+ end
+ end
+ end
+ end
+ end
+end
+
+function EI:BuildInfoText(name)
+ local frame
+
+ for slotName, durability in pairs(slots) do
+ frame = _G[format("%s%s", name, slotName)]
+
+ frame.ItemLevel = frame:CreateFontString(nil, "OVERLAY")
+
+ if name == "Character" and durability then
+ frame.DurabilityInfo = frame:CreateFontString(nil, "OVERLAY")
+ end
+ end
+
+ self:UpdateInfoText(name)
+end
+
+function EI:UpdateInfoText(name)
+ local db = E.db.enhanced.equipment
+ local frame
+
+ for slotName, durability in pairs(slots) do
+ frame = _G[format("%s%s", name, slotName)]
+
+ if frame then
+ frame.ItemLevel:ClearAllPoints()
+ frame.ItemLevel:Point(db.itemlevel.position, frame, db.itemlevel.xOffset, db.itemlevel.yOffset)
+ frame.ItemLevel:FontTemplate(E.LSM:Fetch("font", db.font), db.fontSize, db.fontOutline)
+
+ if name == "Character" and durability then
+ frame.DurabilityInfo:ClearAllPoints()
+ frame.DurabilityInfo:Point(db.durability.position, frame, db.durability.xOffset, db.durability.yOffset)
+ frame.DurabilityInfo:FontTemplate(E.LSM:Fetch("font", db.font), db.fontSize, db.fontOutline)
+ end
+ end
+ end
+end
+
+local function InspectFrameUpdate()
+ EI:UpdatePaperDoll()
+end
+
+function EI:OnEvent(event, unit)
+ if event == "UPDATE_INVENTORY_DURABILITY" then
+ self:UpdatePaperDoll("player")
+ elseif event == "UNIT_INVENTORY_CHANGED" then
+ if unit ~= "player" and InspectFrame and unit == InspectFrame.unit then
+ self:UpdatePaperDoll(unit)
+ end
+ elseif event == "PLAYER_REGEN_ENABLED" then
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED")
+ self:UpdatePaperDoll("player")
+ elseif event == "ADDON_LOADED" and unit == "Blizzard_InspectUI" then
+ self.initializedInspect = true
+ self:UnregisterEvent("ADDON_LOADED")
+ self:BuildInfoText("Inspect")
+ self:HookScript(InspectFrame, "OnShow", InspectFrameUpdate)
+ self:SecureHook("InspectFrame_UnitChanged", InspectFrameUpdate)
+ end
+end
+
+function EI:InitialUpdatePaperDoll()
+ if self.initialized then return end
+
+ self:UnregisterEvent("PLAYER_ENTERING_WORLD")
+ self:BuildInfoText("Character")
+
+ self.initialized = true
+end
+
+function EI:UpdateText()
+ self:UpdatePaperDoll("player")
+
+ if self.initializedInspect and InspectFrame.unit then
+ self:UpdatePaperDoll()
+ end
+end
+
+function EI:UpdateTextSettings()
+ self:UpdateInfoText("Character")
+
+ if self.initializedInspect then
+ self:UpdateInfoText("Inspect")
+ end
+end
+
+function EI:ToggleState(init)
+ if E.db.enhanced.equipment.enable then
+ if not self.initialized then
+ if init then
+ self:RegisterEvent("PLAYER_ENTERING_WORLD", "InitialUpdatePaperDoll")
+ else
+ self:InitialUpdatePaperDoll()
+ end
+
+ if IsAddOnLoaded("Blizzard_InspectUI") or InspectFrame then
+ self:OnEvent("ADDON_LOADED", "Blizzard_InspectUI")
+ else
+ self:RegisterEvent("ADDON_LOADED", "OnEvent")
+ end
+ end
+
+ self:UpdateText()
+
+ self:RegisterEvent("UPDATE_INVENTORY_DURABILITY", "OnEvent")
+ self:RegisterEvent("UNIT_INVENTORY_CHANGED", "OnEvent")
+
+ if not self.initializedInspect then
+ self:RegisterEvent("ADDON_LOADED", "OnEvent")
+ end
+ elseif self.initialized then
+ self:UnhookAll()
+ self:UnregisterAllEvents()
+
+ for slotName, durability in pairs(slots) do
+ _G["Character"..slotName].ItemLevel:SetText()
+
+ if durability then
+ _G["Character"..slotName].DurabilityInfo:SetText()
+ end
+
+ if self.initializedInspect then
+ if _G["Inspect"..slotName].ItemLevel then
+ _G["Inspect"..slotName].ItemLevel:SetText()
+ end
+ end
+ end
+ end
+end
+
+function EI:Initialize()
+ if not E.db.enhanced.equipment.enable then return end
+
+ self:ToggleState(true)
+end
+
+local function InitializeCallback()
+ EI:Initialize()
+end
+
+E:RegisterModule(EI:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/Faction.lua b/ElvUI_Enhanced/Modules/Misc/Faction.lua
new file mode 100644
index 0000000..f4e0953
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/Faction.lua
@@ -0,0 +1,47 @@
+local E, L, V, P, G = unpack(ElvUI)
+local M = E:GetModule("Enhanced_Misc")
+
+local find, gsub = string.find, string.gsub
+
+local GetFactionInfo = GetFactionInfo
+local GetNumFactions = GetNumFactions
+local GetWatchedFactionInfo = GetWatchedFactionInfo
+local IsFactionInactive = IsFactionInactive
+local SetWatchedFactionIndex = SetWatchedFactionIndex
+
+local increased = gsub(gsub(FACTION_STANDING_INCREASED, "(%%s)", "(.+)"), "(%%d)", "(.+)")
+local decreased = gsub(gsub(FACTION_STANDING_DECREASED, "(%%s)", "(.+)"), "(%%d)", "(.+)")
+local changed = gsub(gsub(FACTION_STANDING_CHANGED, "(%%s)", "(.+)"), "(%%d)", "(.+)")
+
+function M:CHAT_MSG_COMBAT_FACTION_CHANGE(_, msg)
+ local startPos, _, faction = find(msg, increased)
+
+ if not startPos then
+ startPos, _, faction = find(msg, decreased)
+ if not startPos then
+ _, _, faction = find(msg, changed)
+ end
+ end
+
+ if faction and faction ~= GetWatchedFactionInfo() then
+ for factionIndex = 1, GetNumFactions() do
+ local name = GetFactionInfo(factionIndex)
+
+ if name == faction then
+ if not IsFactionInactive(factionIndex) then
+ SetWatchedFactionIndex(factionIndex)
+ end
+
+ break
+ end
+ end
+ end
+end
+
+function M:WatchedFaction()
+ if E.db.enhanced.general.autoRepChange then
+ self:RegisterEvent("CHAT_MSG_COMBAT_FACTION_CHANGE")
+ else
+ self:UnregisterEvent("CHAT_MSG_COMBAT_FACTION_CHANGE")
+ end
+end
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/InterruptTracker.lua b/ElvUI_Enhanced/Modules/Misc/InterruptTracker.lua
new file mode 100644
index 0000000..5a4489a
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/InterruptTracker.lua
@@ -0,0 +1,237 @@
+local E, L, V, P, G = unpack(ElvUI)
+local IT = E:NewModule("Enhanced_InterruptTracker", "AceEvent-3.0")
+
+local ipairs = ipairs
+local unpack = unpack
+local band = bit.band
+local ceil, floor = math.ceil, math.floor
+local twipe = table.wipe
+
+local CreateFrame = CreateFrame
+local GetInstanceInfo = GetInstanceInfo
+local GetSpellInfo = GetSpellInfo
+local GetTime = GetTime
+
+local COMBATLOG_OBJECT_REACTION_HOSTILE = COMBATLOG_OBJECT_REACTION_HOSTILE
+
+local spellList = {
+ [72] = 12, -- Shield Bash
+ [408] = 20, -- Kidney Shot
+ [1766] = 10, -- Kick
+ [2139] = 24, -- Counterspell
+ [6552] = 10, -- Pummel
+ [10890] = 23, -- Psychic Scream
+ [15487] = 45, -- Silence
+ [16979] = 15, -- Feral Charge
+ [19503] = 30, -- Scatter Shot
+ [19647] = 24, -- Spell Lock
+ [23920] = 10, -- Spell Reflection
+ [31224] = 90, -- Cloak of Shadows
+ [34490] = 30, -- Silencing Shot
+ [44572] = 30, -- Deep Freeze
+ [47528] = 10, -- Mind Freeze
+ [48707] = 45, -- Anti-Magic Shell
+ [49916] = 120, -- Strangulate
+ [51514] = 45, -- Hex
+ [57994] = 6, -- Wind Shear
+}
+
+local column = 5 -- max number of interrupt icons show per column
+local numRows = 1
+local iconTotal = 0
+local activeIcons = {}
+
+local function UpdateIconTimer(self, elapsed)
+ if not self.expirationTime then return end
+
+ self.expirationTime = self.expirationTime - elapsed
+
+ if self.expirationTime > 0 then
+ self.timerText:SetText(floor(self.expirationTime + 1))
+ else
+ self.timerText:SetText("")
+ IT:StopIconTimer(self)
+ end
+end
+
+function IT:CountActiveIcons()
+ local total, icon = 0
+ twipe(activeIcons)
+
+ for i = 1, iconTotal do
+ icon = self.icons[i]
+ if icon:IsShown() then
+ total = total + 1
+ activeIcons[total] = icon
+ end
+ end
+
+ return total
+end
+
+function IT:RepositionIcons()
+ local total = self:CountActiveIcons()
+ local icon
+
+ for i, activeIcon in ipairs(activeIcons) do
+ icon = self.icons[i]
+ icon.texture:SetTexture(activeIcon.iconTexture)
+ icon.expirationTime = activeIcon.expirationTime
+ icon.cooldown:SetCooldown(GetTime(), activeIcon.expirationTime)
+ icon:SetScript("OnUpdate", UpdateIconTimer)
+ icon:Show()
+ end
+
+ for i = total + 1, iconTotal do
+ icon = self.icons[i]
+ icon:Hide()
+ icon:SetScript("OnUpdate", nil)
+ end
+end
+
+function IT:StopIconTimer(icon)
+ icon:Hide()
+ icon.expirationTime = nil
+ icon:SetScript("OnUpdate", nil)
+ self:RepositionIcons()
+end
+
+function IT:StartIconTimer(icon, cooldown)
+ icon.expirationTime = cooldown
+ icon.cooldown:SetCooldown(GetTime(), cooldown)
+ icon:SetScript("OnUpdate", UpdateIconTimer)
+ icon:Show()
+end
+
+function IT:UpdateIcon(index, cooldown, texture)
+ local icon = self.icons[index]
+ icon.texture:SetTexture(texture)
+ icon.iconTexture = texture
+ self:StartIconTimer(icon, cooldown)
+end
+
+function IT:CreateIcon(i)
+ self.icons[i] = CreateFrame("Frame", "ElvUI_InterruptIcon"..i, self.header)
+ self.icons[i]:Size(self.db.size)
+ self.icons[i]:SetTemplate()
+
+ self.icons[i].texture = self.icons[i]:CreateTexture("$parentIconTexture", "BORDER")
+ self.icons[i].texture:SetInside()
+ self.icons[i].texture:SetTexCoord(unpack(E.TexCoords))
+
+ self.icons[i].cooldown = CreateFrame("Cooldown", self.icons[i]:GetName().."Cooldown", self.icons[i], "CooldownFrameTemplate")
+ self.icons[i].cooldown:SetInside()
+
+ self.icons[i].timerText = self.icons[i].cooldown:CreateFontString("$parentTimeText", "OVERLAY")
+ local x, y = E:GetXYOffset(self.db.text.position)
+ self.icons[i].timerText:ClearAllPoints()
+ self.icons[i].timerText:Point(self.db.text.position, self.icons[i], self.db.text.position, x + self.db.text.xOffset, y + self.db.text.yOffset)
+ self.icons[i].timerText:FontTemplate(E.LSM:Fetch("font", self.db.text.font), self.db.text.fontSize, self.db.text.fontOutline)
+
+ if i == 1 then
+ self.icons[i]:Point("CENTER", self.header, "CENTER", -2, -6)
+ else
+ local row = ceil(i / column)
+
+ if numRows ~= row then
+ self.icons[i]:Point("RIGHT", self.icons[i-column], "LEFT", -6, 0)
+ numRows = row
+ else
+ self.icons[i]:Point("TOP", self.icons[i-1], "BOTTOM", 0, -6)
+ end
+ end
+
+ iconTotal = i
+end
+
+function IT:Update(cooldown, texture)
+ local found, icon
+
+ for i = 1, iconTotal do
+ icon = self.icons[i]
+
+ if icon and not icon:IsShown() then
+ found = true
+ self:UpdateIcon(i, cooldown, texture)
+ break
+ end
+ end
+
+ if found then return end
+
+ local i = iconTotal + 1
+ self:CreateIcon(i)
+ self:UpdateIcon(i, cooldown, texture)
+end
+
+function IT:UpdateAllIconsTimers()
+ local x, y = E:GetXYOffset(self.db.text.position)
+ local icon
+
+ for i = 1, iconTotal do
+ icon = self.icons[i]
+
+ if icon then
+ icon:Size(self.db.size)
+
+ icon.timerText:ClearAllPoints()
+ icon.timerText:Point(self.db.text.position, icon, self.db.text.position, x + self.db.text.xOffset, y + self.db.text.yOffset)
+ icon.timerText:FontTemplate(E.LSM:Fetch("font", self.db.text.font), self.db.text.fontSize, self.db.text.fontOutline)
+ end
+ end
+end
+
+function IT:StopAllIconsTimers()
+ local icon
+
+ for i = 1, iconTotal do
+ icon = self.icons[i]
+ icon:Hide()
+ icon:SetScript("OnUpdate", nil)
+ end
+end
+
+function IT:COMBAT_LOG_EVENT_UNFILTERED(event, _, subEvent, sourceGUID, _, sourceFlags, _, _, _, spellID)
+ if subEvent == "SPELL_CAST_SUCCESS" and spellList[spellID] then
+ if sourceGUID and (band(sourceFlags, COMBATLOG_OBJECT_REACTION_HOSTILE) == COMBATLOG_OBJECT_REACTION_HOSTILE) then
+ local _, _, texture = GetSpellInfo(spellID)
+ self:Update(spellList[spellID], texture)
+ end
+ end
+end
+
+function IT:PLAYER_ENTERING_WORLD()
+ self:StopAllIconsTimers()
+ self:UpdateState()
+end
+
+function IT:UpdateState()
+ local _, zoneType = GetInstanceInfo()
+ if E.private.enhanced.interruptTracker.everywhere or (E.private.enhanced.interruptTracker.arena and zoneType == "arena") or (E.private.enhanced.interruptTracker.battleground and zoneType == "pvp") then
+ self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+ else
+ self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+ end
+end
+
+function IT:Initialize()
+ if not E.private.enhanced.interruptTracker.enable then return end
+
+ self.db = E.db.enhanced.interruptTracker
+ self.icons = {}
+
+ self.header = CreateFrame("Frame", "ElvUI_InterruptTrackerHeader", UIParent)
+ self.header:Size(50)
+ self.header:Point("CENTER", -300, 50)
+
+ E:CreateMover(self.header, self.header:GetName().."Mover", L["Interrupt Tracker"])
+
+ self:RegisterEvent("PLAYER_ENTERING_WORLD")
+ self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+end
+
+local function InitializeCallback()
+ IT:Initialize()
+end
+
+E:RegisterModule(IT:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/Load_Misc.xml b/ElvUI_Enhanced/Modules/Misc/Load_Misc.xml
new file mode 100644
index 0000000..bebb03b
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/Load_Misc.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/LoseControl.lua b/ElvUI_Enhanced/Modules/Misc/LoseControl.lua
new file mode 100644
index 0000000..d05e36e
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/LoseControl.lua
@@ -0,0 +1,358 @@
+local E, L, V, P, G = unpack(ElvUI)
+local LC = E:NewModule("Enhanced_LoseControl", "AceEvent-3.0")
+
+local GetSpellInfo = GetSpellInfo
+local GetTime = GetTime
+local UnitDebuff = UnitDebuff
+
+local spellNameList = {}
+local spellIDList = {
+ -- Death Knight
+ [47481] = "CC", -- Gnaw (Ghoul)
+ [51209] = "CC", -- Hungering Cold
+ [47476] = "Silence", -- Strangulate
+ [45524] = "Snare", -- Chains of Ice
+ [55666] = "Snare", -- Desecration
+ [58617] = "Snare", -- Glyph of Heart Strike
+ [50436] = "Snare", -- Icy Clutch
+ -- Druid
+ [5211] = "CC", -- Bash
+ [33786] = "CC", -- Cyclone
+ [2637] = "CC", -- Hibernate
+ [22570] = "CC", -- Maim
+ [9005] = "CC", -- Pounce
+ [339] = "Root", -- Entangling Roots
+ [19675] = "Root", -- Feral Charge Effect
+ [58179] = "Snare", -- Infected Wounds
+ [61391] = "Snare", -- Typhoon
+ -- Hunter
+ [60210] = "CC", -- Freezing Arrow Effect
+ [3355] = "CC", -- Freezing Trap Effect
+ [24394] = "CC", -- Intimidation
+ [1513] = "CC", -- Scare Beast
+ [19503] = "CC", -- Scatter Shot
+ [19386] = "CC", -- Wyvern Sting
+ [34490] = "Silence", -- Silencing Shot
+ [53359] = "Disarm", -- Chimera Shot - Scorpid
+ [19306] = "Root", -- Counterattack
+ [19185] = "Root", -- Entrapment
+ [35101] = "Snare", -- Concussive Barrage
+ [5116] = "Snare", -- Concussive Shot
+ [13810] = "Snare", -- Frost Trap Aura
+ [61394] = "Snare", -- Glyph of Freezing Trap
+ [2974] = "Snare", -- Wing Clip
+ -- Hunter Pets
+ [50519] = "CC", -- Sonic Blast
+ [50541] = "Disarm", -- Snatch
+ [54644] = "Snare", -- Froststorm Breath
+ [50245] = "Root", -- Pin
+ [50271] = "Snare", -- Tendon Rip
+ [50518] = "CC", -- Ravage
+ [54706] = "Root", -- Venom Web Spray
+ [4167] = "Root", -- Web
+ -- Mage
+ [44572] = "CC", -- Deep Freeze
+ [31661] = "CC", -- Dragon's Breath
+ [12355] = "CC", -- Impact
+ [118] = "CC", -- Polymorph
+ [18469] = "Silence", -- Silenced - Improved Counterspell
+ [64346] = "Disarm", -- Fiery Payback
+ [33395] = "Root", -- Freeze
+ [122] = "Root", -- Frost Nova
+ [11071] = "Root", -- Frostbite
+ [55080] = "Root", -- Shattered Barrier
+ [11113] = "Snare", -- Blast Wave
+ [6136] = "Snare", -- Chilled
+ [120] = "Snare", -- Cone of Cold
+ [116] = "Snare", -- Frostbolt
+ [47610] = "Snare", -- Frostfire Bolt
+ [31589] = "Snare", -- Slow
+ -- Paladin
+ [853] = "CC", -- Hammer of Justice
+ [2812] = "CC", -- Holy Wrath
+ [20066] = "CC", -- Repentance
+ [20170] = "CC", -- Stun
+ [10326] = "CC", -- Turn Evil
+ [63529] = "Silence", -- Silenced - Shield of the Templar
+ [20184] = "Snare", -- Judgement of Justice
+ -- Priest
+ [605] = "CC", -- Mind Control
+ [64044] = "CC", -- Psychic Horror
+ [8122] = "CC", -- Psychic Scream
+ [9484] = "CC", -- Shackle Undead
+ [15487] = "Silence", -- Silence
+ [64058] = "Disarm", -- Psychic Horror
+ [15407] = "Snare", -- Mind Flay
+ -- Rogue
+ [2094] = "CC", -- Blind
+ [1833] = "CC", -- Cheap Shot
+ [1776] = "CC", -- Gouge
+ [408] = "CC", -- Kidney Shot
+ [6770] = "CC", -- Sap
+ [1330] = "Silence", -- Garrote - Silence
+ [18425] = "Silence", -- Silenced - Improved Kick
+ [51722] = "Disarm", -- Dismantle
+ [31125] = "Snare", -- Blade Twisting
+ [3409] = "Snare", -- Crippling Poison
+ [26679] = "Snare", -- Deadly Throw
+ -- Shaman
+ [39796] = "CC", -- Stoneclaw Stun
+ [51514] = "CC", -- Hex
+ [64695] = "Root", -- Earthgrab
+ [63685] = "Root", -- Freeze
+ [3600] = "Snare", -- Earthbind
+ [8056] = "Snare", -- Frost Shock
+ [8034] = "Snare", -- Frostbrand Attack
+ -- Warlock
+ [710] = "CC", -- Banish
+ [6789] = "CC", -- Death Coil
+ [5782] = "CC", -- Fear
+ [5484] = "CC", -- Howl of Terror
+ [6358] = "CC", -- Seduction
+ [30283] = "CC", -- Shadowfury
+ [24259] = "Silence", -- Spell Lock
+ [18118] = "Snare", -- Aftermath
+ [18223] = "Snare", -- Curse of Exhaustion
+ -- Warrior
+ [7922] = "CC", -- Charge Stun
+ [12809] = "CC", -- Concussion Blow
+ [20253] = "CC", -- Intercept
+ [5246] = "CC", -- Intimidating Shout
+ [12798] = "CC", -- Revenge Stun
+ [46968] = "CC", -- Shockwave
+ [18498] = "Silence", -- Silenced - Gag Order
+ [676] = "Disarm", -- Disarm
+ [58373] = "Root", -- Glyph of Hamstring
+ [23694] = "Root", -- Improved Hamstring
+ [1715] = "Snare", -- Hamstring
+ [12323] = "Snare", -- Piercing Howl
+ -- Other
+ [30217] = "CC", -- Adamantite Grenade
+ [67769] = "CC", -- Cobalt Frag Bomb
+ [30216] = "CC", -- Fel Iron Bomb
+ [20549] = "CC", -- War Stomp
+ [25046] = "Silence", -- Arcane Torrent
+ [39965] = "Root", -- Frost Grenade
+ [55536] = "Root", -- Frostweave Net
+ [13099] = "Root", -- Net-o-Matic
+ [29703] = "Snare", -- Dazed
+ -- PvE
+ [28169] = "PvE", -- Mutating Injection
+ [28059] = "PvE", -- Positive Charge
+ [28084] = "PvE", -- Negative Charge
+ [27819] = "PvE", -- Detonate Mana
+ [63024] = "PvE", -- Gravity Bomb
+ [63018] = "PvE", -- Searing Light
+ [62589] = "PvE", -- Nature's Fury
+ [63276] = "PvE", -- Mark of the Faceless
+ [66770] = "PvE", -- Ferocious Butt
+ [71340] = "PvE", -- Pact of the Darkfallen
+ [70126] = "PvE", -- Frost Beacon
+ [73785] = "PvE", -- Necrotic Plague
+}
+
+local priorities = {
+ ["CC"] = 60,
+ ["PvE"] = 50,
+ ["Silence"] = 40,
+ ["Disarm"] = 30,
+ ["Root"] = 20,
+ ["Snare"] = 10,
+}
+
+function LC:OnUpdate(elapsed)
+ self.timeLeft = self.timeLeft - elapsed
+
+ if self.timeLeft > 10 then
+ self.cooldownTime:SetFormattedText("%d", self.timeLeft)
+ elseif self.timeLeft > 0 then
+ self.cooldownTime:SetFormattedText("%.1f", self.timeLeft)
+ else
+ self:SetScript("OnUpdate", nil)
+ self.timeLeft = nil
+ self.cooldownTime:SetText("0")
+ end
+end
+
+local function CheckPriority(priority, ccPriority, expirationTime, ccExpirationTime)
+ if not ccPriority then
+ return true
+ end
+
+ if priorities[priority] > priorities[ccPriority] then
+ return true
+ elseif priorities[priority] == priorities[ccPriority] and expirationTime > ccExpirationTime then
+ return true
+ end
+end
+
+function LC:UNIT_AURA(event, unit)
+ if unit ~= "player" then return end
+
+ local ccExpirationTime = 0
+ local ccName, ccIcon, ccDuration, ccPriority, wyvernSting
+ local _, name, icon, duration, expirationTime, priority
+
+ for i = 1, 40 do
+ name, _, icon, _, _, duration, expirationTime = UnitDebuff("player", i)
+ if not name then break end
+
+ if name == self.wyvernStingName then
+ wyvernSting = 1
+
+ if not self.wyvernSting then
+ self.wyvernSting = 1
+ elseif expirationTime > self.wyvernStingExpirationTime then
+ self.wyvernSting = 2
+ end
+
+ self.wyvernStingExpirationTime = expirationTime
+
+ if self.wyvernSting == 2 then
+ name = nil
+ end
+ elseif name == self.psychicHorrorName and icon ~= "Interface\\Icons\\Ability_Warrior_Disarm" then
+ name = nil
+ end
+
+ priority = self.db[spellNameList[name]]
+
+ if priority and CheckPriority(priority, ccPriority, expirationTime, ccExpirationTime) then
+ ccName = name
+ ccIcon = icon
+ ccDuration = duration
+ ccExpirationTime = expirationTime
+ ccPriority = priorities[priority]
+ end
+ end
+
+ if self.wyvernSting == 2 and not wyvernSting then
+ self.wyvernSting = nil
+ end
+
+ if ccExpirationTime == 0 then
+ if self.ccExpirationTime ~= 0 then
+ self.ccExpirationTime = 0
+ self.frame.timeLeft = nil
+ self.frame:SetScript("OnUpdate", nil)
+ self.frame:Hide()
+ end
+ elseif ccExpirationTime ~= self.ccExpirationTime then
+ self.ccExpirationTime = ccExpirationTime
+
+ self.frame.icon:SetTexture(ccIcon)
+ self.frame.spellName:SetText(ccName)
+
+ if ccDuration > 0 then
+ self.frame.cooldown:SetCooldown(ccExpirationTime - ccDuration, ccDuration)
+
+ local timeLeft = ccExpirationTime - GetTime()
+
+ if self.frame.timeLeft then
+ self.frame.timeLeft = timeLeft
+ else
+ self.frame.timeLeft = timeLeft
+ self.frame:SetScript("OnUpdate", self.OnUpdate)
+ end
+ end
+
+ self.frame:Show()
+ end
+end
+
+function LC:UpdateSpellNames()
+ local spellName
+ for spellID, ccType in pairs(spellIDList) do
+ spellName = GetSpellInfo(spellID)
+
+ if spellName then
+ spellNameList[spellName] = ccType
+ end
+ end
+end
+
+function LC:ToggleState()
+ if E.private.enhanced.loseControl.enable then
+ if not self.initialized then
+ self:Initialize()
+ return
+ end
+
+ E:EnableMover(self.frame.mover:GetName())
+ self:RegisterEvent("UNIT_AURA")
+ else
+ self.ccExpirationTime = 0
+ self.frame.timeLeft = nil
+ self.frame:SetScript("OnUpdate", nil)
+ self.frame:Hide()
+
+ E:DisableMover(self.frame.mover:GetName())
+ self:UnregisterEvent("UNIT_AURA")
+ end
+end
+
+function LC:UpdateSettings()
+ if not self.db then return end
+
+ self.frame:Size(self.db.iconSize)
+
+ if self.db.compactMode then
+ self.frame.cooldownTime:FontTemplate(E.media.normFont, E:Round(self.db.iconSize / 3), "OUTLINE")
+ self.frame.cooldownTime:ClearAllPoints()
+ self.frame.cooldownTime:SetPoint("CENTER")
+ self.frame.spellName:Hide()
+ self.frame.secondsText:Hide()
+ else
+ self.frame.cooldownTime:FontTemplate(E.media.normFont, 20, "OUTLINE")
+ self.frame.cooldownTime:SetPoint("BOTTOM", 0, -50)
+ self.frame.spellName:Show()
+ self.frame.secondsText:Show()
+ end
+end
+
+function LC:Initialize()
+ if not E.private.enhanced.loseControl.enable then return end
+
+ self.db = E.db.enhanced.loseControl
+
+ self.frame = CreateFrame("Frame", "ElvUI_LoseControl", UIParent)
+ self.frame:SetPoint("CENTER")
+ self.frame:SetTemplate()
+ self.frame:Hide()
+
+ self.frame.icon = self.frame:CreateTexture(nil, "ARTWORK")
+ self.frame.icon:SetInside()
+ self.frame.icon:SetTexCoord(unpack(E.TexCoords))
+
+ self.frame.cooldown = CreateFrame("Cooldown", "$parent_Cooldown", self.frame, "CooldownFrameTemplate")
+ self.frame.cooldown:SetInside()
+
+ self.frame.spellName = self.frame:CreateFontString(nil, "OVERLAY")
+ self.frame.spellName:FontTemplate(E.media.normFont, 20, "OUTLINE")
+ self.frame.spellName:SetPoint("BOTTOM", 0, -25)
+
+ self.frame.cooldownTime = self.frame.cooldown:CreateFontString(nil, "OVERLAY")
+
+ self.frame.secondsText = self.frame.cooldown:CreateFontString(nil, "OVERLAY")
+ self.frame.secondsText:FontTemplate(E.media.normFont, 20, "OUTLINE")
+ self.frame.secondsText:SetPoint("BOTTOM", 0, -75)
+ self.frame.secondsText:SetText(L["seconds"])
+
+ self:UpdateSettings()
+
+ E:CreateMover(self.frame, "LossControlMover", L["Loss Control"], nil, nil, nil, "ALL,ARENA")
+
+ self:UpdateSpellNames()
+ self.wyvernStingName = GetSpellInfo(19386)
+ self.psychicHorrorName = GetSpellInfo(64058)
+
+ self:RegisterEvent("UNIT_AURA")
+
+ self.initialized = true
+end
+
+local function InitializeCallback()
+ LC:Initialize()
+end
+
+E:RegisterModule(LC:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/MerchantBuyStack.lua b/ElvUI_Enhanced/Modules/Misc/MerchantBuyStack.lua
new file mode 100644
index 0000000..3f92d22
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/MerchantBuyStack.lua
@@ -0,0 +1,54 @@
+local E, L, V, P, G = unpack(ElvUI)
+local M = E:GetModule("Enhanced_Misc")
+
+local select = select
+local ceil = math.ceil
+
+local BuyMerchantItem = BuyMerchantItem
+local GetItemInfo = GetItemInfo
+local GetMerchantItemInfo = GetMerchantItemInfo
+local GetMerchantItemLink = GetMerchantItemLink
+local GetMerchantItemMaxStack = GetMerchantItemMaxStack
+local IsAltKeyDown = IsAltKeyDown
+
+function M:MerchantItemButton_OnModifiedClick(button)
+ if IsAltKeyDown() then
+ local id = button:GetID()
+ local maxStack = select(8, GetItemInfo(GetMerchantItemLink(id)))
+
+ if maxStack and maxStack > 1 then
+ local stack = GetMerchantItemMaxStack(id)
+
+ if stack > 1 then
+ BuyMerchantItem(id, stack)
+ return
+ else
+ local _, _, _, quantity, numAvailable = GetMerchantItemInfo(id)
+ quantity = ceil(maxStack / quantity)
+
+ if numAvailable > -1 and numAvailable < quantity then
+ quantity = numAvailable
+ end
+
+ if quantity > 1 then
+ BuyMerchantItem(id, quantity)
+ return
+ end
+ end
+ end
+
+ BuyMerchantItem(id)
+ end
+end
+
+function M:BuyStackToggle()
+ if E.db.enhanced.general.altBuyMaxStack then
+ if not self:IsHooked("MerchantItemButton_OnModifiedClick") then
+ self:SecureHook("MerchantItemButton_OnModifiedClick")
+ end
+ else
+ if self:IsHooked("MerchantItemButton_OnModifiedClick") then
+ self:Unhook("MerchantItemButton_OnModifiedClick")
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/Misc.lua b/ElvUI_Enhanced/Modules/Misc/Misc.lua
new file mode 100644
index 0000000..4d75c09
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/Misc.lua
@@ -0,0 +1,72 @@
+local E, L, V, P, G = unpack(ElvUI)
+local M = E:NewModule("Enhanced_Misc", "AceHook-3.0", "AceEvent-3.0")
+
+local CancelDuel = CancelDuel
+local GetSpellInfo = GetSpellInfo
+local IsInInstance = IsInInstance
+local RepopMe = RepopMe
+local UnitBuff = UnitBuff
+
+local soulstone
+function M:PLAYER_DEAD()
+ local inInstance, instanceType = IsInInstance()
+
+ if inInstance and instanceType == "pvp" then
+ if not soulstone then
+ soulstone = GetSpellInfo(20707)
+ end
+
+ if E.myclass ~= "SHAMAN" and not (soulstone and UnitBuff("player", soulstone)) then
+ RepopMe()
+ end
+ end
+end
+
+function M:AutoRelease()
+ if E.db.enhanced.general.pvpAutoRelease then
+ self:RegisterEvent("PLAYER_DEAD")
+ else
+ self:UnregisterEvent("PLAYER_DEAD")
+ end
+end
+
+function M:DUEL_REQUESTED(_, name)
+ StaticPopup_Hide("DUEL_REQUESTED")
+ CancelDuel()
+ E:Print(L["Declined duel request from "]..name)
+end
+
+function M:DeclineDuel()
+ if E.db.enhanced.general.declineduel then
+ self:RegisterEvent("DUEL_REQUESTED")
+ else
+ self:UnregisterEvent("DUEL_REQUESTED")
+ end
+end
+
+function M:HideZone()
+ if E.db.enhanced.general.hideZoneText then
+ ZoneTextFrame:UnregisterAllEvents()
+ else
+ ZoneTextFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
+ ZoneTextFrame:RegisterEvent("ZONE_CHANGED_INDOORS")
+ ZoneTextFrame:RegisterEvent("ZONE_CHANGED")
+ end
+end
+
+function M:Initialize()
+ self:AutoRelease()
+ self:DeclineDuel()
+ self:HideZone()
+ self:ToggleQuestReward()
+ self:WatchedFaction()
+ self:LoadMoverTransparancy()
+ self:QuestLevelToggle()
+ self:BuyStackToggle()
+end
+
+local function InitializeCallback()
+ M:Initialize()
+end
+
+E:RegisterModule(M:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/Movers.lua b/ElvUI_Enhanced/Modules/Misc/Movers.lua
new file mode 100644
index 0000000..1992c85
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/Movers.lua
@@ -0,0 +1,27 @@
+local E, L, V, P, G = unpack(ElvUI)
+local M = E:GetModule("Enhanced_Misc")
+
+local _G = _G
+local pairs = pairs
+
+function M:UpdateMoverTransparancy()
+ local mover
+
+ for name in pairs(E.CreatedMovers) do
+ mover = _G[name]
+
+ if mover then
+ mover:SetAlpha(E.db.enhanced.general.moverTransparancy)
+ end
+ end
+end
+
+function M:LoadMoverTransparancy()
+ hooksecurefunc(E, "CreateMover", function(_, parent)
+ if parent.mover then
+ parent.mover:SetAlpha(E.db.enhanced.general.moverTransparancy)
+ end
+ end)
+
+ self:UpdateMoverTransparancy()
+end
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/QuestLevel.lua b/ElvUI_Enhanced/Modules/Misc/QuestLevel.lua
new file mode 100644
index 0000000..46baba7
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/QuestLevel.lua
@@ -0,0 +1,58 @@
+local E, L, V, P, G = unpack(ElvUI)
+local M = E:GetModule("Enhanced_Misc")
+
+local ipairs = ipairs
+
+local GetNumQuestLogEntries = GetNumQuestLogEntries
+local GetQuestLogTitle = GetQuestLogTitle
+local HybridScrollFrame_GetOffset = HybridScrollFrame_GetOffset
+local QuestLogTitleButton_Resize = QuestLogTitleButton_Resize
+
+local function ShowLevel()
+ local scrollOffset = HybridScrollFrame_GetOffset(QuestLogScrollFrame)
+ local numEntries = GetNumQuestLogEntries()
+ local _, questIndex, title, level, isHeader
+
+ for i, questLogTitle in ipairs(QuestLogScrollFrame.buttons) do
+ questIndex = i + scrollOffset
+
+ if questIndex <= numEntries then
+ title, level, _, _, isHeader = GetQuestLogTitle(questIndex)
+
+ if not isHeader then
+ if questLogTitle.groupMates:IsShown() then
+ questLogTitle.groupMates:Hide()
+ questLogTitle:SetFormattedText("|cff4F8CC9%s|r[%d] %s", questLogTitle.groupMates:GetText() or "", level, title)
+ else
+ questLogTitle:SetFormattedText("[%d] %s", level, title)
+ end
+
+ QuestLogTitleButton_Resize(questLogTitle)
+ end
+ end
+ end
+end
+
+function M:QuestLevelToggle()
+ if IsAddOnLoaded("QuestGuru") then return end
+
+ local enabled = E.db.enhanced.general.showQuestLevel
+
+ for _, questLogTitle in ipairs(QuestLogScrollFrame.buttons) do
+ if enabled then
+ questLogTitle.check:Point("LEFT", 5, 0)
+ else
+ questLogTitle.check:Point("LEFT", questLogTitle.normalText, "RIGHT", 2, 0)
+ end
+ end
+
+ if enabled then
+ self:SecureHook("QuestLog_Update", ShowLevel)
+ self:SecureHookScript(QuestLogScrollFrameScrollBar, "OnValueChanged", ShowLevel)
+ else
+ self:Unhook("QuestLog_Update")
+ self:Unhook(QuestLogScrollFrameScrollBar, "OnValueChanged")
+ end
+
+ QuestLog_Update()
+end
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/QuestReward.lua b/ElvUI_Enhanced/Modules/Misc/QuestReward.lua
new file mode 100644
index 0000000..4b1e2f5
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/QuestReward.lua
@@ -0,0 +1,58 @@
+local E, L, V, P, G = unpack(ElvUI)
+local M = E:GetModule("Enhanced_Misc")
+
+local _G = _G
+local select = select
+
+local GetItemInfo = GetItemInfo
+local GetNumQuestChoices = GetNumQuestChoices
+local GetQuestItemLink = GetQuestItemLink
+
+local function SelectQuestReward(id)
+ local button = _G["QuestInfoItem"..id]
+
+ if button.type == "choice" then
+ if E.private.skins.blizzard.enable and E.private.skins.blizzard.quest then
+ _G[button:GetName()]:SetBackdropBorderColor(1, 0.80, 0.10)
+ _G[button:GetName()].backdrop:SetBackdropBorderColor(1, 0.80, 0.10)
+ _G[button:GetName().."Name"]:SetTextColor(1, 0.80, 0.10)
+ else
+ QuestInfoItemHighlight:ClearAllPoints()
+ QuestInfoItemHighlight:SetAllPoints(button)
+ QuestInfoItemHighlight:Show()
+ end
+
+ QuestInfoFrame.itemChoice = button:GetID()
+ end
+end
+
+function M:QUEST_COMPLETE()
+ local numItems = GetNumQuestChoices()
+ if numItems <= 0 then return end
+
+ local link, sellPrice
+ local choiceID, maxPrice = 1, 0
+
+ for i = 1, numItems do
+ link = GetQuestItemLink("choice", i)
+
+ if link then
+ sellPrice = select(11, GetItemInfo(link))
+
+ if sellPrice and sellPrice > maxPrice then
+ maxPrice = sellPrice
+ choiceID = i
+ end
+ end
+ end
+
+ SelectQuestReward(choiceID)
+end
+
+function M:ToggleQuestReward()
+ if E.private.general.selectQuestReward then
+ self:RegisterEvent("QUEST_COMPLETE")
+ else
+ self:UnregisterEvent("QUEST_COMPLETE")
+ end
+end
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/TrainAllSkills.lua b/ElvUI_Enhanced/Modules/Misc/TrainAllSkills.lua
new file mode 100644
index 0000000..657d481
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/TrainAllSkills.lua
@@ -0,0 +1,200 @@
+local E, L, V, P, G = unpack(ElvUI)
+local TA = E:NewModule("Enhanced_TrainAll", "AceHook-3.0", "AceEvent-3.0")
+
+local select = select
+local format = string.format
+
+local BuyTrainerService = BuyTrainerService
+local GetMoney = GetMoney
+local GetNumTrainerServices = GetNumTrainerServices
+local GetTrainerServiceCost = GetTrainerServiceCost
+local GetTrainerServiceInfo = GetTrainerServiceInfo
+
+local function BetterSafeThanSorry_OnUpdate(self, elapsed)
+ self.delay = self.delay - elapsed
+
+ if self.delay <= 0 then
+ TA:ResetScript()
+ end
+end
+
+function TA:TrainAllSkills()
+ self.locked = true
+ self.button:Disable()
+
+ local j, cost = 0
+ local money = GetMoney()
+
+ for i = 1, GetNumTrainerServices() do
+ if select(3, GetTrainerServiceInfo(i)) == "available" then
+ j = j + 1
+ cost = GetTrainerServiceCost(i)
+ if money >= cost then
+ money = money - cost
+ BuyTrainerService(i)
+ else
+ self:ResetScript()
+ return
+ end
+ end
+ end
+
+ if j > 0 then
+ self.skillsToLearn = j
+ self.skillsLearned = 0
+
+ self:RegisterEvent("TRAINER_UPDATE")
+
+ self.button.delay = 1
+ self.button:SetScript("OnUpdate", BetterSafeThanSorry_OnUpdate)
+ else
+ self:ResetScript()
+ end
+end
+
+function TA:TRAINER_UPDATE()
+ self.skillsLearned = self.skillsLearned + 1
+
+ if self.skillsLearned >= self.skillsToLearn then
+ self:ResetScript()
+ self:TrainAllSkills()
+ else
+ self.button.delay = 1
+ end
+end
+
+function TA:ResetScript()
+ self.button:SetScript("OnUpdate", nil)
+ self:UnregisterEvent("TRAINER_UPDATE")
+
+ self.skillsLearned = nil
+ self.skillsToLearn = nil
+ self.button.delay = nil
+ self.locked = nil
+end
+
+function TA:ButtonCreate()
+ self.button = CreateFrame("Button", "ElvUI_TrainAllButton", ClassTrainerFrame, "UIPanelButtonTemplate")
+ self.button:Size(80, 22)
+ self.button:SetFormattedText("%s %s", TRAIN, ALL)
+
+ if E.private.skins.blizzard.enable and E.private.skins.blizzard.trainer then
+ self.button:Point("RIGHT", ClassTrainerTrainButton, "LEFT", -3, 0)
+ E:GetModule("Skins"):HandleButton(self.button)
+ else
+ self.button:Point("RIGHT", ClassTrainerTrainButton, "LEFT")
+ end
+
+ self.button:SetScript("OnClick", function() TA:TrainAllSkills() end)
+
+ self.button:HookScript("OnEnter", function()
+ local cost = 0
+ for i = 1, GetNumTrainerServices() do
+ if select(3, GetTrainerServiceInfo(i)) == "available" then
+ cost = cost + GetTrainerServiceCost(i)
+ end
+ end
+
+ GameTooltip:SetOwner(self.button,"ANCHOR_TOPLEFT", 0, 5)
+ GameTooltip:SetText(format("|cffffffff%s|r %s", TABARDVENDORCOST, E:FormatMoney(cost, E.db.datatexts.goldFormat or "BLIZZARD", not E.db.datatexts.goldCoins)))
+ end)
+
+ self.button:HookScript("OnLeave", function()
+ GameTooltip:Hide()
+ end)
+end
+
+function TA:ButtonUpdate()
+ if self.locked then return end
+
+ for i = 1, GetNumTrainerServices() do
+ if select(3, GetTrainerServiceInfo(i)) == "available" then
+ self.button:Enable()
+ return
+ end
+ end
+
+ self.button:Disable()
+end
+
+function TA:ButtonPosition(disable)
+ if disable then
+ ClassTrainerTrainButton:Point("CENTER", ClassTrainerFrame, "TOPLEFT", 221, -417)
+
+ ClassTrainerCancelButton.Show = nil
+ ClassTrainerCancelButton:Show()
+ else
+ ClassTrainerTrainButton:Point("CENTER", ClassTrainerFrame, "TOPLEFT", 304, -417)
+
+ ClassTrainerCancelButton.Show = E.noop
+ ClassTrainerCancelButton:Hide()
+ end
+end
+
+function TA:ADDON_LOADED(_, addon)
+ if self.blockCallback or addon ~= "Blizzard_TrainerUI" then return end
+
+ self:ButtonCreate()
+ self:ButtonPosition()
+
+ self:SecureHook("ClassTrainerFrame_Update", "ButtonUpdate")
+ self:UnregisterEvent("ADDON_LOADED")
+end
+
+function TA:ToggleState()
+ if E.db.enhanced.general.trainAllSkills then
+ if not self.button then
+ if IsAddOnLoaded("Blizzard_TrainerUI") then
+ self.blockCallback = nil
+ self:ADDON_LOADED(nil, "Blizzard_TrainerUI")
+ elseif E.private.skins.blizzard.enable and E.private.skins.blizzard.trainer then
+ if not self.skinCallback then
+ E:GetModule("Skins"):AddCallbackForAddon("Blizzard_TrainerUI", "Enhanced_Blizzard_TrainerUI_TrainAll", function()
+ self:ADDON_LOADED(nil, "Blizzard_TrainerUI")
+ end)
+
+ self.skinCallback = true
+ else
+ self.blockCallback = nil
+ end
+ else
+ self:RegisterEvent("ADDON_LOADED")
+ end
+ else
+ self.button:Show()
+ self:ButtonPosition()
+
+ if not self:IsHooked("ClassTrainerFrame_Update") then
+ self:SecureHook("ClassTrainerFrame_Update", "ButtonUpdate")
+ end
+ end
+ else
+ if not self.button then
+ self:UnregisterEvent("ADDON_LOADED")
+
+ if self.skinCallback then
+ self.blockCallback = true
+ end
+ else
+ self.button:Hide()
+ self:UnhookAll()
+ self:ButtonPosition(true)
+
+ if self.locked then
+ self:ResetScript()
+ end
+ end
+ end
+end
+
+function TA:Initialize()
+ if not E.db.enhanced.general.trainAllSkills then return end
+
+ self:ToggleState()
+end
+
+local function InitializeCallback()
+ TA:Initialize()
+end
+
+E:RegisterModule(TA:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Misc/UndressButton.lua b/ElvUI_Enhanced/Modules/Misc/UndressButton.lua
new file mode 100644
index 0000000..6672fe6
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Misc/UndressButton.lua
@@ -0,0 +1,86 @@
+local E, L, V, P, G = unpack(ElvUI)
+local UB = E:NewModule("Enhanced_UndressButtons", "AceEvent-3.0")
+local S = E:GetModule("Skins")
+
+function UB:CreateUndressButton(auction)
+ if not auction then
+ self.dressUpButton = CreateFrame("Button", "DressUpFrame_UndressButton", DressUpFrame, "UIPanelButtonTemplate")
+ self.dressUpButton:Size(80, 22)
+ self.dressUpButton:SetText(L["Undress"])
+ self.dressUpButton:SetScript("OnClick", function(self)
+ self.model:Undress()
+ PlaySound("gsTitleOptionOK")
+ end)
+ self.dressUpButton.model = DressUpModel
+
+ if not (E.private.skins.blizzard.enable and E.private.skins.blizzard.dressingroom) then
+ self.dressUpButton:Point("RIGHT", DressUpFrameResetButton, "LEFT", 2, 0)
+ else
+ S:HandleButton(self.dressUpButton)
+ self.dressUpButton:Point("RIGHT", DressUpFrameResetButton, "LEFT", -3, 0)
+ end
+ else
+ self.auctionDressUpButton = CreateFrame("Button", "AuctionDressUpFrame_UndressButton", AuctionDressUpFrame, "UIPanelButtonTemplate")
+ self.auctionDressUpButton:Size(80, 22)
+ self.auctionDressUpButton:SetFrameStrata("HIGH")
+ self.auctionDressUpButton:SetText(L["Undress"])
+ self.auctionDressUpButton:SetScript("OnClick", function(self)
+ self.model:Undress()
+ PlaySound("gsTitleOptionOK")
+ end)
+ self.auctionDressUpButton.model = AuctionDressUpModel
+
+ if not (E.private.skins.blizzard.enable and E.private.skins.blizzard.dressingroom) then
+ self.auctionDressUpButton:Point("BOTTOM", AuctionDressUpFrameResetButton, "BOTTOM", 0, -25)
+ else
+ S:HandleButton(self.auctionDressUpButton)
+ self.auctionDressUpButton:Point("RIGHT", AuctionDressUpFrameResetButton, "LEFT", -3, 0)
+ AuctionDressUpFrameResetButton:Point("BOTTOM", 42, 33)
+ end
+ end
+end
+
+function UB:ADDON_LOADED(_, addon)
+ if addon ~= "Blizzard_AuctionUI" then return end
+
+ self:CreateUndressButton(true)
+
+ self:UnregisterEvent("ADDON_LOADED")
+end
+
+function UB:ToggleState()
+ if E.db.enhanced.general.undressButton then
+ if not self.dressUpButton then
+ self:CreateUndressButton()
+ end
+ self.dressUpButton:Show()
+
+ if self.auctionDressUpButton then
+ self.auctionDressUpButton:Show()
+ else
+ self:RegisterEvent("ADDON_LOADED")
+ end
+ else
+ if self.dressUpButton then
+ self.dressUpButton:Hide()
+ end
+
+ if self.auctionDressUpButton then
+ self.auctionDressUpButton:Hide()
+ else
+ self:UnregisterEvent("ADDON_LOADED")
+ end
+ end
+end
+
+function UB:Initialize()
+ if not E.db.enhanced.general.undressButton then return end
+
+ self:ToggleState()
+end
+
+local function InitializeCallback()
+ UB:Initialize()
+end
+
+E:RegisterModule(UB:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Nameplates/Load_Nameplates.xml b/ElvUI_Enhanced/Modules/Nameplates/Load_Nameplates.xml
new file mode 100644
index 0000000..b5fdaed
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Nameplates/Load_Nameplates.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Nameplates/Nameplates.lua b/ElvUI_Enhanced/Modules/Nameplates/Nameplates.lua
new file mode 100644
index 0000000..c55b4eb
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Nameplates/Nameplates.lua
@@ -0,0 +1,572 @@
+local E, L, V, P, G = unpack(ElvUI)
+local ENP = E:NewModule("Enhanced_NamePlates", "AceHook-3.0", "AceEvent-3.0")
+local NP = E:GetModule("NamePlates")
+local M = E:GetModule("Misc")
+local CH = E:GetModule("Chat")
+
+local _G = _G
+local ipairs, next, pairs = ipairs, next, pairs
+local sub, gsub, floor = string.sub, string.gsub, math.floor
+local match, gmatch, format, lower = string.match, string.gmatch, string.format, string.lower
+local tinsert, tremove = table.insert, table.remove
+
+local GetGuildInfo = GetGuildInfo
+local IsInGuild = IsInGuild
+local IsInInstance = IsInInstance
+local IsResting = IsResting
+local UnitClass = UnitClass
+local UnitInParty = UnitInParty
+local UnitInRaid = UnitInRaid
+local UnitIsPlayer = UnitIsPlayer
+local UnitName = UnitName
+local UnitPlayerControlled = UnitPlayerControlled
+local UnitReaction = UnitReaction
+local UNKNOWN = UNKNOWN
+
+local classMap = {}
+local guildMap = {}
+local npcTitleMap = {}
+
+local function UpdateNameplateByName(name)
+ for frame in pairs(NP.VisiblePlates) do
+ if frame.UnitName == name then
+ NP.OnShow(frame:GetParent(), nil, true)
+ end
+ end
+end
+
+function ENP:UPDATE_MOUSEOVER_UNIT()
+ if UnitIsPlayer("mouseover") and UnitReaction("mouseover", "player") ~= 2 then
+ local name, realm = UnitName("mouseover")
+ if realm or not name or name == UNKNOWN then return end
+
+ if E.db.enhanced.nameplates.classCache then
+ local _, class = UnitClass("mouseover")
+ class = classMap[class]
+
+ if EnhancedDB.UnitClass[name] ~= class then
+ EnhancedDB.UnitClass[name] = class
+ end
+ end
+
+ if E.db.enhanced.nameplates.titleCache then
+ local guildName = GetGuildInfo("mouseover")
+ if not guildName then
+ if EnhancedDB.UnitTitle[name] then
+ EnhancedDB.UnitTitle[name] = nil
+ UpdateNameplateByName(name)
+ end
+ return
+ end
+
+ if not guildMap[guildName] then
+ tinsert(EnhancedDB.GuildList, guildName)
+ guildMap[guildName] = #EnhancedDB.GuildList
+ end
+
+ if EnhancedDB.UnitTitle[name] ~= guildMap[guildName] then
+ EnhancedDB.UnitTitle[name] = guildMap[guildName]
+ UpdateNameplateByName(name)
+ end
+ end
+ else
+ self.scanner:ClearLines()
+ self.scanner:SetUnit("mouseover")
+
+ local name = _G["Enhanced_ScanningTooltipTextLeft1"]:GetText()
+ if not name then return end
+ local description = _G["Enhanced_ScanningTooltipTextLeft2"]:GetText()
+ if not description then return end
+
+ if match(description, UNIT_LEVEL_TEMPLATE) then return end
+
+ name = gsub(gsub((name), "|c........", "" ), "|r", "")
+ if name ~= UnitName("mouseover") then return end
+ if UnitPlayerControlled("mouseover") then return end
+
+ if not npcTitleMap[description] then
+ tinsert(EnhancedDB.NPCList, description)
+ npcTitleMap[description] = #EnhancedDB.NPCList
+ end
+
+ if EnhancedDB.UnitTitle[name] ~= npcTitleMap[description] then
+ EnhancedDB.UnitTitle[name] = npcTitleMap[description]
+ UpdateNameplateByName(name)
+ end
+ end
+end
+
+-- Class Cache
+local grenColorToClass = {}
+for class, color in pairs(RAID_CLASS_COLORS) do
+ grenColorToClass[color.g] = class
+end
+
+local function UnitClassHook(self, frame, unitType)
+ if unitType == "FRIENDLY_PLAYER" then
+ local unitName = frame.UnitName
+ local unit = self[unitType][unitName]
+ if unit then
+ local _, class = UnitClass(unit)
+ if class then
+ return class
+ end
+ elseif EnhancedDB.UnitClass[unitName] then
+ return CLASS_SORT_ORDER[EnhancedDB.UnitClass[unitName]]
+ else
+ return NP:GetUnitClassByGUID(frame)
+ end
+ elseif unitType == "ENEMY_PLAYER" then
+ local _, g = frame.oldHealthBar:GetStatusBarColor()
+ return grenColorToClass[floor(g*100 + 0.5) / 100]
+ end
+end
+
+function ENP:ClassCache()
+ if E.db.enhanced.nameplates.classCache then
+ if not self:IsHooked(NP, "UnitClass") then
+ self:RawHook(NP, "UnitClass", UnitClassHook)
+ end
+ else
+ if self:IsHooked(NP, "UnitClass") then
+ self:Unhook(NP, "UnitClass")
+ end
+ end
+end
+
+-- Title Cache
+local separatorMap = {
+ [" "] = "%s",
+ ["<"] = "<%s>",
+ ["("] = "(%s)",
+ ["["] = "[%s]",
+ ["{"] = "{%s}"
+}
+
+local function Update_NameHook(self, frame)
+ if not E.db.enhanced.nameplates.titleCache then return end
+
+ if frame.Health:IsShown() then
+ if frame.Title then
+ frame.Title:SetText()
+ frame.Title:Hide()
+ end
+ return
+ end
+
+ local guildName = EnhancedDB.GuildList[EnhancedDB.UnitTitle[frame.UnitName]]
+ if frame.UnitType == "FRIENDLY_PLAYER" and guildName then
+ local db = E.db.enhanced.nameplates.guild
+
+ local shown
+ if IsResting() then
+ shown = db.visibility.city
+ else
+ local _, instanceType = IsInInstance()
+ if instanceType == "pvp" then
+ shown = db.visibility.pvp
+ elseif instanceType == "arena" then
+ shown = db.visibility.arena
+ elseif instanceType == "party" then
+ shown = db.visibility.party
+ elseif instanceType == "raid" then
+ shown = db.visibility.raid
+ else
+ shown = true
+ end
+ end
+
+ if shown then
+ if not frame.Title then
+ frame.Title = frame:CreateFontString(nil, "OVERLAY")
+ frame.Title:SetWordWrap(false)
+ end
+
+ frame.Title:SetFont(E.LSM:Fetch("font", db.font), db.fontSize, db.fontOutline)
+
+ local color
+ if UnitInRaid(frame.UnitName) then
+ color = db.colors.raid
+ elseif UnitInParty(frame.UnitName) then
+ color = db.colors.party
+ elseif IsInGuild and GetGuildInfo("player") == guildName then
+ color = db.colors.guild
+ else
+ color = db.colors.none
+ end
+
+ frame.Title:SetTextColor(color.r, color.g, color.b)
+ frame.Title:SetPoint("TOP", frame.Name, "BOTTOM")
+ frame.Title:SetFormattedText(separatorMap[db.separator], guildName)
+ frame.Title:Show()
+ elseif frame.Title then
+ frame.Title:Hide()
+ end
+ elseif (frame.UnitType == "FRIENDLY_NPC" or frame.UnitType == "ENEMY_NPC") and EnhancedDB.NPCList[EnhancedDB.UnitTitle[frame.UnitName]] then
+ if not frame.Title then
+ frame.Title = frame:CreateFontString(nil, "OVERLAY")
+ frame.Title:SetWordWrap(false)
+ end
+
+ local db = E.db.enhanced.nameplates.npc
+ frame.Title:SetFont(E.LSM:Fetch("font", db.font), db.fontSize, db.fontOutline)
+
+ if E.db.enhanced.nameplates.npc.reactionColor then
+ local db = self.db.colors
+ if frame.UnitReaction == 5 then -- friendly
+ r, g, b = db.reactions.good.r, db.reactions.good.g, db.reactions.good.b
+ elseif frame.UnitReaction == 1 or frame.UnitReaction == 2 then -- hostile
+ r, g, b = db.reactions.bad.r, db.reactions.bad.g, db.reactions.bad.b
+ elseif frame.UnitReaction == 4 then -- neutral
+ r, g, b = db.reactions.neutral.r, db.reactions.neutral.g, db.reactions.neutral.b
+ else
+ r, g, b = 1, 1, 1
+ end
+ frame.Title:SetTextColor(r, g, b)
+ else
+ frame.Title:SetTextColor(db.color.r, db.color.g, db.color.b)
+ end
+
+ frame.Title:SetPoint("TOP", frame.Name, "BOTTOM")
+ frame.Title:SetFormattedText(separatorMap[db.separator], EnhancedDB.NPCList[EnhancedDB.UnitTitle[frame.UnitName]])
+ frame.Title:Show()
+ elseif frame.Title then
+ frame.Title:SetText("")
+ end
+end
+
+function ENP:TitleCache()
+ if E.db.enhanced.nameplates.titleCache then
+ if not self:IsHooked(NP, "Update_Name") then
+ self:Hook(NP, "Update_Name", Update_NameHook)
+ end
+ else
+ if self:IsHooked(NP, "Update_Name") then
+ self:Unhook(NP, "Update_Name")
+ end
+ end
+end
+
+-- Chat Bubbles
+local events = {
+ "CHAT_MSG_GUILD",
+ "CHAT_MSG_OFFICER",
+ "CHAT_MSG_PARTY",
+ "CHAT_MSG_PARTY_LEADER",
+ "CHAT_MSG_RAID",
+ "CHAT_MSG_RAID_LEADER",
+ "CHAT_MSG_RAID_WARNING",
+ "CHAT_MSG_BATTLEGROUND",
+ "CHAT_MSG_BATTLEGROUND_LEADER",
+ "CHAT_MSG_CHANNEL",
+ "CHAT_MSG_SAY",
+ "CHAT_MSG_YELL",
+ "CHAT_MSG_MONSTER_SAY",
+ "CHAT_MSG_MONSTER_YELL"
+}
+
+local bubbleList = {}
+local delayFrame = CreateFrame("Frame")
+delayFrame:Hide()
+delayFrame:SetScript("OnUpdate", function(self, elapsed)
+ local i, frame = 1
+
+ while bubbleList[i] do
+ frame = bubbleList[i]
+ frame.delay = frame.delay - elapsed
+
+ if frame.delay <= 0 then
+ frame.delay = 0
+ E:UIFrameFadeOut(frame, .2, frame:GetAlpha(), 0)
+ tremove(bubbleList, i)
+ else
+ i = i + 1
+ end
+ end
+
+ if #bubbleList == 0 then
+ self:Hide()
+ end
+end)
+
+local function SetBubbleDelay(frame, delay)
+ local found
+
+ if #bubbleList > 0 then
+ for _, v in ipairs(bubbleList) do
+ if v == frame then
+ v.delay = delay
+ found = true
+ break
+ end
+ end
+ end
+
+ if not found then
+ frame.delay = delay
+ tinsert(bubbleList, frame)
+ delayFrame:Show()
+ end
+end
+
+local inactiveBubbles = {}
+
+local function ReleaseBubble(frame)
+ inactiveBubbles[#inactiveBubbles + 1] = frame
+ frame.parent.bubbleFrame = nil
+ frame:Hide()
+end
+
+local function FadeClosure(frame)
+ if frame.fadeInfo.mode == "OUT" then
+ ReleaseBubble(frame)
+ end
+end
+
+local function CreateBubble()
+ local frame = CreateFrame("Frame")
+ frame:SetFrameStrata("BACKGROUND")
+ frame:Hide()
+ frame.text = frame:CreateFontString()
+ frame.text:SetJustifyH("CENTER")
+ frame.text:SetJustifyV("MIDDLE")
+ frame.text:SetWordWrap(true)
+ frame.text:SetNonSpaceWrap(true)
+ frame:SetPoint("TOPLEFT", frame.text, -15, 15)
+ frame:SetPoint("BOTTOMRIGHT", frame.text, 15, -15)
+ M:SkinBubble(frame)
+
+ frame.delay = 0
+ frame.FadeObject = {
+ finishedFuncKeep = true,
+ finishedArg1 = frame,
+ finishedFunc = FadeClosure
+ }
+
+ return frame
+end
+
+local function AcquireBubble()
+ local numInactiveObjects = #inactiveBubbles
+ if numInactiveObjects > 0 then
+ local frame = inactiveBubbles[numInactiveObjects]
+ inactiveBubbles[numInactiveObjects] = nil
+ return frame
+ end
+
+ return CreateBubble()
+end
+
+function ENP:AddBubbleMessage(frame, msg, author, guid)
+ if E.private.general.chatBubbleName then
+ M:AddChatBubbleName(frame, guid, author)
+ else
+ frame.Name:SetText()
+ end
+
+ frame.text:SetText(msg)
+
+ if frame.text:GetStringWidth() > 300 then
+ frame.text:SetWidth(300)
+ end
+
+ if E.private.chat.enable and E.private.general.classColorMentionsSpeech then
+ local classColorTable, lowerCaseWord, isFirstWord, rebuiltString, tempWord, wordMatch, classMatch
+ if msg and match(msg, "%s-%S+%s*") then
+ for word in gmatch(msg, "%s-%S+%s*") do
+ tempWord = gsub(word, "^[%s%p]-([^%s%p]+)([%-]?[^%s%p]-)[%s%p]*$","%1%2")
+ lowerCaseWord = lower(tempWord)
+
+ classMatch = CH.ClassNames[lowerCaseWord]
+ wordMatch = classMatch and lowerCaseWord
+
+ if wordMatch and not E.global.chat.classColorMentionExcludedNames[wordMatch] then
+ classColorTable = CUSTOM_CLASS_COLORS and CUSTOM_CLASS_COLORS[classMatch] or RAID_CLASS_COLORS[classMatch]
+ word = gsub(word, gsub(tempWord, "%-","%%-"), format("\124cff%.2x%.2x%.2x%s\124r", classColorTable.r*255, classColorTable.g*255, classColorTable.b*255, tempWord))
+ end
+
+ if not isFirstWord then
+ rebuiltString = word
+ isFirstWord = true
+ else
+ rebuiltString = format("%s%s", rebuiltString, word)
+ end
+ end
+
+ if rebuiltString ~= nil then
+ frame.text:SetText(rebuiltString)
+ end
+ end
+ end
+end
+
+function ENP:FindNameplateByChatMsg(event, msg, author, _, _, _, _, _, channelID, _, _, _, guid)
+ if author == UnitName("player") or not author then return end
+ if not next(NP.VisiblePlates) then return end
+
+ local chatType = sub(event, 10)
+ if sub(chatType, 1, 7) == "CHANNEL" then
+ chatType = "CHANNEL"..channelID
+ end
+
+ local info = ChatTypeInfo[chatType]
+ if not info then return end
+
+ for frame in pairs(NP.VisiblePlates) do
+ if frame.UnitName == author then
+ local bubbleFrame
+ if not frame.bubbleFrame then
+ bubbleFrame = AcquireBubble()
+ frame.bubbleFrame = bubbleFrame
+ bubbleFrame.text:ClearAllPoints()
+ bubbleFrame.text:SetPoint("BOTTOM", frame, "TOP", 0, 20)
+ bubbleFrame:Show()
+ E:UIFrameFadeIn(bubbleFrame, .2, 0, 1)
+ else
+ bubbleFrame = frame.bubbleFrame
+ end
+
+ bubbleFrame.parent = frame
+
+ bubbleFrame.text:SetSize(0, 0)
+ bubbleFrame.text:SetTextColor(info.r, info.g, info.b)
+ bubbleFrame.author = author
+
+ if E.private.general.chatBubbles == "backdrop" then
+ if E.PixelMode then
+ bubbleFrame:SetBackdropBorderColor(info.r, info.g, info.b)
+ else
+ local r, g, b = info.r, info.g, info.b
+ bubbleFrame.bordertop:SetTexture(r, g, b)
+ bubbleFrame.borderbottom:SetTexture(r, g, b)
+ bubbleFrame.borderleft:SetTexture(r, g, b)
+ bubbleFrame.borderright:SetTexture(r, g, b)
+ end
+ end
+
+ ENP:AddBubbleMessage(bubbleFrame, msg, author, guid)
+
+ if bubbleFrame.delay == 0 then
+ E:UIFrameFadeRemoveFrame(bubbleFrame)
+ E:UIFrameFadeIn(bubbleFrame, .2, bubbleFrame:GetAlpha(), 1)
+ end
+
+ local _, delayMult = gsub(msg, "%s+", "")
+ SetBubbleDelay(bubbleFrame, 2 + (0.5 * delayMult))
+ end
+ end
+end
+
+local function OnShowHook(frame, ...)
+ ENP.hooks[NP].OnShow(frame, ...)
+
+ if frame.UnitFrame.bubbleFrame then
+ frame.UnitFrame.bubbleFrame = nil
+ end
+
+ if #bubbleList > 0 then
+ for _, bubbleFrame in ipairs(bubbleList) do
+ if frame.UnitFrame.UnitName == bubbleFrame.author then
+ frame.UnitFrame.bubbleFrame = bubbleFrame
+ bubbleFrame.parent = frame.UnitFrame
+
+ bubbleFrame.text:ClearAllPoints()
+ bubbleFrame.text:SetPoint("BOTTOM", frame.UnitFrame, "TOP", 0, 20)
+ bubbleFrame:Show()
+ break
+ end
+ end
+ end
+end
+
+local function OnHideHook(frame)
+ if frame.UnitFrame.bubbleFrame then
+ frame.UnitFrame.bubbleFrame:Hide()
+ end
+ if frame.UnitFrame.Title then
+ frame.UnitFrame.Title:SetText()
+ frame.UnitFrame.Title:Hide()
+ end
+end
+
+function ENP:ChatBubbles()
+ if E.db.enhanced.nameplates.chatBubbles then
+ for _, event in ipairs(events) do
+ ENP:RegisterEvent(event, "FindNameplateByChatMsg")
+ end
+ else
+ for _, event in ipairs(events) do
+ ENP:UnregisterEvent(event)
+ end
+ end
+end
+
+function ENP:UpdateAllSettings()
+ self:ClassCache()
+ self:ChatBubbles()
+ self:TitleCache()
+
+ if E.db.enhanced.nameplates.titleCache or E.db.enhanced.nameplates.classCache then
+ if not self.scanner then
+ self.scanner = CreateFrame("GameTooltip", "Enhanced_ScanningTooltip", nil, "GameTooltipTemplate")
+ self.scanner:SetOwner(WorldFrame, "ANCHOR_NONE")
+ end
+
+ self:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
+
+ elseif not E.db.enhanced.nameplates.titleCache and not E.db.enhanced.nameplates.classCache then
+ self:UnregisterEvent("UPDATE_MOUSEOVER_UNIT")
+ end
+
+ if E.db.enhanced.nameplates.chatBubbles or E.db.enhanced.nameplates.titleCache then
+ if not ENP:IsHooked(NP, "OnHide") then
+ ENP:Hook(NP, "OnHide", OnHideHook)
+ end
+ elseif not E.db.enhanced.nameplates.chatBubbles and not E.db.enhanced.nameplates.titleCache then
+ if ENP:IsHooked(NP, "OnHide") then
+ ENP:Unhook(NP, "OnHide")
+ end
+ end
+ if E.db.enhanced.nameplates.chatBubbles then
+ if not ENP:IsHooked(NP, "OnShow") then
+ ENP:RawHook(NP, "OnShow", OnShowHook, true)
+ end
+ else
+ if ENP:IsHooked(NP, "OnShow") then
+ ENP:Unhook(NP, "OnShow")
+ end
+ end
+end
+
+function ENP:Initialize()
+ EnhancedDB.UnitClass = EnhancedDB.UnitClass or {}
+ EnhancedDB.UnitTitle = EnhancedDB.UnitTitle or {}
+
+ if EnhancedDB.GuildList then
+ for i, guildName in ipairs(EnhancedDB.GuildList) do
+ guildMap[guildName] = i
+ end
+ else
+ EnhancedDB.GuildList = {}
+ end
+
+ if EnhancedDB.NPCList then
+ for i, guildName in ipairs(EnhancedDB.NPCList) do
+ npcTitleMap[guildName] = i
+ end
+ else
+ EnhancedDB.NPCList = {}
+ end
+
+ for i, class in ipairs(CLASS_SORT_ORDER) do
+ classMap[class] = i
+ end
+
+ ENP:UpdateAllSettings()
+end
+
+local function InitializeCallback()
+ ENP:Initialize()
+end
+
+E:RegisterModule(ENP:GetName(), InitializeCallback)
diff --git a/ElvUI_Enhanced/Modules/Tooltip/ItemQualityBorder.lua b/ElvUI_Enhanced/Modules/Tooltip/ItemQualityBorder.lua
new file mode 100644
index 0000000..1d83d1c
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Tooltip/ItemQualityBorder.lua
@@ -0,0 +1,40 @@
+local E, L, V, P, G = unpack(ElvUI)
+local IBC = E:NewModule("Enhanced_ItemBorderColor", "AceHook-3.0")
+local TT = E:GetModule("Tooltip")
+
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+
+function IBC:SetBorderColor(_, tt)
+ if not tt.GetItem then return end
+
+ local _, link = tt:GetItem()
+ if link then
+ local _, _, quality = GetItemInfo(link)
+ if quality then
+ tt:SetBackdropBorderColor(GetItemQualityColor(quality))
+ end
+ end
+end
+
+function IBC:ToggleState()
+ if E.db.enhanced.tooltip.itemQualityBorderColor then
+ if not self:IsHooked(TT, "SetStyle", "SetBorderColor") then
+ self:SecureHook(TT, "SetStyle", "SetBorderColor")
+ end
+ else
+ self:UnhookAll()
+ end
+end
+
+function IBC:Initialize()
+ if not E.db.enhanced.tooltip.itemQualityBorderColor then return end
+
+ self:ToggleState()
+end
+
+local function InitializeCallback()
+ IBC:Initialize()
+end
+
+E:RegisterModule(IBC:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Tooltip/Load_Tooltip.xml b/ElvUI_Enhanced/Modules/Tooltip/Load_Tooltip.xml
new file mode 100644
index 0000000..4806d43
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Tooltip/Load_Tooltip.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Tooltip/ProgressionInfo.lua b/ElvUI_Enhanced/Modules/Tooltip/ProgressionInfo.lua
new file mode 100644
index 0000000..ad0880e
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Tooltip/ProgressionInfo.lua
@@ -0,0 +1,372 @@
+local E, L, V, P, G = unpack(ElvUI)
+local PI = E:NewModule("Enhanced_ProgressionInfo", "AceHook-3.0", "AceEvent-3.0")
+local TT = E:GetModule("Tooltip")
+
+local pairs, ipairs, select, tonumber = pairs, ipairs, select, tonumber
+local format = string.format
+local twipe = table.wipe
+
+local CanInspect = CanInspect
+local ClearAchievementComparisonUnit = ClearAchievementComparisonUnit
+local GetAchievementComparisonInfo = GetAchievementComparisonInfo
+local GetAchievementInfo = GetAchievementInfo
+local GetComparisonStatistic = GetComparisonStatistic
+local GetStatistic = GetStatistic
+local GetTime = GetTime
+local InCombatLockdown = InCombatLockdown
+local IsAltKeyDown = IsAltKeyDown
+local IsControlKeyDown = IsControlKeyDown
+local IsShiftKeyDown = IsShiftKeyDown
+local SetAchievementComparisonUnit = SetAchievementComparisonUnit
+local UnitExists = UnitExists
+local UnitGUID = UnitGUID
+local UnitIsPlayer = UnitIsPlayer
+local UnitLevel = UnitLevel
+
+local MAX_PLAYER_LEVEL = MAX_PLAYER_LEVEL
+
+local difficulties = {"H25", "H10", "N25", "N10"}
+
+local statisticTiers = {
+ ["RS"] = {
+ {4823}, -- Heroic 25
+ {4822}, -- Heroic 10
+ {4820}, -- Normal 25
+ {4821} -- Normal 10
+ },
+ ["ICC"] = {
+ {4642, 4656, 4661, 4664, 4667, 4670, 4673, 4676, 4679, 4682, 4685, 4688}, -- Heroic 25
+ {4640, 4654, 4659, 4662, 4665, 4668, 4671, 4674, 4677, 4680, 4684, 4686}, -- Heroic 10
+ {4641, 4655, 4660, 4663, 4666, 4669, 4672, 4675, 4678, 4681, 4683, 4687}, -- Normal 25
+ {4639, 4643, 4644, 4645, 4646, 4647, 4648, 4649, 4650, 4651, 4652, 4653} -- Normal 10
+ },
+ ["ToC"] = {
+ {4029, 4035, 4039, 4043, 4047}, -- Heroic 25
+ {4030, 4033, 4037, 4041, 4045}, -- Heroic 10
+ {4031, 4034, 4038, 4042, 4046}, -- Normal 25
+ {4028, 4032, 4036, 4040, 4044} -- Normal 10
+ },
+ ["Ulduar"] = {
+ {},
+ {},
+ {2872, 2873, 2874, 2884, 2885, 2875, 2882, 3256, 3257, 3258, 2879, 2880, 2883, 2881}, -- Normal 25
+ {2856, 2857, 2858, 2859, 2860, 2861, 2868, 2862, 2863, 2864, 2865, 2866, 2869, 2867} -- Normal 10
+ }
+}
+
+local achievementTiers = {
+ ["RS"] = {
+ { -- Heroic 25
+ 4816 -- [1] Heroic: The Twilight Destroyer
+ },
+ { -- Heroic 10
+ 4818 -- [1] Heroic: The Twilight Destroyer
+ },
+ { -- Normal 25
+ 4815 -- [1] The Twilight Destroyer
+ },
+ { -- Normal 10
+ 4817 -- [1] The Twilight Destroyer
+ }
+ },
+ ["ICC"] = {
+ { -- Heroic 25
+ -- [0] = 4637, -- [12] Heroic: Fall of the Lich King
+ 4632, -- [4] Heroic: Storming the Citadel
+ 4633, -- [3] Heroic: The Plagueworks
+ 4634, -- [2] Heroic: The Crimson Hall
+ 4635, -- [2] Heroic: The Frostwing Halls
+ 4584 -- [1] The Light of Dawn
+ },
+ { -- Heroic 10
+ -- [0] = 4636, -- [12] Heroic: Fall of the Lich King
+ 4628, -- [4] Heroic: Storming the Citadel
+ 4629, -- [3] Heroic: The Plagueworks
+ 4630, -- [2] Heroic: The Crimson Hall
+ 4631, -- [2] Heroic: The Frostwing Halls
+ 4583 -- [1] Bane of the Fallen King
+ },
+ { -- Normal 25
+ -- [0] = 4608, -- [12] Fall of the Lich King
+ 4604, -- [4] Storming the Citadel
+ 4605, -- [3] The Plagueworks
+ 4606, -- [2] The Crimson Hall
+ 4607, -- [2] The Frostwing Halls
+ 4597 -- [1] The Frozen Throne
+ },
+ { -- Normal 10
+ -- [0] = 4532, -- [12] Fall of the Lich King
+ 4531, -- [4] Storming the Citadel
+ 4528, -- [3] The Plagueworks
+ 4529, -- [2] The Crimson Hall
+ 4527, -- [2] The Frostwing Halls
+ 4530 -- [1] The Frozen Throne
+ }
+ },
+ ["ToC"] = {
+ { -- Heroic 25
+ 3812 -- [5] Call of the Grand Crusade
+ },
+ { -- Heroic 10
+ 3918 -- [5] Call of the Grand Crusade
+ },
+ { -- Normal 25
+ 3916 -- [5] Call of the Crusade
+ },
+ { -- Normal 10
+ 3917 -- [5] Call of the Crusade
+ }
+ },
+ ["Ulduar"] = {
+ {},
+ {},
+ { -- Normal 25
+ -- [0] = 2895, -- [13] The Secrets of Ulduar
+ 2887, -- [4] The Siege of Ulduar
+ 2889, -- [3] The Antechamber of Ulduar
+ 2891, -- [4] The Keepers of Ulduar
+ 2893, -- [2] The Descent into Madness
+ 3037 -- [1] Observed
+ },
+ { -- Normal 10
+ -- [0] = 2894, -- [13] The Secrets of Ulduar
+ 2886, -- [4] The Siege of Ulduar
+ 2888, -- [3] The Antechamber of Ulduar
+ 2890, -- [4] The Keepers of Ulduar
+ 2892, -- [2] The Descent into Madness
+ 3036 -- [1] Observed
+ }
+ }
+}
+
+local progressCache = {}
+
+--[[
+local GetAchievementCriteriaInfo = GetAchievementCriteriaInfo
+local GetAchievementNumCriteria = GetAchievementNumCriteria
+
+local function getAchievementProgress(achievementID, criteriaInfo)
+ local progress = 0
+
+ for i = 1, GetAchievementNumCriteria(achievementID) do
+ local _, _, completed = GetAchievementCriteriaInfo(achievementID, i)
+
+ if completed then
+ progress = progress + 1
+ end
+ end
+
+ return progress
+end
+]]
+
+local function isAchievementComplete(achievementID)
+ return (select(4, GetAchievementInfo(achievementID))) and 1 or 0
+end
+
+local function isAchievementComparisonComplete(achievementID)
+ return (GetAchievementComparisonInfo(achievementID)) and 1 or 0
+end
+
+local function GetProgression(guid)
+ local total, kills, killed, tierName
+ local statFunc, tiers
+
+ if E.db.enhanced.tooltip.progressInfo.checkAchievements then
+ statFunc = guid == E.myguid and isAchievementComplete or isAchievementComparisonComplete
+ tiers = achievementTiers
+ else
+ statFunc = guid == E.myguid and GetStatistic or GetComparisonStatistic
+ tiers = statisticTiers
+ end
+
+ local header = progressCache[guid].header
+ local info = progressCache[guid].info
+
+ for tier in pairs(tiers) do
+ header[tier] = header[tier] and twipe(header[tier]) or {}
+ info[tier] = info[tier] and twipe(info[tier]) or {}
+
+ for i, difficulty in ipairs(difficulties) do
+ if #tiers[tier][i] > 0 then
+ total = #tiers[tier][i]
+ killed = 0
+
+ for _, statsID in ipairs(tiers[tier][i]) do
+ kills = tonumber(statFunc(statsID))
+
+ if kills and kills > 0 then
+ killed = killed + 1
+ end
+ end
+
+ if killed > 0 then
+ tierName = tier
+ if i <= 2 and tier == "ToC" then
+ tierName = "ToGC"
+ end
+
+ header[tier][i] = format("%s [%s]:", L[tierName], difficulty)
+ info[tier][i] = format("%d/%d", killed, total)
+
+ if killed == total then
+ break
+ end
+ end
+ end
+ end
+ end
+end
+
+local function UpdateProgression(guid)
+ if not progressCache[guid] then
+ progressCache[guid] = {
+ header = {},
+ info = {},
+ }
+ end
+
+ progressCache[guid].timer = GetTime()
+
+ GetProgression(guid)
+end
+
+local function SetProgressionInfo(guid, tt)
+ if not progressCache[guid] then return end
+
+ local tiers = E.db.enhanced.tooltip.progressInfo.checkAchievements and achievementTiers or statisticTiers
+
+ for tier in pairs(tiers) do
+ if E.db.enhanced.tooltip.progressInfo.tiers[tier] then
+ for i = 1, #difficulties do
+ if #tiers[tier][i] > 0 then
+ tt:AddDoubleLine(progressCache[guid].header[tier][i], progressCache[guid].info[tier][i], nil, nil, nil, 1, 1, 1)
+ end
+ end
+ end
+ end
+end
+
+local function ShowInspectInfo(tt)
+ if InCombatLockdown() then return end
+
+ local modifier = E.db.enhanced.tooltip.progressInfo.modifier
+ if modifier ~= "ALL" and not ((modifier == "SHIFT" and IsShiftKeyDown()) or (modifier == "CTRL" and IsControlKeyDown()) or (modifier == "ALT" and IsAltKeyDown())) then return end
+
+ local unit = select(2, tt:GetUnit())
+ if unit == "player" then
+ if not E.db.enhanced.tooltip.progressInfo.checkPlayer then return end
+
+ UpdateProgression(E.myguid)
+ SetProgressionInfo(E.myguid, tt)
+ return
+ end
+
+ if not unit or not UnitIsPlayer(unit) then return end
+
+ local level = UnitLevel(unit)
+ if not level or level < MAX_PLAYER_LEVEL then return end
+
+ if not CanInspect(unit, false) then return end
+
+ local guid = UnitGUID(unit)
+ local frameShowen = AchievementFrame and AchievementFrame:IsShown()
+
+ if progressCache[guid] and (frameShowen or (GetTime() - progressCache[guid].timer) < 600) then
+ SetProgressionInfo(guid, tt)
+ elseif not frameShowen then
+ PI.compareGUID = guid
+
+ PI:RegisterEvent("INSPECT_ACHIEVEMENT_READY")
+
+ if AchievementFrameComparison then
+ AchievementFrameComparison:UnregisterEvent("INSPECT_ACHIEVEMENT_READY")
+ end
+
+ ClearAchievementComparisonUnit()
+ SetAchievementComparisonUnit(unit)
+ end
+end
+
+function PI:INSPECT_ACHIEVEMENT_READY()
+ UpdateProgression(self.compareGUID)
+ ClearAchievementComparisonUnit()
+
+ if UnitExists("mouseover") and UnitGUID("mouseover") == self.compareGUID then
+ GameTooltip:SetUnit("mouseover")
+ end
+
+ self:UnregisterEvent("INSPECT_ACHIEVEMENT_READY")
+
+ if AchievementFrameComparison then
+ AchievementFrameComparison:RegisterEvent("INSPECT_ACHIEVEMENT_READY")
+ end
+
+ self.compareGUID = nil
+end
+
+function PI:MODIFIER_STATE_CHANGED(_, key)
+ if (key == format("L%s", self.modifier) or key == format("R%s", self.modifier)) and UnitExists("mouseover") then
+ GameTooltip:SetUnit("mouseover")
+ end
+end
+
+function PI:UpdateSettings()
+ local enabled
+
+ for _, state in pairs(E.db.enhanced.tooltip.progressInfo.tiers) do
+ if state then
+ enabled = state
+ break
+ end
+ end
+
+ if enabled then
+ self:ToggleState()
+ else
+ self:UnregisterEvent("INSPECT_ACHIEVEMENT_READY")
+ self:UnhookAll()
+ end
+end
+
+function PI:UpdateModifier()
+ self.modifier = E.db.enhanced.tooltip.progressInfo.modifier
+
+ if self.modifier == "ALL" then
+ self:UnregisterEvent("MODIFIER_STATE_CHANGED")
+ else
+ self:RegisterEvent("MODIFIER_STATE_CHANGED")
+ end
+end
+
+function PI:ToggleState()
+ if E.db.enhanced.tooltip.progressInfo.enable then
+ if E.private.tooltip.enabled and TT then
+ if not self:IsHooked(TT, "GameTooltip_OnTooltipSetUnit", ShowInspectInfo) then
+ self:SecureHook(TT, "GameTooltip_OnTooltipSetUnit", ShowInspectInfo)
+ end
+ else
+ if not self:IsHooked(GameTooltip, "OnTooltipSetUnit", ShowInspectInfo) then
+ self:HookScript(GameTooltip, "OnTooltipSetUnit", ShowInspectInfo)
+ end
+ end
+
+ self:UpdateModifier()
+ else
+ self:UnregisterAllEvents()
+ self:UnhookAll()
+ end
+end
+
+function PI:Initialize()
+ if not E.db.enhanced.tooltip.progressInfo.enable then return end
+
+ self.progressCache = progressCache
+ self:ToggleState()
+end
+
+local function InitializeCallback()
+ PI:Initialize()
+end
+
+E:RegisterModule(PI:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Tooltip/TooltipIcon.lua b/ElvUI_Enhanced/Modules/Tooltip/TooltipIcon.lua
new file mode 100644
index 0000000..12e2785
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Tooltip/TooltipIcon.lua
@@ -0,0 +1,109 @@
+local E, L, V, P, G = unpack(ElvUI)
+local TI = E:NewModule("Enhanced_TooltipIcon", "AceHook-3.0")
+
+local _G = _G
+local select, type = select, type
+local find, match = string.find, string.match
+
+local GetAchievementInfo = GetAchievementInfo
+local GetItemIcon = GetItemIcon
+local GetSpellInfo = GetSpellInfo
+
+local itemTooltips = {
+ GameTooltip,
+ ItemRefTooltip,
+ ShoppingTooltip1,
+ ShoppingTooltip2
+}
+
+local spellTooltips = {
+ GameTooltip,
+ ItemRefTooltip
+}
+
+local function AddIcon(self, icon)
+ if not icon then return end
+
+ local title = _G[self:GetName().."TextLeft1"]
+ local text = title and title:GetText()
+
+ if text and not find(text, "|T"..icon) then
+ title:SetFormattedText("|T%s:30:30:0:0:64:64:5:59:5:59|t %s", icon, text)
+ end
+end
+
+local function ItemIcon(self)
+ local _, link = self:GetItem()
+ local icon = link and GetItemIcon(link)
+ AddIcon(self, icon)
+end
+
+local function SpellIcon(self)
+ local id = self:GetSpell()
+ if id then
+ AddIcon(self, select(3, GetSpellInfo(id)))
+ end
+end
+
+local function AchievementIcon(self, link)
+ if type(link) ~= "string" then return end
+
+ local linkType, id = match(link, "^([^:]+):(%d+)")
+ if id and (linkType == "achievement") then
+ AddIcon(self, select(10, GetAchievementInfo(id)))
+ end
+end
+
+function TI:ToggleItemsState()
+ local state = E.db.enhanced.tooltip.tooltipIcon.tooltipIconItems and E.db.enhanced.tooltip.tooltipIcon.enable
+
+ for _, tooltip in ipairs(itemTooltips) do
+ if state then
+ if not self:IsHooked(tooltip, "OnTooltipSetItem", ItemIcon) then
+ self:SecureHookScript(tooltip, "OnTooltipSetItem", ItemIcon)
+ end
+ else
+ self:Unhook(tooltip, "OnTooltipSetItem")
+ end
+ end
+end
+
+function TI:ToggleSpellsState()
+ local state = E.db.enhanced.tooltip.tooltipIcon.tooltipIconSpells and E.db.enhanced.tooltip.tooltipIcon.enable
+
+ for _, tooltip in ipairs(spellTooltips) do
+ if state then
+ if not self:IsHooked(tooltip, "OnTooltipSetSpell", SpellIcon) then
+ self:SecureHookScript(tooltip, "OnTooltipSetSpell", SpellIcon)
+ end
+ else
+ self:Unhook(tooltip, "OnTooltipSetSpell")
+ end
+ end
+end
+
+function TI:ToggleAchievementsState()
+ local state = E.db.enhanced.tooltip.tooltipIcon.tooltipIconAchievements and E.db.enhanced.tooltip.tooltipIcon.enable
+
+ if state then
+ if not self:IsHooked(GameTooltip, "SetHyperlink", AchievementIcon) then
+ self:SecureHook(GameTooltip, "SetHyperlink", AchievementIcon)
+ end
+ else
+ self:Unhook(GameTooltip, "SetHyperlink")
+ end
+end
+
+function TI:Initialize()
+ if not E.db.enhanced.tooltip.tooltipIcon.enable then return end
+
+ self:ToggleItemsState()
+ self:ToggleSpellsState()
+ self:ToggleAchievementsState()
+end
+
+local function InitializeCallback()
+ TI:Initialize()
+end
+
+E:RegisterModule(TI:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Unitframes/DetachedPortrait.lua b/ElvUI_Enhanced/Modules/Unitframes/DetachedPortrait.lua
new file mode 100644
index 0000000..3d38e0b
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Unitframes/DetachedPortrait.lua
@@ -0,0 +1,79 @@
+local E, L, V, P, G = unpack(ElvUI)
+local UFDP = E:NewModule("Enhanced_DetachedPortrait", "AceHook-3.0")
+local UF = E:GetModule("UnitFrames")
+
+local function Configure_Portrait(self, frame)
+ if frame.unitframeType == "player" or frame.unitframeType == "target" then
+ local db = E.db.enhanced.unitframe.detachPortrait[frame.unitframeType]
+
+ frame.PORTRAIT_DETACHED = frame.USE_PORTRAIT and db.enable and not frame.USE_PORTRAIT_OVERLAY
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or frame.PORTRAIT_DETACHED or not frame.USE_PORTRAIT) and 0 or frame.db.portrait.width
+ frame.CLASSBAR_WIDTH = frame.UNIT_WIDTH - (frame.BORDER + frame.SPACING) * 2 - frame.PORTRAIT_WIDTH - frame.POWERBAR_OFFSET
+
+ if frame.USE_PORTRAIT then
+ local portrait = frame.Portrait
+
+ if frame.PORTRAIT_DETACHED then
+ if not portrait.Holder or (portrait.Holder and not portrait.Holder.mover) then
+ portrait.Holder = CreateFrame("Frame", nil, UIParent)
+ portrait.Holder:Size(db.width, db.height)
+
+ if frame.ORIENTATION == "LEFT" then
+ portrait.Holder:Point("RIGHT", frame, "LEFT", -frame.BORDER, 0)
+ elseif frame.ORIENTATION == "RIGHT" then
+ portrait.Holder:Point("LEFT", frame, "RIGHT", frame.BORDER, 0)
+ end
+
+ portrait:SetInside(portrait.Holder)
+ portrait.backdrop:SetOutside(portrait)
+
+ if frame.unitframeType == "player" then
+ E:CreateMover(portrait.Holder, "PlayerPortraitMover", L["Player Portrait"], nil, nil, nil, "ALL,SOLO")
+ elseif frame.unitframeType == "target" then
+ E:CreateMover(portrait.Holder, "TargetPortraitMover", L["Target Portrait"], nil, nil, nil, "ALL,SOLO")
+ end
+ else
+ portrait.Holder:Size(db.width, db.height)
+ portrait:SetInside(portrait.Holder)
+ portrait.backdrop:SetOutside(portrait)
+ E:EnableMover(portrait.Holder.mover:GetName())
+ end
+ end
+
+ if not frame.PORTRAIT_DETACHED and portrait.Holder and portrait.Holder.mover then
+ E:DisableMover(portrait.Holder.mover:GetName())
+ end
+
+ self:Configure_HealthBar(frame)
+ self:Configure_Power(frame)
+ end
+ end
+end
+
+function UFDP:ToggleState(unit)
+ if E.db.enhanced.unitframe.detachPortrait.player.enable or E.db.enhanced.unitframe.detachPortrait.target.enable then
+ if not self:IsHooked(UF, "Configure_Portrait") then
+ self:SecureHook(UF, "Configure_Portrait", Configure_Portrait)
+ end
+
+ if unit then
+ UF:CreateAndUpdateUF(unit)
+ end
+ else
+ UF:CreateAndUpdateUF(unit)
+ self:Unhook(UF, "Configure_Portrait")
+ end
+end
+
+function UFDP:Initialize()
+ if not E.private.unitframe.enable then return end
+ if not (E.db.enhanced.unitframe.detachPortrait.player.enable or E.db.enhanced.unitframe.detachPortrait.target.enable) then return end
+
+ self:ToggleState()
+end
+
+local function InitializeCallback()
+ UFDP:Initialize()
+end
+
+E:RegisterModule(UFDP:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Unitframes/Load_UnitFrames.xml b/ElvUI_Enhanced/Modules/Unitframes/Load_UnitFrames.xml
new file mode 100644
index 0000000..1e82bdd
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Unitframes/Load_UnitFrames.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Unitframes/PortraitHDModelFix.lua b/ElvUI_Enhanced/Modules/Unitframes/PortraitHDModelFix.lua
new file mode 100644
index 0000000..f4b6c22
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Unitframes/PortraitHDModelFix.lua
@@ -0,0 +1,122 @@
+local E, L, V, P, G = unpack(ElvUI)
+local UFPM = E:NewModule("Enhanced_PortraitHDModelFix", "AceHook-3.0")
+local UF = E:GetModule("UnitFrames")
+
+local find, format, gsub, split = string.find, string.format, string.gsub, string.split
+local tinsert, twipe = table.insert, table.wipe
+local ipairs = ipairs
+
+local function HdModels()
+ local f = CreateFrame("frame", nil)
+ local t = f:CreateTexture()
+ t:SetPoint("CENTER", WorldFrame)
+ t:SetTexture("Character\\Tauren\\Male\\TaurenMaleFaceLower00_00_HD")
+ t:SetSize(0, 0)
+ local exist = t:GetTexture() and true or false
+ t:SetTexture(nil)
+ f:Kill()
+ return exist
+end
+
+local function PortraitHDModelFix(self)
+ if self:IsObjectType("Model") then
+ local model = self:GetModel()
+ if not model or type(model) ~= "string" then return end
+
+ if UFPM.db.debug then
+ print(format("|cffc79c6eUnit:|r %s; |cffc79c6eModel:|r %s", self:GetParent().unitframeType, gsub(model, ".+\\(%S+%.m2)", "%1")))
+ end
+
+ for _, modelName in ipairs(UFPM.modelsToFix) do
+ if find(model, modelName) then
+ self:SetCamera(1)
+ break
+ end
+ end
+
+ end
+end
+
+local frames = {
+ {"player", "target", "targettarget", "targettargettarget", "focus", "focustarget", "pet", "pettarget"},
+ {"boss", "arena"},
+ {"party", "raid", "raid40"}
+}
+
+function UFPM:UpdatePortraits()
+ local modelList = self.db.modelsToFix
+ modelList = gsub(modelList, "%s+", "")
+ twipe(self.modelsToFix)
+
+ for _, modelName in ipairs({split(";", modelList)}) do
+ if modelName ~= "" then
+ tinsert(self.modelsToFix, modelName)
+ end
+ end
+
+ for i = 1, 3 do
+ for _, frame in ipairs(frames[i]) do
+ if i == 1 then
+ UF.CreateAndUpdateUF(UF, frame)
+ elseif i == 2 then
+ if frame == "boss" then
+ UF.CreateAndUpdateUFGroup(UF, frame, MAX_BOSS_FRAMES)
+ else
+ UF.CreateAndUpdateUFGroup(UF, frame, 5)
+ end
+ else
+ UF.CreateAndUpdateHeaderGroup(UF, frame)
+ end
+ end
+ end
+end
+
+function UFPM:ToggleState()
+ if not self.hdModels then return end
+
+ if self.db.enable then
+ self:SecureHook(UF, "PortraitUpdate", PortraitHDModelFix)
+ else
+ self:UnhookAll()
+ return
+ end
+
+ local frame, frameName
+
+ for i = 1, 3 do
+ for _, unit in ipairs(frames[i]) do
+ frameName = E:StringTitle(unit)
+ frame = _G["ElvUF_"..frameName]
+
+ if frame and frame.Portrait3D and frame.Portrait3D.PostUpdate then
+ if self.db.enable then
+ if not self:IsHooked(frame.Portrait3D, "PostUpdate", PortraitHDModelFix) then
+ self:SecureHook(frame.Portrait3D, "PostUpdate", PortraitHDModelFix)
+ end
+ else
+ self:UnhookAll()
+ end
+ end
+ end
+ end
+
+ self:UpdatePortraits()
+end
+
+function UFPM:Initialize()
+ if not E.private.unitframe.enable then return end
+
+ self.db = E.db.enhanced.unitframe.portraitHDModelFix
+ self.modelsToFix = {}
+ self.hdModels = HdModels()
+
+ if not self.db.enable then return end
+
+ self:ToggleState()
+end
+
+local function InitializeCallback()
+ UFPM:Initialize()
+end
+
+E:RegisterModule(UFPM:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Unitframes/TargetClass.lua b/ElvUI_Enhanced/Modules/Unitframes/TargetClass.lua
new file mode 100644
index 0000000..9b72693
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Unitframes/TargetClass.lua
@@ -0,0 +1,55 @@
+local E, L, V, P, G = unpack(ElvUI)
+local TC = E:NewModule("Enhanced_TargetClass", "AceEvent-3.0")
+
+local select = select
+
+local UnitClass = UnitClass
+local UnitClassification = UnitClassification
+local UnitIsPlayer = UnitIsPlayer
+
+local CLASS_ICON_TCOORDS = CLASS_ICON_TCOORDS
+
+function TC:TargetChanged()
+ self.frame:Hide()
+
+ local class = UnitIsPlayer("target") and select(2, UnitClass("target")) or UnitClassification("target")
+ if class then
+ local coordinates = CLASS_ICON_TCOORDS[class]
+ if coordinates then
+ self.frame.Texture:SetTexCoord(coordinates[1], coordinates[2], coordinates[3], coordinates[4])
+ self.frame:Show()
+ end
+ end
+end
+
+function TC:ToggleSettings()
+ if self.db.enable then
+ self.frame:Size(self.db.size, self.db.size)
+ self.frame:ClearAllPoints()
+ self.frame:Point("CENTER", ElvUF_Target, "TOP", self.db.xOffset, self.db.yOffset)
+
+ self:RegisterEvent("PLAYER_TARGET_CHANGED", "TargetChanged")
+ self:TargetChanged()
+ else
+ self:UnregisterEvent("PLAYER_TARGET_CHANGED")
+ self.frame:Hide()
+ end
+end
+
+function TC:Initialize()
+ self.db = E.db.enhanced.unitframe.units.target.classicon
+
+ self.frame = CreateFrame("Frame", "TargetClass", E.UIParent)
+ self.frame:SetFrameLevel(12)
+ self.frame.Texture = self.frame:CreateTexture(nil, "ARTWORK")
+ self.frame.Texture:SetAllPoints()
+ self.frame.Texture:SetTexture([[Interface\WorldStateFrame\Icons-Classes]])
+
+ self:ToggleSettings()
+end
+
+local function InitializeCallback()
+ TC:Initialize()
+end
+
+E:RegisterModule(TC:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Watchframe/Load_WatchFrame.xml b/ElvUI_Enhanced/Modules/Watchframe/Load_WatchFrame.xml
new file mode 100644
index 0000000..bae398d
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Watchframe/Load_WatchFrame.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Modules/Watchframe/WatchFrame.lua b/ElvUI_Enhanced/Modules/Watchframe/WatchFrame.lua
new file mode 100644
index 0000000..9ba40e7
--- /dev/null
+++ b/ElvUI_Enhanced/Modules/Watchframe/WatchFrame.lua
@@ -0,0 +1,77 @@
+local E, L, V, P, G = unpack(ElvUI)
+local WF = E:NewModule("Enhanced_WatchFrame", "AceEvent-3.0")
+
+local IsInInstance = IsInInstance
+local IsResting = IsResting
+local UnitAffectingCombat = UnitAffectingCombat
+
+local watchFrame
+
+local statedriver = {
+ ["NONE"] = function()
+ WatchFrame.userCollapsed = false
+ WatchFrame_Expand(watchFrame)
+ WatchFrame:Show()
+ end,
+ ["COLLAPSED"] = function()
+ WatchFrame.userCollapsed = true
+ WatchFrame_Collapse(watchFrame)
+ WatchFrame:Show()
+ end,
+ ["HIDDEN"] = function()
+ WatchFrame:Hide()
+ end
+}
+
+function WF:ChangeState()
+ if UnitAffectingCombat("player") then
+ self:RegisterEvent("PLAYER_REGEN_ENABLED", "ChangeState")
+ self.inCombat = true
+ return
+ end
+
+ if IsResting() then
+ statedriver[self.db.city](watchFrame)
+ else
+ local _, instanceType = IsInInstance()
+ if instanceType == "pvp" then
+ statedriver[self.db.pvp](watchFrame)
+ elseif instanceType == "arena" then
+ statedriver[self.db.arena](watchFrame)
+ elseif instanceType == "party" then
+ statedriver[self.db.party](watchFrame)
+ elseif instanceType == "raid" then
+ statedriver[self.db.raid](watchFrame)
+ else
+ statedriver["NONE"](watchFrame)
+ end
+ end
+
+ if self.inCombat then
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED")
+ self.inCombat = nil
+ end
+end
+
+function WF:UpdateSettings()
+ if self.db.enable then
+ self:RegisterEvent("PLAYER_ENTERING_WORLD", "ChangeState")
+ self:RegisterEvent("PLAYER_UPDATE_RESTING", "ChangeState")
+ else
+ self:UnregisterEvent("PLAYER_ENTERING_WORLD")
+ self:UnregisterEvent("PLAYER_UPDATE_RESTING")
+ end
+end
+
+function WF:Initialize()
+ watchFrame = _G["WatchFrame"]
+ self.db = E.db.enhanced.watchframe
+
+ self:UpdateSettings()
+end
+
+local function InitializeCallback()
+ WF:Initialize()
+end
+
+E:RegisterModule(WF:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Settings/Load_Settings.xml b/ElvUI_Enhanced/Settings/Load_Settings.xml
new file mode 100644
index 0000000..265f032
--- /dev/null
+++ b/ElvUI_Enhanced/Settings/Load_Settings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Settings/Private.lua b/ElvUI_Enhanced/Settings/Private.lua
new file mode 100644
index 0000000..c6fd545
--- /dev/null
+++ b/ElvUI_Enhanced/Settings/Private.lua
@@ -0,0 +1,51 @@
+local E, L, V, P, G = unpack(ElvUI)
+
+V.enhanced = {
+ animatedAchievementBars = false,
+ deathRecap = false,
+ actionbar = {
+ keyPressAnimation = false
+ },
+ character = {
+ enable = true,
+ modelFrames = false,
+ collapsed = false,
+ player = {
+ orderName = "",
+ collapsedName = {
+ ITEM_LEVEL = false,
+ BASE_STATS = false,
+ MELEE_COMBAT = false,
+ RANGED_COMBAT = false,
+ SPELL_COMBAT = false,
+ DEFENSES = false,
+ RESISTANCE = false
+ }
+ },
+ pet = {
+ orderName = "",
+ collapsedName = {
+ ITEM_LEVEL = false,
+ BASE_STATS = false,
+ MELEE_COMBAT = false,
+ RANGED_COMBAT = false,
+ SPELL_COMBAT = false,
+ DEFENSES = false,
+ RESISTANCE = false
+ }
+ }
+ },
+ timerTracker = {
+ enable = false
+ },
+ loseControl = {
+ enable = false
+ },
+ interruptTracker = {
+ enable = false,
+ everywhere = false,
+ arena = true,
+ battleground = false
+ },
+ minimapButtonGrabber = false
+}
\ No newline at end of file
diff --git a/ElvUI_Enhanced/Settings/Profile.lua b/ElvUI_Enhanced/Settings/Profile.lua
new file mode 100644
index 0000000..e792a26
--- /dev/null
+++ b/ElvUI_Enhanced/Settings/Profile.lua
@@ -0,0 +1,219 @@
+local E, L, V, P, G = unpack(ElvUI)
+
+P.enhanced = {
+ general = {
+ pvpAutoRelease = false,
+ autoRepChange = false,
+ merchant = false,
+ moverTransparancy = 0.8,
+ showQuestLevel = false,
+ declineduel = false,
+ hideZoneText = false,
+ trainAllSkills = false,
+ undressButton = false,
+ alreadyKnown = false,
+ },
+ actionbar = {
+ keyPressAnimation = {
+ color = {r = 1, g = 1, b = 1},
+ scale = 1.5,
+ rotation = 90,
+ }
+ },
+ blizzard = {
+ dressUpFrame = {
+ enable = false,
+ multiplier = 1.25
+ },
+ errorFrame = {
+ enable = false,
+ width = 300,
+ height = 60,
+ font = "PT Sans Narrow",
+ fontSize = 12,
+ fontOutline = "NONE"
+ },
+ takeAllMail = false
+ },
+ chat = {
+ dpsLinks = false,
+ },
+ character = {
+ animations = false,
+ characterBackground = false,
+ petBackground = false,
+ inspectBackground = false,
+ companionBackground = false,
+ desaturateCharacter = false,
+ desaturatePet = false,
+ desaturateInspect = false,
+ desaturateCompanion = false
+ },
+ equipment = {
+ enable = false,
+ font = "Homespun",
+ fontSize = 10,
+ fontOutline = "MONOCHROMEOUTLINE",
+ itemlevel = {
+ enable = true,
+ qualityColor = true,
+ position = "BOTTOMLEFT",
+ xOffset = 1,
+ yOffset = 4
+ },
+ durability = {
+ enable = false,
+ onlydamaged = true,
+ position = "TOPLEFT",
+ xOffset = 1,
+ yOffset = 0
+ }
+ },
+ map = {
+ fogClear = {
+ enable = false,
+ color = {r = 0.5, g = 0.5, b = 0.5, a = 1}
+ }
+ },
+ minimap = {
+ location = false,
+ showlocationdigits = true,
+ locationdigits = 1,
+ hideincombat = false,
+ fadeindelay = 5,
+ buttonGrabber = {
+ backdrop = false,
+ backdropSpacing = 1,
+ mouseover = false,
+ alpha = 1,
+ buttonSize = 22,
+ buttonSpacing = 0,
+ buttonsPerRow = 1,
+ growFrom = "TOPLEFT",
+ insideMinimap = {
+ enable = true,
+ position = "TOPLEFT",
+ xOffset = -1,
+ yOffset = 1
+ }
+ }
+ },
+ nameplates = {
+ classCache = false,
+ chatBubbles = false,
+ titleCache = false,
+ guild = {
+ font = "PT Sans Narrow",
+ fontSize = 11,
+ fontOutline = "OUTLINE",
+ separator = " ",
+ colors = {
+ raid = {r = 1, g = 127/255, b = 0},
+ party = {r = 118/255, g = 200/255, b = 1},
+ guild = {r = 64/255, g = 1, b = 64/255},
+ none = {r = 1, g = 1, b = 1}
+ },
+ visibility = {
+ city = true,
+ pvp = true,
+ arena = true,
+ party = true,
+ raid = true
+ }
+ },
+ npc = {
+ font = "PT Sans Narrow",
+ fontSize = 11,
+ fontOutline = "OUTLINE",
+ reactionColor = false,
+ color = {r = 1, g = 1, b = 1},
+ separator = " ",
+ }
+ },
+ tooltip = {
+ itemQualityBorderColor = false,
+ tooltipIcon = {
+ enable = false,
+ tooltipIconSpells = true,
+ tooltipIconItems = true,
+ tooltipIconAchievements = true
+ },
+ progressInfo = {
+ enable = false,
+ checkAchievements = false,
+ checkPlayer = false,
+ modifier = "SHIFT",
+ tiers = {
+ ["DS"] = true,
+ ["FL"] = true,
+ ["BH"] = true,
+ ["TOTFW"] = true,
+ ["BT"] = true,
+ ["BWD"] = true
+ }
+ }
+ },
+ loseControl = {
+ iconSize = 60,
+ compactMode = false,
+ CC = true,
+ PvE = true,
+ Silence = true,
+ Disarm = true,
+ Root = false,
+ Snare = false
+ },
+ timerTracker = {
+ dbm = true
+ },
+ interruptTracker = {
+ size = 32,
+ text = {
+ enable = true,
+ font = "PT Sans Narrow",
+ fontSize = 10,
+ fontOutline = "OUTLINE",
+ position = "CENTER",
+ xOffset = 0,
+ yOffset = 0,
+ }
+ },
+ unitframe = {
+ portraitHDModelFix = {
+ enable = false,
+ debug = false,
+ modelsToFix = "scourgemale.m2; scourgefemale.m2; humanfemale.m2; dwarfmale.m2; orcmalenpc.m2; scourgemalenpc.m2; scourgefemalenpc.m2; dwarfmalenpc.m2; humanmalekid.m2; humanfemalekid.m2; chicken.m2; rat.m2"
+ },
+ detachPortrait = {
+ player = {
+ enable = false,
+ width = 54,
+ height = 54
+ },
+ target = {
+ enable = false,
+ width = 54,
+ height = 54
+ }
+ },
+ units = {
+ target = {
+ classicon = {
+ enable = false,
+ size = 28,
+ xOffset = -58,
+ yOffset = -22
+ }
+ }
+ },
+ hideRoleInCombat = false
+ },
+ watchframe = {
+ enable = false,
+ city = "COLLAPSED",
+ pvp = "HIDDEN",
+ arena = "HIDDEN",
+ party = "COLLAPSED",
+ raid = "COLLAPSED"
+ }
+}