Files
moonwell-core/lua_scripts/MythicPlus/Mythic_Client.lua
2025-08-30 19:38:04 +04:00

1527 lines
58 KiB
Lua

local activeAffixes = {}
local AIO = AIO or require("AIO")
local L = {
Text = function(self, category, key, localeIndex)
if not self[category] or not self[category][key] then
return key
end
if not self[category][key][localeIndex] then
return self[category][key][0]
end
return self[category][key][localeIndex]
end,
Items = {},
Dungeons = {},
UI = {}
}
if AIO.AddAddon() then
return
end
MythicPlusCharRunState = {
active = false,
mapId = nil,
tier = nil,
duration = nil,
elapsed = nil,
bossNames = {},
killedBosses = {},
potentialGain = 0,
penalty = 0,
bonus = 0,
deaths = 0,
maxDeaths = 0,
enemyForces = {
current = 0,
required = 0,
percentage = 0,
completed = false
},
saveTime = nil
}
AIO.AddSavedVarChar("MythicPlusCharRunState")
local MythicHandlers = AIO.AddHandlers("AIO_Mythic", {})
local lastKeystoneLink = nil
local lastMapName = nil
local lastTierLevel = nil
local fmt, floor = string.format, math.floor
local localeDataReceived = false
function MythicHandlers.ReceiveLocaleData(_, category, entries)
if type(entries) == "table" then
L[category] = entries
if L.Items and L.Dungeons and L.UI then
localeDataReceived = true
if MythicPlusFrame then
UpdateLocalizedElements()
end
end
end
end
function MythicGetText(category, key)
local localeIndex = GetLocale() and MythicGetLocaleIndex() or 0
return L:Text(category, key, localeIndex)
end
function MythicGetLocaleIndex()
local locale = GetLocale()
local localeMap = {
["enUS"] = 0, ["enGB"] = 0,
["koKR"] = 1,
["frFR"] = 2,
["deDE"] = 3,
["zhCN"] = 4,
["zhTW"] = 5,
["esES"] = 6,
["esMX"] = 7,
["ruRU"] = 8
}
return localeMap[locale] or 0
end
function UpdateLocalizedElements()
if DUNGEONS then
for mapId, dungeonData in pairs(DUNGEONS) do
dungeonData.name = MythicGetText("Dungeons", dungeonData.originalName)
end
end
if MythicPlusFrame then
if tabs then
for i, tab in ipairs(tabs) do
if i == 1 then
tab:SetText(MythicGetText("UI", "Overview"))
elseif i == 2 then
tab:SetText(MythicGetText("UI", "Score"))
elseif i == 3 then
tab:SetText(MythicGetText("UI", "Leaderboard"))
end
end
end
if MythicPlusFrame.overviewTitle then
MythicPlusFrame.overviewTitle:SetText(MythicGetText("UI", "Overview"))
end
if MythicPlusFrame.scoreTitle then
MythicPlusFrame.scoreTitle:SetText(MythicGetText("UI", "Score"))
end
if MythicPlusFrame.leaderboardTitle then
MythicPlusFrame.leaderboardTitle:SetText(MythicGetText("UI", "Leaderboard"))
end
if frame and frame.affixButtons then
for _, button in ipairs(frame.affixButtons) do
if button.affixName then
local isActive = frame.currentAffixes and
(button.affixName == frame.currentAffixes[1] or
button.affixName == frame.currentAffixes[2] or
button.affixName == frame.currentAffixes[3])
button.label:SetText((isActive and "|cff00ff00" or "") .. MythicGetText("UI", button.affixName))
button:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
local color = AFFIXES[button.affixName].color or "|cffffffff"
GameTooltip:SetText(color .. MythicGetText("UI", button.affixName) .. "|r")
GameTooltip:AddLine(AFFIXES[button.affixName].description or "", 1, 1, 1, true)
GameTooltip:Show()
end)
end
end
end
if frame and frame.scoreButtons then
for i, button in ipairs(frame.scoreButtons) do
local mapId = DUNGEON_ORDER[i]
if mapId and DUNGEONS[mapId] then
button.nameLabel:SetText(DUNGEONS[mapId].name)
end
end
end
if frame and frame.leaderboardButtons then
for i, button in ipairs(frame.leaderboardButtons) do
local mapId = DUNGEON_ORDER[i]
if mapId then
button:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetText(MythicGetText("Dungeons", DUNGEONS[mapId].originalName))
GameTooltip:Show()
end)
end
end
end
if MythicPlusFrame:IsVisible() and MythicPlusFrame.currentTab then
SetActiveTab(MythicPlusFrame.currentTab)
end
end
end
local DUNGEONS = {
[574] = { originalName = "Utgarde Keep", name = "Utgarde Keep", icon = "Interface\\Icons\\achievement_boss_svalasorrowgrave" },
[575] = { originalName = "Utgarde Pinnacle", name = "Utgarde Pinnacle", icon = "Interface\\Icons\\achievement_boss_kingymiron" },
[576] = { originalName = "The Nexus", name = "The Nexus", icon = "Interface\\Icons\\spell_frost_frozencore" },
[578] = { originalName = "The Oculus", name = "The Oculus", icon = "Interface\\Icons\\achievement_boss_eregos" },
[595] = { originalName = "The Culling of Stratholme", name = "The Culling of Stratholme", icon = "Interface\\Icons\\achievement_dungeon_cotstratholme_normal" },
[599] = { originalName = "Halls of Stone", name = "Halls of Stone", icon = "Interface\\Icons\\achievement_boss_sjonnir" },
[600] = { originalName = "Drak'Tharon Keep", name = "Drak'Tharon Keep", icon = "Interface\\Icons\\inv_bone_skull_04" },
[601] = { originalName = "Azjol-Nerub", name = "Azjol-Nerub", icon = "Interface\\Icons\\inv_misc_head_nerubian_01" },
[602] = { originalName = "Halls of Lightning", name = "Halls of Lightning", icon = "Interface\\Icons\\achievement_boss_archaedas" },
[604] = { originalName = "Gundrak", name = "Gundrak", icon = "Interface\\Icons\\achievement_boss_galdarah" },
[608] = { originalName = "The Violet Hold", name = "The Violet Hold", icon = "Interface\\Icons\\achievement_reputation_kirintor" },
[619] = { originalName = "Ahn'kahet: The Old Kingdom", name = "Ahn'kahet: The Old Kingdom", icon = "Interface\\Icons\\achievement_boss_yoggsaron_01" },
[632] = { originalName = "The Forge of Souls", name = "The Forge of Souls", icon = "Interface\\Icons\\achievement_boss_devourerofsouls" },
[650] = { originalName = "Trial of the Champion", name = "Trial of the Champion", icon = "Interface\\Icons\\achievement_reputation_argentcrusader" },
[658] = { originalName = "Pit of Saron", name = "Pit of Saron", icon = "Interface\\Icons\\achievement_boss_scourgelordtyrannus" },
[668] = { originalName = "Halls of Reflection", name = "Halls of Reflection", icon = "Interface\\Icons\\achievement_dungeon_icecrown_frostmourne" },
}
AIO.Handle("AIO_Mythic", "RequestLocaleData", "Items")
AIO.Handle("AIO_Mythic", "RequestLocaleData", "Dungeons")
AIO.Handle("AIO_Mythic", "RequestLocaleData", "UI")
AIO.Handle("AIO_Mythic", "RequestRunState")
local DUNGEON_ORDER = {
574, 575, 576, 578,
595, 599, 600, 601,
602, 604, 608, 619,
632, 650, 658, 668
}
local AFFIXES = {
["Enrage"] = { icon = "Interface\\Icons\\spell_nature_shamanrage", color = "|cffff0000", description = function() return MythicGetText("UI", "Enrage Description") end },
["Rejuvenating"] = { icon = "Interface\\Icons\\ability_druid_empoweredrejuvination", color = "|cff00ff00", description = function() return MythicGetText("UI", "Rejuvenating Description") end },
["Turtling"] = { icon = "Interface\\Icons\\ability_warrior_shieldmastery", color = "|cffffff00", description = function() return MythicGetText("UI", "Turtling Description") end },
["Shamanism"] = { icon = "Interface\\Icons\\spell_fire_totemofwrath", color = "|cffa335ee", description = function() return MythicGetText("UI", "Shamanism Description") end },
["Magus"] = { icon = "Interface\\Icons\\ability_mage_hotstreak", color = "|cff3399ff", description = function() return MythicGetText("UI", "Magus Description") end },
["Priest Empowered"] = { icon = "Interface\\Icons\\spell_holy_searinglightpriest", color = "|cffcccccc", description = function() return MythicGetText("UI", "Priest Empowered Description") end },
["Demonism"] = { icon = "Interface\\Icons\\ability_warlock_demonicpower", color = "|cff8b0000", description = function() return MythicGetText("UI", "Demonism Description") end },
["Falling Stars"] = { icon = "Interface\\Icons\\ability_druid_starfall", color = "|cff66ccff", description = function() return MythicGetText("UI", "Falling Stars Description") end },
}
function MythicHandlers.ReceiveMapNameAndTier(_, mapName, tier)
local originalMapName = mapName
for id, dungeon in pairs(DUNGEONS) do
if dungeon.originalName == mapName then
mapName = MythicGetText("Dungeons", dungeon.originalName)
break
end
end
lastMapName = mapName
lastTierLevel = tier
if GameTooltip:IsShown() then
local name, link = GameTooltip:GetItem()
if link and name and (string.find(name, "Mythic Keystone") or string.find(name, MythicGetText("Items", "Mythic Keystone"))) then
GameTooltip:Hide()
GameTooltip:SetOwner(UIParent, "ANCHOR_CURSOR")
GameTooltip:SetHyperlink(link)
end
end
end
local lineAdded = false
function OnTooltipSetItem(tooltip)
local name, link = tooltip:GetItem()
local englishName = "Mythic Keystone"
local localizedName = MythicGetText("Items", "Mythic Keystone")
if not name or (not string.find(name, englishName) and not string.find(name, localizedName)) then
return
end
if link ~= lastKeystoneLink then
lastKeystoneLink = link
lastMapName = "Loading..."
lastTierLevel = "Loading..."
AIO.Handle("AIO_Mythic", "RequestMapNameAndTier")
end
local line = _G[tooltip:GetName() .. "TextLeft2"]
if line then
local tierText = lastTierLevel and lastTierLevel ~= "Loading..." and ("+" .. lastTierLevel) or ""
line:SetText("|cffa335ee" .. MythicGetText("UI", "Mythic") .. tierText .. " |r" .. (lastMapName or "Loading..."))
line:Show()
tooltip:Show()
end
end
local function OnTooltipCleared(tooltip)
lineAdded = false
end
GameTooltip:HookScript("OnTooltipSetItem", OnTooltipSetItem)
GameTooltip:HookScript("OnTooltipCleared", OnTooltipCleared)
local mythicMiniButton = CreateFrame("Button", "MythicPlusMiniButton", Minimap)
mythicMiniButton:SetSize(24, 24)
mythicMiniButton:SetFrameStrata("MEDIUM")
mythicMiniButton:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")
mythicMiniButton:SetNormalTexture("Interface\\AddOns\\Blizzard_AchievementUI\\UI-Achievement-MinimapButton")
mythicMiniButton:SetPushedTexture("Interface\\AddOns\\Blizzard_AchievementUI\\UI-Achievement-MinimapButton-Down")
local icon = mythicMiniButton:CreateTexture(nil, "ARTWORK")
icon:SetTexture("Interface\\Icons\\achievement_bg_wineos_underxminutes")
icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
icon:SetAllPoints(mythicMiniButton)
local border = mythicMiniButton:CreateTexture(nil, "OVERLAY")
border:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
border:SetSize(64, 64)
border:SetPoint("CENTER", mythicMiniButton, "CENTER", 12, -12)
mythicMiniButton:SetPoint("TOPLEFT", Minimap, "BOTTOMLEFT", -20, 70)
mythicMiniButton:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_LEFT")
GameTooltip:SetText(MythicGetText("UI", "Mythic+"))
if self.hasVaultLoot then
GameTooltip:AddLine(MythicGetText("UI", "There is loot in your Vault in Dalaran City"), 1, 1, 0)
end
GameTooltip:Show()
end)
mythicMiniButton:SetScript("OnLeave", GameTooltip_Hide)
mythicMiniButton:SetScript("OnClick", function()
if MythicPlusFrame:IsShown() then
PlaySound("igCharacterInfoClose")
MythicPlusFrame:Hide()
else
PlaySound("igCharacterInfoOpen")
MythicPlusFrame:Show()
end
end)
function MythicHandlers.ReceiveWeeklyAffixes(_, affix1, affix2, affix3)
local function colorize(name)
return (AFFIXES[name].color or "|cffffffff") .. MythicGetText("UI", name) .. "|r"
end
local text = MythicGetText("UI", "This week's affixes:") .. " " ..
colorize(affix1) .. ", " ..
colorize(affix2) .. ", " ..
colorize(affix3)
MythicPlusFrame.affixText:SetText(text)
MythicPlusFrame.currentAffixes = {affix1, affix2, affix3}
for _, button in ipairs(MythicPlusFrame.affixButtons) do
local name = button.affixName
local label = button.label
local isActive = name == affix1 or name == affix2 or name == affix3
label:SetText((isActive and "|cff00ff00" or "") .. MythicGetText("UI", name))
end
end
MythicPlusFrame = CreateFrame("Frame", "MythicPlusFrame", UIParent)
local frame = MythicPlusFrame
if localeDataReceived then
UpdateLocalizedElements()
end
frame:SetSize(720, 480)
frame:SetPoint("CENTER", UIParent, "CENTER", 270, 270)
frame:SetToplevel(true)
frame:SetClampedToScreen(true)
frame:SetMovable(true)
frame:EnableMouse(true)
frame:RegisterForDrag("LeftButton")
frame:SetScript("OnDragStart", frame.StartMoving)
frame:SetScript("OnHide", function(self)PlaySound("igCharacterInfoClose") self:StopMovingOrSizing() end)
frame:SetScript("OnDragStop", frame.StopMovingOrSizing)
for _, region in ipairs({frame:GetRegions()}) do
if region:GetObjectType() == "Texture" then
region:Hide()
end
end
local paperBG = frame:CreateTexture(nil, "BACKGROUND")
paperBG:SetTexture("Interface\\MythicPlus\\textures\\Paper")
paperBG:SetAllPoints(frame)
paperBG:SetTexCoord(0, 1, 75/1024, (1024-75)/1024)
local borderSize = 167
local borderCornerTexCoordW = 167/256
local borderCornerTexCoordH = 168/256
local borderExpansion = math.floor(borderSize * 0.1)
local topLeftCorner = frame:CreateTexture(nil, "ARTWORK")
topLeftCorner:SetTexture("Interface\\MythicPlus\\textures\\Border")
topLeftCorner:SetSize(borderSize, borderSize)
topLeftCorner:SetPoint("TOPLEFT", frame, "TOPLEFT", -borderExpansion, borderExpansion)
topLeftCorner:SetTexCoord(0, borderCornerTexCoordW, 0, borderCornerTexCoordH)
local topRightCorner = frame:CreateTexture(nil, "ARTWORK")
topRightCorner:SetTexture("Interface\\MythicPlus\\textures\\Border")
topRightCorner:SetSize(borderSize, borderSize)
topRightCorner:SetPoint("TOPRIGHT", frame, "TOPRIGHT", borderExpansion, borderExpansion)
topRightCorner:SetTexCoord(borderCornerTexCoordW, 0, 0, borderCornerTexCoordH)
local bottomLeftCorner = frame:CreateTexture(nil, "ARTWORK")
bottomLeftCorner:SetTexture("Interface\\MythicPlus\\textures\\Border")
bottomLeftCorner:SetSize(borderSize, borderSize)
bottomLeftCorner:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", -borderExpansion, -borderExpansion)
bottomLeftCorner:SetTexCoord(0, borderCornerTexCoordW, borderCornerTexCoordH, 0)
local bottomRightCorner = frame:CreateTexture(nil, "ARTWORK")
bottomRightCorner:SetTexture("Interface\\MythicPlus\\textures\\Border")
bottomRightCorner:SetSize(borderSize, borderSize)
bottomRightCorner:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", borderExpansion, -borderExpansion)
bottomRightCorner:SetTexCoord(borderCornerTexCoordW, 0, borderCornerTexCoordH, 0)
local topBorder = frame:CreateTexture(nil, "ARTWORK")
topBorder:SetTexture("Interface\\MythicPlus\\textures\\Border_Top")
topBorder:SetHeight(32)
topBorder:SetPoint("TOPLEFT", topLeftCorner, "TOPRIGHT", 0, 0)
topBorder:SetPoint("TOPRIGHT", topRightCorner, "TOPLEFT", 0, 0)
local topBorderWidth = 720 + (borderExpansion * 2) - (borderSize * 2)
local topTexCoordRight = math.min(1.0, topBorderWidth / 1024)
topBorder:SetTexCoord(0, topTexCoordRight, 0, 1)
local bottomBorder = frame:CreateTexture(nil, "ARTWORK")
bottomBorder:SetTexture("Interface\\MythicPlus\\textures\\Border_Bottom")
bottomBorder:SetHeight(32)
bottomBorder:SetPoint("BOTTOMLEFT", bottomLeftCorner, "BOTTOMRIGHT", 0, 0)
bottomBorder:SetPoint("BOTTOMRIGHT", bottomRightCorner, "BOTTOMLEFT", 0, 0)
local bottomTexCoordRight = math.min(1.0, topBorderWidth / 1024)
bottomBorder:SetTexCoord(0, bottomTexCoordRight, 0, 1)
local leftBorder = frame:CreateTexture(nil, "ARTWORK")
leftBorder:SetTexture("Interface\\MythicPlus\\textures\\Border_Left")
leftBorder:SetWidth(32)
leftBorder:SetPoint("TOPLEFT", topLeftCorner, "BOTTOMLEFT", -1, 0)
leftBorder:SetPoint("BOTTOMLEFT", bottomLeftCorner, "TOPLEFT", -1, 0)
local leftBorderHeight = 480 + (borderExpansion * 2) - (borderSize * 2)
local leftTexCoordBottom = math.min(1.0, leftBorderHeight / 1024)
leftBorder:SetTexCoord(0, 1, 0, leftTexCoordBottom)
local rightBorder = frame:CreateTexture(nil, "ARTWORK")
rightBorder:SetTexture("Interface\\MythicPlus\\textures\\Border_Right")
rightBorder:SetWidth(32)
rightBorder:SetPoint("TOPRIGHT", topRightCorner, "BOTTOMRIGHT", 1, 0)
rightBorder:SetPoint("BOTTOMRIGHT", bottomRightCorner, "TOPRIGHT", 1, 0)
local rightTexCoordBottom = math.min(1.0, leftBorderHeight / 1024)
rightBorder:SetTexCoord(0, 1, 0, rightTexCoordBottom)
table.insert(UISpecialFrames, "MythicPlusFrame")
frame:Hide()
local tabBackground = CreateFrame("Frame", nil, frame)
tabBackground:SetSize(120, 400)
tabBackground:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -20)
local function CreateStyledTabButton(parent, text, index, onClick)
local button = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
button:SetSize(100, 32)
button:SetPoint("TOPLEFT", parent, "TOPLEFT", 10, -20 - ((index - 1) * 35))
button:SetText(text)
button:SetNormalFontObject("GameFontNormal")
button:GetNormalTexture():SetVertexColor(0.8, 0.2, 0.2, 1)
button:GetHighlightTexture():SetVertexColor(1, 0.3, 0.3, 1)
button:GetPushedTexture():SetVertexColor(0.6, 0.1, 0.1, 1)
button.isSelected = false
button:SetScript("OnClick", function()
onClick(index)
end)
return button
end
local function CreateBannerTitle(parent, text, anchorPoint)
local banner = parent:CreateTexture(nil, "OVERLAY")
banner:SetTexture("Interface\\MythicPlus\\textures\\Banner")
banner:SetSize(256, 64)
banner:SetPoint("TOP", parent, "TOP", 40, anchorPoint)
local title = parent:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
title:SetPoint("CENTER", banner, "CENTER", 0, 0)
title:SetText(text)
title:SetFont("Fonts\\FRIZQT__.TTF", 20, "OUTLINE")
title:SetTextColor(1, 1, 1)
return banner, title
end
local overviewBanner, overviewTitle = CreateBannerTitle(frame, MythicGetText("UI", "Overview"), 0)
frame.overviewTitle = overviewTitle
frame.overviewBanner = overviewBanner
local scoreBanner, scoreTitle = CreateBannerTitle(frame, MythicGetText("UI", "Score"), 0)
frame.scoreTitle = scoreTitle
frame.scoreBanner = scoreBanner
scoreBanner:Hide()
scoreTitle:Hide()
local leaderboardBanner, leaderboardTitle = CreateBannerTitle(frame, MythicGetText("UI", "Leaderboard"), 0)
frame.leaderboardTitle = leaderboardTitle
frame.leaderboardBanner = leaderboardBanner
leaderboardBanner:Hide()
leaderboardTitle:Hide()
local affixText = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
affixText:SetPoint("TOP", overviewBanner, "BOTTOM", 0, -10)
affixText:SetJustifyH("CENTER")
affixText:SetFont("Fonts\\FRIZQT__.TTF", 14, "OUTLINE")
affixText:SetText(MythicGetText("UI", "This week's affixes:") .. " Loading...")
frame.affixText = affixText
local scoreText = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
scoreText:SetPoint("TOP", scoreBanner, "BOTTOM", 0, -10)
scoreText:SetText("Score: Loading...")
frame.scoreText = scoreText
scoreText:Hide()
local affixNames = {
"Enrage", "Rejuvenating", "Turtling", "Shamanism",
"Magus", "Priest Empowered", "Demonism", "Falling Stars"
}
frame.affixButtons = {}
local buttonSize = 80
local buttonSpacing = 30
local columns = 4
local totalWidth = columns * buttonSize + (columns - 1) * buttonSpacing
local startX = -(totalWidth / 2) + 40
for i, name in ipairs(affixNames) do
local button = CreateFrame("Button", nil, frame)
button:SetSize(buttonSize, buttonSize)
local row = math.floor((i - 1) / columns)
local col = (i - 1) % columns
button:SetPoint(
"TOP",
affixText,
"BOTTOM",
startX + col * (buttonSize + buttonSpacing),
-40 - row * (buttonSize + buttonSpacing)
)
local icon = button:CreateTexture(nil, "BACKGROUND")
icon:SetAllPoints()
icon:SetTexture(AFFIXES[name].icon or "Interface\\Icons\\spell_nature_polymorph")
local label = button:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
label:SetPoint("TOP", button, "BOTTOM", 0, -2)
label:SetFont("Fonts\\FRIZQT__.TTF", 12, "")
label:SetText(name)
button.affixName = name
button.label = label
button:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
local color = AFFIXES[name].color or "|cffffffff"
GameTooltip:SetText(color .. MythicGetText("UI", name) .. "|r")
local description = AFFIXES[name].description
if type(description) == "function" then
description = description()
end
GameTooltip:AddLine(description or "", 1, 1, 1, true)
GameTooltip:Show()
end)
button:SetScript("OnLeave", function() GameTooltip:Hide() end)
frame.affixButtons[i] = button
end
frame.scoreButtons = {}
local scoreButtonSize = 50
local scoreCols = 4
local scoreButtonSpacingX = 60
local scoreButtonSpacingY = 26
local scoreStartX = -(scoreCols * scoreButtonSize + (scoreCols - 1) * scoreButtonSpacingX) / 2 + 25
for i, mapId in ipairs(DUNGEON_ORDER) do
local name = DUNGEONS[mapId].name or ("Map " .. mapId)
local icon = DUNGEONS[mapId].icon or "Interface\\Icons\\inv_misc_questionmark"
local button = CreateFrame("Button", nil, frame)
button:SetSize(scoreButtonSize, scoreButtonSize)
local row = math.floor((i - 1) / scoreCols)
local col = (i - 1) % scoreCols
button:SetPoint(
"TOP",
scoreText,
"BOTTOM",
scoreStartX + col * (scoreButtonSize + scoreButtonSpacingX),
-20 - row * (scoreButtonSize + scoreButtonSpacingY)
)
local tex = button:CreateTexture(nil, "BACKGROUND")
tex:SetAllPoints()
tex:SetTexture(icon)
local scoreFontSize = 16
local scoreLabel = button:CreateFontString(nil, "OVERLAY")
scoreLabel:SetPoint("CENTER", button, "CENTER", 0, -15)
scoreLabel:SetFont("Fonts\\FRIZQT__.TTF", scoreFontSize, "OUTLINE, THICK")
scoreLabel:SetText("0")
button.scoreLabel = scoreLabel
local nameLabel = button:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
nameLabel:SetPoint("TOP", button, "BOTTOM", 0, 0)
nameLabel:SetWidth(scoreButtonSize + 40)
nameLabel:SetFont("Fonts\\FRIZQT__.TTF", 10, "OUTLINE")
nameLabel:SetWordWrap(true)
nameLabel:SetText(DUNGEONS[mapId].name or ("Map " .. mapId))
nameLabel:SetJustifyH("CENTER")
nameLabel:SetJustifyV("TOP")
button.nameLabel = nameLabel
button:Hide()
frame.scoreButtons[i] = button
end
frame.podiums = {}
local podiumSpecs = {
{ height = 60, color = {0.8, 0.8, 0.8,}, x = -140 },
{ height = 90, color = {0.95, 0.84, 0.0}, x = 0 },
{ height = 40, color = {0.72, 0.45, 0.2}, x = 140 },
}
for i, spec in ipairs(podiumSpecs) do
local podium = CreateFrame("Frame", nil, frame)
podium:SetSize(135, spec.height)
podium:SetPoint("BOTTOM", leaderboardBanner, "TOP", spec.x + 0, -200)
local bg = podium:CreateTexture(nil, "BACKGROUND")
bg:SetAllPoints()
bg:SetTexture(spec.color[1], spec.color[2], spec.color[3], 1)
local name = podium:CreateFontString(nil, "OVERLAY", "GameFontNormal")
name:SetPoint("BOTTOM", podium, "TOP", 0, 4)
name:SetText("")
podium.name = name
local score = podium:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
score:SetPoint("CENTER", podium, "CENTER")
score:SetText("0")
podium.score = score
podium:Hide()
frame.podiums[i] = podium
end
frame.leaderboardButtons = {}
local lbButtonSize = 53
local lbSpacingX = 20
local lbSpacingY = 15
local lbCols = 6
local lbStartX = -(lbCols * lbButtonSize + (lbCols - 1) * lbSpacingX) / 2 + 166
for i, mapId in ipairs(DUNGEON_ORDER) do
local button = CreateFrame("Button", nil, frame)
button:SetSize(lbButtonSize, lbButtonSize)
local row = math.floor((i - 1) / lbCols)
local col = (i - 1) % lbCols
button:SetPoint(
"TOP",
frame.podiums[1],
"BOTTOM",
lbStartX + col * (lbButtonSize + lbSpacingX),
-20 - row * (lbButtonSize + lbSpacingY)
)
local icon = button:CreateTexture(nil, "BACKGROUND")
icon:SetAllPoints()
icon:SetTexture(DUNGEONS[mapId].icon or "Interface\\Icons\\inv_misc_questionmark")
button:Hide()
frame.leaderboardButtons[i] = button
end
local tabs = {}
local function SetActiveTab(index)
PlaySound("igMainMenuOptionCheckBoxOn")
frame.currentTab = index
for i, tab in ipairs(tabs) do
if i == index then
tab.isSelected = true
tab:GetNormalTexture():SetVertexColor(1, 0.4, 0.4, 1)
tab:GetHighlightTexture():SetVertexColor(1, 0.5, 0.5, 1)
else
tab.isSelected = false
tab:GetNormalTexture():SetVertexColor(0.8, 0.2, 0.2, 1)
tab:GetHighlightTexture():SetVertexColor(1, 0.3, 0.3, 1)
end
end
local showOverview = index == 1
local showScore = index == 2
local showLeaderboard = index == 3
if showOverview then
frame.overviewBanner:Show()
frame.overviewTitle:Show()
frame.affixText:Show()
for _, button in ipairs(frame.affixButtons) do
button:Show()
end
else
frame.overviewBanner:Hide()
frame.overviewTitle:Hide()
frame.affixText:Hide()
for _, button in ipairs(frame.affixButtons) do
button:Hide()
end
end
if showScore then
frame.scoreBanner:Show()
frame.scoreTitle:Show()
frame.scoreText:Show()
for _, btn in ipairs(frame.scoreButtons) do
btn:Show()
end
AIO.Handle("AIO_Mythic", "RequestTotalPoints")
else
frame.scoreBanner:Hide()
frame.scoreTitle:Hide()
frame.scoreText:Hide()
for _, btn in ipairs(frame.scoreButtons) do
btn:Hide()
end
end
if showLeaderboard then
frame.leaderboardBanner:Show()
frame.leaderboardTitle:Show()
for _, podium in ipairs(frame.podiums) do podium:Show() end
for _, btn in ipairs(frame.leaderboardButtons) do btn:Show() end
AIO.Handle("AIO_Mythic", "RequestLeaderboard")
else
frame.leaderboardBanner:Hide()
frame.leaderboardTitle:Hide()
for _, podium in ipairs(frame.podiums) do podium:Hide() end
for _, btn in ipairs(frame.leaderboardButtons) do btn:Hide() end
end
if showOverview then
AIO.Handle("AIO_Mythic", "RequestWeeklyAffixes")
end
end
tabs[1] = CreateStyledTabButton(tabBackground, MythicGetText("UI", "Overview"), 1, SetActiveTab)
tabs[2] = CreateStyledTabButton(tabBackground, MythicGetText("UI", "Score"), 2, SetActiveTab)
tabs[3] = CreateStyledTabButton(tabBackground, MythicGetText("UI", "Leaderboard"), 3, SetActiveTab)
SetActiveTab(1)
function MythicHandlers.ReceiveLeaderboard(_, topThree, dungeonTop)
local visualToRank = {2, 1, 3}
for i = 1, 3 do
local rank = visualToRank[i]
local entry = topThree[rank]
local podium = frame.podiums[i]
if entry then
podium.name:SetText(entry.name)
podium.score:SetText(string.format("%.2f", entry.points))
podium.name:SetFont("Fonts\\FRIZQT__.TTF", 14, "OUTLINE, THICK")
podium.score:SetFont("Fonts\\FRIZQT__.TTF", 14, "OUTLINE")
else
podium.name:SetText("")
podium.score:SetText("0")
podium.name:SetFont("Fonts\\FRIZQT__.TTF", 14, "OUTLINE, THICK")
podium.score:SetFont("Fonts\\FRIZQT__.TTF", 14, "OUTLINE")
end
end
for i, mapId in ipairs(DUNGEON_ORDER) do
local top = dungeonTop[tostring(mapId)]
local button = frame.leaderboardButtons[i]
if button then
button:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetText(MythicGetText("Dungeons", DUNGEONS[mapId].originalName))
if top then
GameTooltip:AddLine(MythicGetText("UI", "Highest Score:"), 1, 1, 0)
GameTooltip:AddLine(" " .. top.name .. ": " .. top.score, 1, 1, 1)
if top.highestKey and top.highestKey > 0 then
local highestKeyText = MythicGetText("UI", "Highest Key +%d by:"):format(top.highestKey)
GameTooltip:AddLine(highestKeyText, 1, 1, 0)
if top.keyHolderNames and #top.keyHolderNames > 0 then
for _, memberName in ipairs(top.keyHolderNames) do
GameTooltip:AddLine(" " .. memberName, 0.8, 1, 0.8)
end
else
GameTooltip:AddLine(" " .. MythicGetText("UI", "Unknown"), 0.8, 1, 0.8)
end
else
GameTooltip:AddLine(MythicGetText("UI", "Highest Key: None completed in time"), 0.7, 0.7, 0.7)
end
else
GameTooltip:AddLine(MythicGetText("UI", "No records available"), 0.7, 0.7, 0.7)
end
GameTooltip:Show()
end)
button:SetScript("OnLeave", GameTooltip_Hide)
end
end
end
local affixNames = {
"Enrage", "Rejuvenating", "Turtling", "Shamanism",
"Magus", "Priest Empowered", "Demonism", "Falling Stars"
}
local tabs = {}
local function SetActiveTab(index)
PlaySound("igMainMenuOptionCheckBoxOn")
for i, tab in ipairs(tabs) do
tab.bg:SetTexture(i == index and 0.8 or 0.3, i == index and 0.8 or 0.3, i == index and 0.2 or 0.3, 0.5)
end
local showOverview = index == 1
local showScore = index == 2
local showLeaderboard = index == 3
if showOverview then
frame.overviewTitle:Show()
frame.affixText:Show()
for _, button in ipairs(frame.affixButtons) do
button:Show()
end
else
frame.overviewTitle:Hide()
frame.affixText:Hide()
for _, button in ipairs(frame.affixButtons) do
button:Hide()
end
end
if showScore then
frame.scoreTitle:Show()
frame.scoreText:Show()
for _, btn in ipairs(frame.scoreButtons) do
btn:Show()
end
AIO.Handle("AIO_Mythic", "RequestTotalPoints")
else
frame.scoreTitle:Hide()
frame.scoreText:Hide()
for _, btn in ipairs(frame.scoreButtons) do
btn:Hide()
end
end
if showLeaderboard then
frame.leaderboardTitle:Show()
for _, podium in ipairs(frame.podiums) do podium:Show() end
for _, btn in ipairs(frame.leaderboardButtons) do btn:Show() end
AIO.Handle("AIO_Mythic", "RequestLeaderboard")
else
frame.leaderboardTitle:Hide()
for _, podium in ipairs(frame.podiums) do podium:Hide() end
for _, btn in ipairs(frame.leaderboardButtons) do btn:Hide() end
end
if showOverview then
AIO.Handle("AIO_Mythic", "RequestWeeklyAffixes")
end
end
SetActiveTab(1)
function MythicHandlers.StartMythicTimerGUI(_, mapId, tier, duration, bossNames, potentialGain, enemiesRequired)
potentialGain = tonumber(potentialGain) or 0
enemiesRequired = tonumber(enemiesRequired) or 50
if type(bossNames) ~= "table" then bossNames = {} end
local maxDeaths = (tier == 1) and 6 or 4
WatchFrame:Hide(); WATCHFRAME_COLLAPSED = true
local baseHeight = 140 + #bossNames * 18
local frameHeight = (enemiesRequired > 0) and (baseHeight + 28) or baseHeight
local timerFrame = CreateFrame("Frame", nil, UIParent)
timerFrame:SetSize(320, frameHeight)
timerFrame:SetPoint("TOPRIGHT", UIParent, "TOPRIGHT", -20, -120)
timerFrame:SetMovable(true)
timerFrame:EnableMouse(true)
timerFrame:RegisterForDrag("LeftButton")
timerFrame:SetScript("OnDragStart", function(self) self:StartMoving() end)
timerFrame:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
local progressBar = timerFrame:CreateTexture(nil, "BACKGROUND")
progressBar:SetTexture("Interface\\MythicPlus\\textures\\MythicBar.blp")
progressBar:SetSize(0, 128)
progressBar:SetPoint("LEFT", timerFrame, "LEFT", 0, -10)
progressBar:SetTexCoord(0, 0, 0, 1)
progressBar:Hide()
local function updateProgress(killedBosses, totalBosses)
if totalBosses == 0 then return end
local progress = math.min(killedBosses / totalBosses, 1.0)
local maxWidth = 256
local currentWidth = maxWidth * progress
if progress > 0 then
progressBar:Show()
progressBar:SetWidth(currentWidth)
progressBar:SetTexCoord(0, progress, 0, 1)
else
progressBar:Hide()
end
end
local goldenFrame = timerFrame:CreateTexture(nil, "ARTWORK")
goldenFrame:SetTexture("Interface\\MythicPlus\\textures\\MythicFrame.blp")
goldenFrame:SetSize(256, 128)
goldenFrame:SetPoint("LEFT", timerFrame, "LEFT", 0, -10)
goldenFrame:SetTexCoord(0, 1, 0, 1)
local dungeonText = timerFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
dungeonText:SetPoint("TOP", goldenFrame, "TOP", 0, -12)
local dungeonName = (DUNGEONS[mapId] and DUNGEONS[mapId].name) or ("Map "..mapId)
dungeonText:SetFont("Fonts\\FRIZQT__.TTF", 16, "OUTLINE")
dungeonText:SetText(fmt("|cffFFD700%s|r", dungeonName))
local tierText = timerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
tierText:SetPoint("TOP", goldenFrame, "LEFT", 50, 26)
tierText:SetFont("Fonts\\FRIZQT__.TTF", 16, "")
tierText:SetText(fmt("|cffFFD700Level %d|r", tier))
local timerText = timerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
timerText:SetPoint("CENTER", goldenFrame, "LEFT", 48, -6)
timerText:SetFont("Fonts\\FRIZQT__.TTF", 20, "OUTLINE")
timerText:SetText(fmt("%02d:%02d", floor(duration/60), duration%60))
local deaths, penalty, bonus = 0, 0, 0
local scoreLabel = timerFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
scoreLabel:SetPoint("BOTTOM", goldenFrame, "BOTTOM", 60, 50)
local gold, red, green, reset = "|cffFFD700", "|cffff0000", "|cff33ff33", "|r"
local scoreStr = gold..potentialGain..reset.." "..gold.."("..reset..red.."-"..penalty..reset..gold.."/"..reset..green.."+"..bonus..reset..gold..")"..reset.." "..gold..deaths.."/"..maxDeaths..reset
scoreLabel:SetText(scoreStr)
local affixContainer = CreateFrame("Frame", nil, timerFrame)
affixContainer:SetSize(200, 30)
affixContainer:SetPoint("BOTTOM", scoreLabel, "TOP", 40, 11)
local affixIcons = {}
local currentAffixes = {}
if MythicPlusFrame and MythicPlusFrame.currentAffixes then
currentAffixes = MythicPlusFrame.currentAffixes
end
local numAffixes = math.min(tier, 4)
local iconSize = 20
local iconSpacing = 4
local totalWidth = (numAffixes * iconSize) + ((numAffixes - 1) * iconSpacing)
local startX = -totalWidth / 2
for i = 1, numAffixes do
local affixName = currentAffixes[i]
if affixName and AFFIXES[affixName] then
local icon = CreateFrame("Button", nil, affixContainer)
icon:SetSize(iconSize, iconSize)
icon:SetPoint("LEFT", affixContainer, "LEFT", startX + (i-1) * (iconSize + iconSpacing) + 30, -5)
local texture = icon:CreateTexture(nil, "ARTWORK")
texture:SetAllPoints()
texture:SetTexture(AFFIXES[affixName].icon)
icon:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_TOP")
GameTooltip:SetText(affixName)
GameTooltip:Show()
end)
icon:SetScript("OnLeave", function()
GameTooltip:Hide()
end)
affixIcons[i] = icon
end
end
local bossLabels = {}
for i, name in ipairs(bossNames) do
local lbl = timerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
lbl:SetPoint("TOPLEFT", goldenFrame, "BOTTOMLEFT", 20, 10 - (i-1)*16)
lbl:SetText(fmt("%d/%d %s", 0, 1, name))
lbl:SetTextColor(1, 0.82, 0)
lbl.bossName = name
bossLabels[i] = lbl
end
local enemyLabel, enemyProgressFrame, enemyPercentText
if enemiesRequired > 0 then
enemyLabel = timerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
enemyLabel:SetPoint("TOPLEFT", goldenFrame, "BOTTOMLEFT", 20, 10 - #bossNames*16)
enemyLabel:SetText("0/1 " .. MythicGetText("UI", "Enemy Forces"))
enemyLabel:SetTextColor(1, 0.82, 0)
enemyProgressFrame = CreateFrame("StatusBar", nil, timerFrame)
enemyProgressFrame:SetSize(200, 12)
enemyProgressFrame:SetPoint("TOPLEFT", enemyLabel, "BOTTOMLEFT", 0, -10)
enemyProgressFrame:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar")
enemyProgressFrame:SetStatusBarColor(0.2, 0.8, 0.2)
enemyProgressFrame:SetMinMaxValues(0, 100)
enemyProgressFrame:SetValue(0)
local enemyProgressBorder = CreateFrame("Frame", nil, timerFrame, BackdropTemplateMixin and "BackdropTemplate")
enemyProgressBorder:SetAllPoints(enemyProgressFrame)
enemyProgressBorder:SetBackdrop({
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
edgeSize = 8,
insets = { left = 1, right = 1, top = 1, bottom = 1 }
})
enemyProgressBorder:SetBackdropBorderColor(0.5, 0.5, 0.5, 1)
enemyPercentText = enemyProgressFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
enemyPercentText:SetPoint("CENTER", enemyProgressFrame, "CENTER")
enemyPercentText:SetText("0%")
end
local elapsed = 0
timerFrame:SetScript("OnUpdate", function(self, dt)
if self.stopped then return end
elapsed = elapsed + dt
local left = duration - elapsed
if left < 0 then left = 0 end
local m,s = floor(left/60), floor(left%60)
local ratio = left/duration
local color = "|cff00ff00"
if ratio < 0.3 then color = "|cffff0000"
elseif ratio < 0.6 then color = "|cffffff00" end
timerText:SetText(fmt("%s%02d:%02d|r", color, m, s))
end)
timerFrame:Show()
MythicBossTimerUI = {
frame = timerFrame,
timerText = timerText,
scoreLabel = scoreLabel,
labels = bossLabels,
progressBar = progressBar,
updateProgress = updateProgress,
totalBosses = #bossNames,
killedBosses = 0,
potentialGain = potentialGain,
penalty = 0,
bonus = 0,
deaths = 0,
maxDeaths = maxDeaths,
enemyLabel = enemyLabel,
enemyProgressFrame = enemyProgressFrame,
enemyPercentText = enemyPercentText,
enemiesRequired = enemiesRequired,
enemiesCurrent = 0
}
end
function MythicHandlers.UpdateMythicScore(_, newPenalty, newDeaths)
local ui = MythicBossTimerUI
if not ui or not ui.scoreLabel then return end
ui.penalty = tonumber(newPenalty) or ui.penalty
ui.deaths = tonumber(newDeaths) or ui.deaths
local gold = "|cffcc9933"
local red = "|cffff0000"
local green = "|cff33ff33"
local reset = "|r"
local scoreStr =
gold..ui.potentialGain..reset.." "..
gold.."("..reset..
red.."-"..ui.penalty..reset..
gold.."/"..reset..
green.."+"..ui.bonus..reset..
gold..")"..reset.." "..
gold..ui.deaths.."/"..ui.maxDeaths..reset
ui.scoreLabel:SetText(scoreStr)
end
function MythicHandlers.FinalizeMythicScore(_, finalPenalty, finalDeaths, finalBonus)
local ui = MythicBossTimerUI
if not ui or not ui.scoreLabel then return end
ui.penalty = tonumber(finalPenalty) or ui.penalty
ui.deaths = tonumber(finalDeaths) or ui.deaths
ui.bonus = tonumber(finalBonus) or ui.bonus
local gold = "|cffcc9933"
local red = "|cffff0000"
local green = "|cff33ff33"
local reset = "|r"
local scoreStr =
gold..ui.potentialGain..reset.." "..
gold.."("..reset..
red.."-"..ui.penalty..reset..
gold.."/"..reset..
green.."+"..ui.bonus..reset..
gold..")"..reset.." "..
gold..ui.deaths.."/"..ui.maxDeaths..reset
ui.scoreLabel:SetText(scoreStr)
end
function MythicHandlers.MarkBossKilled(_, mapId, bossIndex)
local ui = MythicBossTimerUI
if not ui or not ui.labels then return end
local lbl = ui.labels[bossIndex]
if lbl and lbl.bossName then
lbl:SetText(fmt("|cff26c426%d/%d %s|r", 1, 1, lbl.bossName))
ui.killedBosses = ui.killedBosses + 1
if ui.updateProgress then
ui.updateProgress(ui.killedBosses, ui.totalBosses)
end
end
end
function MythicHandlers.StopMythicTimerGUI(_, remaining)
local ui = MythicBossTimerUI
if ui and ui.timerText then
if type(remaining) == "number" then
local m, s = floor(remaining/60), floor(remaining%60)
ui.timerText:SetText(fmt("|cffffff00%02d:%02d|r", m, s))
end
ui.frame.stopped = true
end
end
function MythicHandlers.KillMythicTimerGUI()
WatchFrame:Show(); WATCHFRAME_COLLAPSED = nil
if MythicBossTimerUI and MythicBossTimerUI.frame then
MythicBossTimerUI.frame.stopped = true
MythicBossTimerUI.frame:Hide()
MythicBossTimerUI.frame:SetScript("OnUpdate", nil)
MythicBossTimerUI.frame:SetParent(nil)
MythicBossTimerUI.frame = nil
end
MythicBossTimerUI = nil
end
function MythicHandlers.StartCountdown(_, seconds)
seconds = tonumber(seconds) or 10
if CountdownFrame then
CountdownFrame:Hide()
CountdownFrame:SetScript("OnUpdate", nil)
end
if not CountdownFrame then
local frame = CreateFrame("Frame", "CountdownFrame", UIParent)
frame:SetSize(512, 256)
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 250)
frame:SetFrameStrata("FULLSCREEN_DIALOG")
frame:Hide()
frame.digit1 = frame:CreateTexture(nil, "ARTWORK")
frame.digit1:SetSize(256, 170)
frame.digit1:SetPoint("CENTER", frame, "CENTER", -70, 0)
frame.digit1:SetTexture("Interface\\MythicPlus\\textures\\BigTimerNumbers")
frame.digit2 = frame:CreateTexture(nil, "ARTWORK")
frame.digit2:SetSize(256, 170)
frame.digit2:SetPoint("CENTER", frame, "CENTER", 70, 0)
frame.digit2:SetTexture("Interface\\MythicPlus\\textures\\BigTimerNumbers")
CountdownFrame = frame
end
local frame = CountdownFrame
frame:Show()
local function setDigits(num)
local texW, texH = 1024, 512
local digitW, digitH = 256, 170
local columns = 4
local n1 = math.floor(num / 10)
local n2 = num % 10
local function setDigit(tex, digit)
local col = digit % columns
local row = math.floor(digit / columns)
local l = (col * digitW) / texW
local r = ((col + 1) * digitW) / texW
local t = (row * digitH) / texH
local b = ((row + 1) * digitH) / texH
tex:SetTexCoord(l, r, t, b)
tex:Show()
end
if n1 > 0 then
setDigit(frame.digit1, n1)
frame.digit1:Show()
frame.digit2:SetPoint("CENTER", frame, "CENTER", 70, 0)
else
frame.digit1:Hide()
frame.digit2:SetPoint("CENTER", frame, "CENTER", 0, 0)
end
setDigit(frame.digit2, n2)
end
setDigits(seconds)
PlaySoundFile("Interface\\MythicPlus\\sounds\\UI_BattlegroundCountdown_Timer.ogg", "master")
local remaining = seconds
frame:SetScript("OnUpdate", function(self, elapsed)
if not self.lastUpdate then self.lastUpdate = 0 end
self.lastUpdate = self.lastUpdate + elapsed
if self.lastUpdate >= 1 then
self.lastUpdate = self.lastUpdate - 1
remaining = remaining - 1
if remaining > 0 then
setDigits(remaining)
PlaySoundFile("Interface\\MythicPlus\\sounds\\UI_BattlegroundCountdown_Timer.ogg", "master")
else
PlaySoundFile("Interface\\MythicPlus\\sounds\\UI_BattlegroundCountdown_End.ogg", "master")
self:Hide()
self:SetScript("OnUpdate", nil)
end
end
end)
end
function MythicHandlers.UpdateVaultStatus(_, hasLoot)
if hasLoot then
mythicMiniButton.hasVaultLoot = true
if not mythicMiniButton.glowTexture then
mythicMiniButton.glowTexture = mythicMiniButton:CreateTexture(nil, "OVERLAY")
mythicMiniButton.glowTexture:SetTexture("Interface\\SpellActivationOverlay\\IconAlert")
mythicMiniButton.glowTexture:SetSize(48, 48)
mythicMiniButton.glowTexture:SetPoint("CENTER")
mythicMiniButton.glowTexture:SetBlendMode("ADD")
end
mythicMiniButton.glowTexture:Show()
else
mythicMiniButton.hasVaultLoot = false
if mythicMiniButton.glowTexture then
mythicMiniButton.glowTexture:Hide()
end
end
end
function MythicHandlers.QueryItemData(_, item1, item2, item3)
if not MythicHiddenTooltip then
MythicHiddenTooltip = CreateFrame("GameTooltip", "MythicHiddenTooltip", nil, "GameTooltipTemplate")
MythicHiddenTooltip:SetOwner(UIParent, "ANCHOR_NONE")
end
local function QueryItem(itemId)
if itemId and itemId > 0 then
MythicHiddenTooltip:SetHyperlink("item:"..itemId..":0:0:0:0:0:0:0")
MythicHiddenTooltip:Show()
end
end
if item1 and item1 > 0 then
QueryItem(item1)
end
if item2 and item2 > 0 then
local item2Timer = CreateFrame("Frame")
item2Timer.elapsed = 0
item2Timer:SetScript("OnUpdate", function(self, elapsed)
self.elapsed = self.elapsed + elapsed
if self.elapsed >= 0.1 then
QueryItem(item2)
self:SetScript("OnUpdate", nil)
end
end)
end
if item3 and item3 > 0 then
local item3Timer = CreateFrame("Frame")
item3Timer.elapsed = 0
item3Timer:SetScript("OnUpdate", function(self, elapsed)
self.elapsed = self.elapsed + elapsed
if self.elapsed >= 0.2 then
QueryItem(item3)
self:SetScript("OnUpdate", nil)
end
end)
end
end
function MythicHandlers.ShowVaultGUI(_, item1, item2, item3, tier1, tier2, tier3)
AIO.Handle("AIO_Mythic", "QueryItemData", item1, item2, item3)
if VaultFrame then
VaultFrame:Hide()
end
VaultFrame = CreateFrame("Frame", "MythicVaultFrame", UIParent)
VaultFrame:SetSize(600, 450)
VaultFrame:SetPoint("CENTER")
VaultFrame:SetToplevel(true)
local vaultBG = VaultFrame:CreateTexture(nil, "BACKGROUND")
vaultBG:SetTexture("Interface\\MythicPlus\\textures\\VaultFrame")
vaultBG:SetAllPoints(VaultFrame)
vaultBG:SetTexCoord(0, 1, 177/1024, (1024-177)/1024)
local title = VaultFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
title:SetPoint("TOP", VaultFrame, "TOP", 0, -40)
title:SetText(MythicGetText("UI", "Mythic+ Vault"))
title:SetFont("Fonts\\FRIZQT__.TTF", 20, "OUTLINE")
title:SetTextColor(1, 0.82, 0)
local subtitle = VaultFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
subtitle:SetPoint("TOP", title, "BOTTOM", 0, -2)
subtitle:SetText(MythicGetText("UI", "Choose item reward"))
subtitle:SetFont("Fonts\\FRIZQT__.TTF", 14, "OUTLINE")
subtitle:SetTextColor(0.9, 0.9, 0.9)
local items = {item1, item2, item3}
local tiers = {tier1, tier2, tier3}
local selectedIndex = nil
local itemButtons = {}
for i = 1, 3 do
if items[i] and items[i] > 0 then
local button = CreateFrame("Button", nil, VaultFrame)
button:SetSize(72, 72)
button:SetPoint("TOP", subtitle, "BOTTOM", -190 + (i-1)*190, -80)
local icon = button:CreateTexture(nil, "ARTWORK")
icon:SetAllPoints(button)
button.icon = icon
local itemTexture = GetItemIcon(items[i])
if itemTexture then
icon:SetTexture(itemTexture)
else
icon:SetTexture("Interface\\Icons\\inv_misc_questionmark")
end
local tierLabel = button:CreateFontString(nil, "OVERLAY", "GameFontNormal")
tierLabel:SetPoint("TOP", button, "BOTTOM", 0, -5)
tierLabel:SetText(MythicGetText("UI", "Tier") .. " " .. (tiers[i] or "?"))
tierLabel:SetFont("Fonts\\FRIZQT__.TTF", 12, "OUTLINE")
tierLabel:SetTextColor(1, 0.82, 0)
button.tierLabel = tierLabel
button:SetScript("OnClick", function(self)
selectedIndex = i
for j, btn in ipairs(itemButtons) do
if j == i then
btn.icon:SetDesaturated(false)
btn.tierLabel:SetTextColor(1, 0.82, 0)
else
btn.icon:SetDesaturated(true)
btn.tierLabel:SetTextColor(0.5, 0.5, 0.5)
end
end
if VaultFrame.confirmButton then
VaultFrame.confirmButton:Enable()
VaultFrame.confirmButton:SetText("Confirm Selection")
end
if VaultFrame.selectionText then
local itemName, itemLink, itemRarity = GetItemInfo(items[i])
if itemLink then
VaultFrame.selectionText:SetText("Selected: " .. itemLink)
else
VaultFrame.selectionText:SetText("Selected: |cffffffff[Unknown Item]|r")
end
VaultFrame.selectionText:SetTextColor(1, 0.82, 0)
end
end)
button:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
local itemLink = select(2, GetItemInfo(items[i]))
if itemLink then
GameTooltip:SetHyperlink(tostring(itemLink))
else
print("Item link not found for item ID:", items[i])
local tooltipTimer = CreateFrame("Frame")
tooltipTimer.elapsed = 0
tooltipTimer:SetScript("OnUpdate", function(frame, elapsed)
frame.elapsed = frame.elapsed + elapsed
if frame.elapsed >= 0.1 then
local link = select(2, GetItemInfo(items[i]))
if link and GameTooltip:IsOwned(self) then
GameTooltip:SetHyperlink(link)
end
frame:SetScript("OnUpdate", nil)
end
end)
end
GameTooltip:Show()
if selectedIndex ~= i then
if not self.highlightTexture then
self.highlightTexture = self:CreateTexture(nil, "HIGHLIGHT")
self.highlightTexture:SetTexture("Interface\\Buttons\\ButtonHilight-Square")
self.highlightTexture:SetAllPoints(self)
self.highlightTexture:SetBlendMode("ADD")
self.highlightTexture:SetVertexColor(1, 1, 1, 0.3)
end
self.highlightTexture:Show()
end
end)
button:SetScript("OnLeave", function(self)
GameTooltip_Hide()
if self.highlightTexture then
self.highlightTexture:Hide()
end
end)
button:SetScript("OnMouseDown", function(self)
icon:SetPoint("TOPLEFT", 1, -1)
icon:SetPoint("BOTTOMRIGHT", 1, -1)
end)
button:SetScript("OnMouseUp", function(self)
icon:SetAllPoints(self)
end)
itemButtons[i] = button
end
end
local selectionText = VaultFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
selectionText:SetPoint("TOP", VaultFrame, "TOP", 0, -300)
selectionText:SetText(MythicGetText("UI", "No item selected"))
selectionText:SetTextColor(1, 0.82, 0)
selectionText:SetFont("Fonts\\FRIZQT__.TTF", 14, "")
VaultFrame.selectionText = selectionText
local confirmButton = CreateFrame("Button", nil, VaultFrame, "UIPanelButtonTemplate")
confirmButton:SetSize(140, 30)
confirmButton:SetPoint("BOTTOM", VaultFrame, "BOTTOM", 0, 40)
confirmButton:SetText(MythicGetText("UI", "Select an Item"))
confirmButton:Disable()
VaultFrame.confirmButton = confirmButton
confirmButton:SetScript("OnClick", function(self)
if selectedIndex then
AIO.Handle("AIO_Mythic", "SelectVaultItem", selectedIndex)
VaultFrame:Hide()
end
end)
local cancelButton = CreateFrame("Button", nil, VaultFrame, "UIPanelButtonTemplate")
cancelButton:SetSize(100, 30)
cancelButton:SetPoint("BOTTOMLEFT", VaultFrame, "BOTTOMLEFT", 20, 40)
cancelButton:SetText(MythicGetText("UI", "Cancel"))
cancelButton:SetScript("OnClick", function(self)
VaultFrame:Hide()
end)
VaultFrame:SetScript("OnHide", function(self)
selectedIndex = nil
end)
VaultFrame:Show()
end
function MythicHandlers.CloseVaultGUI()
if VaultFrame then
VaultFrame:Hide()
end
end
function MythicHandlers.UpdateEnemyForces(_, current, required, percentage, completed)
local ui = MythicBossTimerUI
if not ui or not ui.enemyLabel then return end
ui.enemiesCurrent = current
ui.enemiesRequired = required
local completedText = completed and "1" or "0"
ui.enemyLabel:SetText(fmt("%s/1 %s", completedText, MythicGetText("UI", "Enemy Forces")))
ui.enemyProgressFrame:SetValue(percentage)
ui.enemyPercentText:SetText(fmt("%.0f%%", percentage))
if completed then
ui.enemyLabel:SetTextColor(0.15, 0.76, 0.15)
else
ui.enemyLabel:SetTextColor(1, 0.82, 0)
end
end
function MythicHandlers.ReceiveTotalPoints(_, totalPoints, dungeonScores)
if not frame.scoreText then return end
frame.scoreText:SetText(MythicGetText("UI", "Total Score:") .. " " .. string.format("%.2f", totalPoints or 0))
for i, mapId in ipairs(DUNGEON_ORDER) do
local button = frame.scoreButtons[i]
if button and button.scoreLabel then
local score = dungeonScores and dungeonScores[tostring(mapId)] or 0
button.scoreLabel:SetText(tostring(score))
if button.nameLabel and DUNGEONS[mapId] then
button.nameLabel:SetText(MythicGetText("Dungeons", DUNGEONS[mapId].originalName))
end
end
end
end
function MythicHandlers.RestoreRunState(_, runState)
if not runState or not runState.active then
MythicPlusCharRunState = {
active = false,
mapId = nil,
tier = nil,
duration = nil,
elapsed = nil,
bossNames = {},
killedBosses = {},
potentialGain = 0,
penalty = 0,
bonus = 0,
deaths = 0,
maxDeaths = 0,
enemyForces = {
current = 0,
required = 0,
percentage = 0,
completed = false
},
saveTime = nil
}
return
end
MythicPlusCharRunState = runState
MythicPlusCharRunState.saveTime = GetTime()
MythicHandlers.StartMythicTimerGUI(nil, runState.mapId, runState.tier, runState.duration - runState.elapsed, runState.bossNames, runState.potentialGain, runState.enemyForces.required)
if MythicBossTimerUI then
MythicBossTimerUI.deaths = runState.deaths
MythicBossTimerUI.penalty = runState.penalty
MythicBossTimerUI.maxDeaths = runState.maxDeaths
MythicHandlers.UpdateMythicScore(nil, runState.penalty, runState.deaths)
for _, bossIndex in ipairs(runState.killedBosses) do
MythicHandlers.MarkBossKilled(nil, runState.mapId, bossIndex)
end
if runState.enemyForces then
MythicHandlers.UpdateEnemyForces(nil, runState.enemyForces.current, runState.enemyForces.required, runState.enemyForces.percentage, runState.enemyForces.completed)
end
if runState.overtime then
MythicHandlers.StartOvertimeMode()
end
end
end
function MythicHandlers.ClearRunState()
MythicPlusCharRunState = {
active = false,
mapId = nil,
tier = nil,
duration = nil,
elapsed = nil,
bossNames = {},
killedBosses = {},
potentialGain = 0,
penalty = 0,
bonus = 0,
deaths = 0,
maxDeaths = 0,
enemyForces = {
current = 0,
required = 0,
percentage = 0,
completed = false
},
saveTime = nil
}
end
function MythicHandlers.StartOvertimeMode()
if MythicBossTimerUI and MythicBossTimerUI.timerText then
MythicBossTimerUI.timerText:SetText("|cffff0000OVERTIME|r")
MythicBossTimerUI.frame.stopped = true
end
end