Skip to content

Instantly share code, notes, and snippets.

@LiQiuDGG
Last active December 25, 2025 20:44
Show Gist options
  • Select an option

  • Save LiQiuDGG/20e86415baf043cc268ac64e70dd5b5e to your computer and use it in GitHub Desktop.

Select an option

Save LiQiuDGG/20e86415baf043cc268ac64e70dd5b5e to your computer and use it in GitHub Desktop.
QuaziiUI Main Tank Frames - Implementation with Tank Target Display

QuaziiUI - Main Tank Frames

Adds main tank unit frames with paired target display for raid tank monitoring.

[Tank1 Health] [Tank1's Target]
[Tank2 Health] [Tank2's Target]
[Tank3 Health] [Tank3's Target]

Implementation

1. Add Default Settings

File: utils/quicore_main.lua (add after boss settings, around line 1350)

-- Main Tank frames (for raid tank monitoring)
maintank = {
    enabled = false,  -- Disabled by default
    maxFrames = 4,    -- How many MT frame pairs to create (1-8)
    spacing = 4,      -- Vertical spacing between rows

    -- Tank frame settings
    width = 120,
    height = 28,
    offsetX = -600,
    offsetY = 200,
    texture = "Quazii v5",
    useClassColor = true,
    customHealthColor = { 0.2, 0.6, 0.2, 1 },

    -- Name text
    showName = true,
    nameTextUseClassColor = false,
    nameTextColor = { 1, 1, 1, 1 },
    nameFontSize = 11,
    nameAnchor = "LEFT",
    nameOffsetX = 4,
    nameOffsetY = 0,
    maxNameLength = 8,

    -- Health text
    showHealth = true,
    healthDisplayStyle = "percent",  -- "percent", "absolute", "both"
    healthFontSize = 11,
    healthAnchor = "RIGHT",
    healthOffsetX = -4,
    healthOffsetY = 0,
    healthTextUseClassColor = false,
    healthTextColor = { 1, 1, 1, 1 },

    -- Power bar (usually disabled for compact MT frames)
    showPowerBar = false,
    powerBarHeight = 3,

    -- Target frame settings
    showTarget = true,
    targetWidth = 120,
    targetHeight = 28,
    targetSpacing = 2,  -- Horizontal gap between tank and target frames
    targetTexture = "Quazii v5 Inverse",
    targetUseClassColor = false,
    targetUseHostilityColor = true,  -- Red/yellow/green based on mob hostility
    targetCustomHealthColor = { 0.8, 0.2, 0.2, 1 },

    -- Target name text
    targetShowName = true,
    targetNameFontSize = 11,
    targetNameAnchor = "LEFT",
    targetNameOffsetX = 4,
    targetMaxNameLength = 10,

    -- Target health text
    targetShowHealth = true,
    targetHealthDisplayStyle = "percent",
    targetHealthFontSize = 11,
    targetHealthAnchor = "RIGHT",
    targetHealthOffsetX = -4,
},

2. Create Frame Functions

File: utils/qui_unitframes.lua (add after CreateBossFrame function, around line 1150)

---------------------------------------------------------------------------
-- CREATE: Main Tank Frame
---------------------------------------------------------------------------
local function CreateMainTankFrame(unit, frameKey, mtIndex)
    local settings = GetUnitSettings("maintank")
    local general = GetGeneralSettings()

    if not settings then return nil end

    local frameName = "QUI_MainTank" .. mtIndex
    local frame = CreateFrame("Button", frameName, UIParent, "SecureUnitButtonTemplate, BackdropTemplate")

    frame.unit = unit  -- "maintank1", "maintank2", etc.
    frame.unitKey = "maintank"
    frame.mtIndex = mtIndex

    -- Size and position
    local width = Scale(settings.width or 120)
    local height = Scale(settings.height or 28)
    frame:SetSize(width, height)

    -- Position (first frame uses offsetX/Y, others stack below)
    if mtIndex == 1 then
        local offsetX = Scale(settings.offsetX or -600)
        local offsetY = Scale(settings.offsetY or 200)
        frame:SetPoint("CENTER", UIParent, "CENTER", offsetX, offsetY)
    end

    frame:SetMovable(true)
    frame:SetClampedToScreen(true)

    -- Secure unit attributes
    frame:SetAttribute("unit", unit)
    frame:SetAttribute("*type1", "target")
    frame:SetAttribute("*type2", "togglemenu")
    frame:RegisterForClicks("AnyUp")

    -- Tooltip
    frame:HookScript("OnEnter", function(self) ShowUnitTooltip(self) end)
    frame:HookScript("OnLeave", HideUnitTooltip)

    -- Visibility: show when this maintank exists
    RegisterStateDriver(frame, "visibility", "[@" .. unit .. ",exists] show; hide")

    -- Background
    local bgColor = { 0.1, 0.1, 0.1, 0.9 }
    if general and general.darkMode then
        bgColor = general.darkModeBgColor or { 0.25, 0.25, 0.25, 1 }
    end

    local borderSize = Scale(1)
    frame:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        edgeSize = borderSize,
    })
    frame:SetBackdropColor(bgColor[1], bgColor[2], bgColor[3], bgColor[4] or 1)
    frame:SetBackdropBorderColor(0, 0, 0, 1)

    -- Health bar
    local powerHeight = settings.showPowerBar and Scale(settings.powerBarHeight or 3) or 0
    local separatorHeight = (settings.showPowerBar and settings.powerBarBorder ~= false) and 1 or 0
    local healthBar = CreateFrame("StatusBar", nil, frame)
    healthBar:SetPoint("TOPLEFT", frame, "TOPLEFT", borderSize, -borderSize)
    healthBar:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -borderSize, borderSize + powerHeight + separatorHeight)
    healthBar:SetStatusBarTexture(GetTexturePath(settings.texture))
    healthBar:SetMinMaxValues(0, 100)
    healthBar:SetValue(100)
    healthBar:EnableMouse(false)
    frame.healthBar = healthBar

    -- Name text
    local nameText = healthBar:CreateFontString(nil, "OVERLAY")
    nameText:SetFont(GetFontPath(), settings.nameFontSize or 11, GetFontOutline())
    nameText:SetTextColor(unpack(settings.nameTextColor or {1,1,1,1}))
    nameText:SetShadowOffset(1, -1)
    local nameAnchorInfo = GetTextAnchorInfo(settings.nameAnchor or "LEFT")
    nameText:SetPoint(nameAnchorInfo.point, healthBar, nameAnchorInfo.point,
        Scale(settings.nameOffsetX or 4), Scale(settings.nameOffsetY or 0))
    nameText:SetJustifyH(nameAnchorInfo.justify)
    frame.nameText = nameText

    -- Health text
    local healthText = healthBar:CreateFontString(nil, "OVERLAY")
    healthText:SetFont(GetFontPath(), settings.healthFontSize or 11, GetFontOutline())
    healthText:SetTextColor(unpack(settings.healthTextColor or {1,1,1,1}))
    healthText:SetShadowOffset(1, -1)
    local healthAnchorInfo = GetTextAnchorInfo(settings.healthAnchor or "RIGHT")
    healthText:SetPoint(healthAnchorInfo.point, healthBar, healthAnchorInfo.point,
        Scale(settings.healthOffsetX or -4), Scale(settings.healthOffsetY or 0))
    healthText:SetJustifyH(healthAnchorInfo.justify)
    frame.healthText = healthText

    -- Power bar (optional)
    if settings.showPowerBar then
        local powerBar = CreateFrame("StatusBar", nil, frame)
        powerBar:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", borderSize, borderSize)
        powerBar:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -borderSize, borderSize)
        powerBar:SetHeight(powerHeight)
        powerBar:SetStatusBarTexture(GetTexturePath(settings.texture))
        powerBar:SetMinMaxValues(0, 100)
        powerBar:SetValue(100)
        frame.powerBar = powerBar
    end

    -- Register events
    frame:RegisterEvent("UNIT_HEALTH")
    frame:RegisterEvent("UNIT_MAXHEALTH")
    frame:RegisterEvent("UNIT_NAME_UPDATE")
    frame:RegisterEvent("GROUP_ROSTER_UPDATE")
    if settings.showPowerBar then
        frame:RegisterEvent("UNIT_POWER_UPDATE")
        frame:RegisterEvent("UNIT_MAXPOWER")
    end

    frame:SetScript("OnEvent", function(self, event, arg1)
        if arg1 == self.unit or event == "GROUP_ROSTER_UPDATE" then
            UpdateMainTankFrame(self)
        end
    end)

    return frame
end

---------------------------------------------------------------------------
-- CREATE: Main Tank Target Frame
---------------------------------------------------------------------------
local function CreateMainTankTargetFrame(unit, frameKey, mtIndex, parentFrame)
    local settings = GetUnitSettings("maintank")
    local general = GetGeneralSettings()

    if not settings or not settings.showTarget then return nil end

    local frameName = "QUI_MainTank" .. mtIndex .. "Target"
    local frame = CreateFrame("Button", frameName, UIParent, "SecureUnitButtonTemplate, BackdropTemplate")

    frame.unit = unit  -- "maintank1target", "maintank2target", etc.
    frame.unitKey = "maintanktarget"
    frame.mtIndex = mtIndex

    -- Size
    local width = Scale(settings.targetWidth or 120)
    local height = Scale(settings.targetHeight or 28)
    frame:SetSize(width, height)

    -- Position: anchored to right of parent MT frame
    local targetSpacing = Scale(settings.targetSpacing or 2)
    frame:SetPoint("LEFT", parentFrame, "RIGHT", targetSpacing, 0)

    frame:SetMovable(false)  -- Moves with parent

    -- Secure unit attributes
    frame:SetAttribute("unit", unit)
    frame:SetAttribute("*type1", "target")
    frame:SetAttribute("*type2", "togglemenu")
    frame:RegisterForClicks("AnyUp")

    -- Tooltip
    frame:HookScript("OnEnter", function(self) ShowUnitTooltip(self) end)
    frame:HookScript("OnLeave", HideUnitTooltip)

    -- Visibility: show when maintankN's target exists
    RegisterStateDriver(frame, "visibility", "[@" .. unit .. ",exists] show; hide")

    -- Background
    local bgColor = { 0.1, 0.1, 0.1, 0.9 }
    if general and general.darkMode then
        bgColor = general.darkModeBgColor or { 0.25, 0.25, 0.25, 1 }
    end

    local borderSize = Scale(1)
    frame:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        edgeSize = borderSize,
    })
    frame:SetBackdropColor(bgColor[1], bgColor[2], bgColor[3], bgColor[4] or 1)
    frame:SetBackdropBorderColor(0, 0, 0, 1)

    -- Health bar
    local healthBar = CreateFrame("StatusBar", nil, frame)
    healthBar:SetPoint("TOPLEFT", frame, "TOPLEFT", borderSize, -borderSize)
    healthBar:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -borderSize, borderSize)
    healthBar:SetStatusBarTexture(GetTexturePath(settings.targetTexture or settings.texture))
    healthBar:SetMinMaxValues(0, 100)
    healthBar:SetValue(100)
    healthBar:EnableMouse(false)
    frame.healthBar = healthBar

    -- Name text
    local nameText = healthBar:CreateFontString(nil, "OVERLAY")
    nameText:SetFont(GetFontPath(), settings.targetNameFontSize or 11, GetFontOutline())
    nameText:SetTextColor(1, 1, 1, 1)
    nameText:SetShadowOffset(1, -1)
    nameText:SetPoint("LEFT", healthBar, "LEFT", Scale(settings.targetNameOffsetX or 4), 0)
    nameText:SetJustifyH("LEFT")
    frame.nameText = nameText

    -- Health text
    local healthText = healthBar:CreateFontString(nil, "OVERLAY")
    healthText:SetFont(GetFontPath(), settings.targetHealthFontSize or 11, GetFontOutline())
    healthText:SetTextColor(1, 1, 1, 1)
    healthText:SetShadowOffset(1, -1)
    healthText:SetPoint("RIGHT", healthBar, "RIGHT", Scale(settings.targetHealthOffsetX or -4), 0)
    healthText:SetJustifyH("RIGHT")
    frame.healthText = healthText

    -- Register events
    frame:RegisterEvent("UNIT_HEALTH")
    frame:RegisterEvent("UNIT_MAXHEALTH")
    frame:RegisterEvent("UNIT_NAME_UPDATE")
    frame:RegisterEvent("UNIT_TARGET")  -- For when tank changes target

    frame:SetScript("OnEvent", function(self, event, arg1)
        -- Update when our unit changes or when the parent tank changes target
        local parentUnit = "maintank" .. self.mtIndex
        if arg1 == self.unit or (event == "UNIT_TARGET" and arg1 == parentUnit) then
            UpdateMainTankTargetFrame(self)
        end
    end)

    return frame
end

---------------------------------------------------------------------------
-- UPDATE: Main Tank Frame
---------------------------------------------------------------------------
local function UpdateMainTankFrame(frame)
    if not frame then return end
    local unit = frame.unit
    local settings = GetUnitSettings("maintank")
    if not settings then return end

    if not UnitExists(unit) then
        return
    end

    -- Update health bar
    local healthPct = GetHealthPct(unit) or 100
    frame.healthBar:SetValue(healthPct)

    -- Health bar color (class color or custom)
    if settings.useClassColor then
        local _, class = UnitClass(unit)
        if class and RAID_CLASS_COLORS[class] then
            local c = RAID_CLASS_COLORS[class]
            frame.healthBar:SetStatusBarColor(c.r, c.g, c.b, 1)
        end
    else
        local c = settings.customHealthColor or {0.2, 0.6, 0.2, 1}
        frame.healthBar:SetStatusBarColor(c[1], c[2], c[3], c[4] or 1)
    end

    -- Update name
    if settings.showName and frame.nameText then
        local name = UnitName(unit) or ""
        local maxLen = settings.maxNameLength or 0
        if maxLen > 0 and #name > maxLen then
            name = name:sub(1, maxLen)
        end
        frame.nameText:SetText(name)

        if settings.nameTextUseClassColor then
            local _, class = UnitClass(unit)
            if class and RAID_CLASS_COLORS[class] then
                local c = RAID_CLASS_COLORS[class]
                frame.nameText:SetTextColor(c.r, c.g, c.b, 1)
            end
        end
    end

    -- Update health text
    if settings.showHealth and frame.healthText then
        local text = ""
        if settings.healthDisplayStyle == "percent" then
            text = string.format("%.0f%%", healthPct)
        elseif settings.healthDisplayStyle == "absolute" then
            text = AbbreviateNumber(UnitHealth(unit))
        else
            text = string.format("%.0f%%", healthPct)
        end
        frame.healthText:SetText(text)
    end

    -- Update power bar if enabled
    if settings.showPowerBar and frame.powerBar then
        local powerPct = GetPowerPct(unit) or 100
        frame.powerBar:SetValue(powerPct)
    end
end

---------------------------------------------------------------------------
-- UPDATE: Main Tank Target Frame
---------------------------------------------------------------------------
local function UpdateMainTankTargetFrame(frame)
    if not frame then return end
    local unit = frame.unit
    local settings = GetUnitSettings("maintank")
    if not settings then return end

    if not UnitExists(unit) then
        return
    end

    -- Update health bar
    local healthPct = GetHealthPct(unit) or 100
    frame.healthBar:SetValue(healthPct)

    -- Health bar color (hostility or class color)
    if settings.targetUseHostilityColor then
        local reaction = UnitReaction(unit, "player")
        if UnitIsPlayer(unit) then
            local _, class = UnitClass(unit)
            if class and RAID_CLASS_COLORS[class] then
                local c = RAID_CLASS_COLORS[class]
                frame.healthBar:SetStatusBarColor(c.r, c.g, c.b, 1)
            end
        elseif reaction then
            if reaction <= 2 then
                frame.healthBar:SetStatusBarColor(0.8, 0.2, 0.2, 1)  -- Hostile (red)
            elseif reaction <= 4 then
                frame.healthBar:SetStatusBarColor(0.9, 0.7, 0.2, 1)  -- Neutral (yellow)
            else
                frame.healthBar:SetStatusBarColor(0.2, 0.8, 0.2, 1)  -- Friendly (green)
            end
        end
    elseif settings.targetUseClassColor and UnitIsPlayer(unit) then
        local _, class = UnitClass(unit)
        if class and RAID_CLASS_COLORS[class] then
            local c = RAID_CLASS_COLORS[class]
            frame.healthBar:SetStatusBarColor(c.r, c.g, c.b, 1)
        end
    else
        local c = settings.targetCustomHealthColor or {0.8, 0.2, 0.2, 1}
        frame.healthBar:SetStatusBarColor(c[1], c[2], c[3], c[4] or 1)
    end

    -- Update name
    if settings.targetShowName and frame.nameText then
        local name = UnitName(unit) or ""
        local maxLen = settings.targetMaxNameLength or 0
        if maxLen > 0 and #name > maxLen then
            name = name:sub(1, maxLen)
        end
        frame.nameText:SetText(name)
    end

    -- Update health text
    if settings.targetShowHealth and frame.healthText then
        local text = ""
        if settings.targetHealthDisplayStyle == "percent" then
            text = string.format("%.0f%%", healthPct)
        elseif settings.targetHealthDisplayStyle == "absolute" then
            text = AbbreviateNumber(UnitHealth(unit))
        else
            text = string.format("%.0f%%", healthPct)
        end
        frame.healthText:SetText(text)
    end
end

3. Add Initialization

File: utils/qui_unitframes.lua (add in Initialize() function, after boss frames around line 4230)

-- Create main tank frames (maintank1 through maintankN with targets)
if db.maintank and db.maintank.enabled then
    local maxFrames = db.maintank.maxFrames or 4
    local spacing = db.maintank.spacing or 4

    for i = 1, maxFrames do
        local mtUnit = "maintank" .. i
        local mtKey = "maintank" .. i

        -- Create tank frame
        self.frames[mtKey] = CreateMainTankFrame(mtUnit, mtKey, i)

        -- Position: stack vertically (first frame uses offsetX/Y, others stack below)
        if self.frames[mtKey] and i > 1 then
            local prevFrame = self.frames["maintank" .. (i - 1)]
            if prevFrame then
                self.frames[mtKey]:ClearAllPoints()
                self.frames[mtKey]:SetPoint("TOPLEFT", prevFrame, "BOTTOMLEFT", 0, -spacing)
            end
        end

        -- Create tank target frame (anchored to right of tank frame)
        if self.frames[mtKey] and db.maintank.showTarget then
            local mtTargetKey = "maintank" .. i .. "target"
            self.frames[mtTargetKey] = CreateMainTankTargetFrame(
                mtUnit .. "target",
                mtTargetKey,
                i,
                self.frames[mtKey]
            )
        end
    end
end

4. Add Refresh Functions

File: utils/qui_unitframes.lua (add to RefreshFrame() and RefreshAll())

In RefreshFrame():

-- Handle maintank frames specially - refresh all pairs
if unitKey == "maintank" then
    local settings = GetUnitSettings("maintank")
    local maxFrames = settings and settings.maxFrames or 4
    local spacing = settings and settings.spacing or 4

    for i = 1, maxFrames do
        local mtKey = "maintank" .. i
        local mtTargetKey = "maintank" .. i .. "target"
        local frame = self.frames[mtKey]
        local targetFrame = self.frames[mtTargetKey]

        if frame then
            -- Update size
            frame:SetSize(Scale(settings.width or 120), Scale(settings.height or 28))

            -- Reposition (first frame uses saved position, others stack)
            if i > 1 then
                local prevFrame = self.frames["maintank" .. (i - 1)]
                if prevFrame then
                    frame:ClearAllPoints()
                    frame:SetPoint("TOPLEFT", prevFrame, "BOTTOMLEFT", 0, -spacing)
                end
            end

            UpdateMainTankFrame(frame)
        end

        if targetFrame and settings.showTarget then
            -- Update size and reanchor
            targetFrame:SetSize(Scale(settings.targetWidth or 120), Scale(settings.targetHeight or 28))
            targetFrame:ClearAllPoints()
            targetFrame:SetPoint("LEFT", frame, "RIGHT", Scale(settings.targetSpacing or 2), 0)

            UpdateMainTankTargetFrame(targetFrame)
        end
    end
    return
end

In RefreshAll():

-- Track if we've refreshed maintank frames
local maintankRefreshed = false

-- ... existing code ...

-- In the loop:
if unitKey:match("^maintank%d+") then
    if not maintankRefreshed then
        self:RefreshFrame("maintank")
        maintankRefreshed = true
    end
-- ... rest of existing logic

5. Add Options Panel

File: utils/qui_options.lua (add new tab in Unit Frames section)

-- Main Tank tab (add after Boss tab)
do
    local mtTab = GUI:CreateTab(tabContainer, "Main Tank")
    local mtContent = CreateFrame("Frame", nil, mtTab)
    mtContent:SetAllPoints()

    local ufdb = GetUFDB()
    local mt = ufdb and ufdb.maintank

    local y = -PADDING

    -- Enable checkbox
    local enableCheck = GUI:CreateFormCheckbox(mtContent, "Enable Main Tank Frames",
        "enabled", mt, RefreshNewUF)
    enableCheck:SetPoint("TOPLEFT", PADDING, y)
    y = y - FORM_ROW

    -- Max frames slider (1-8)
    local maxFramesSlider = GUI:CreateFormSlider(mtContent, "Number of Frames",
        "maxFrames", mt, 1, 8, 1, RefreshNewUF)
    maxFramesSlider:SetPoint("TOPLEFT", PADDING, y)
    y = y - FORM_ROW

    -- Show target checkbox
    local showTargetCheck = GUI:CreateFormCheckbox(mtContent, "Show Tank Target",
        "showTarget", mt, RefreshNewUF)
    showTargetCheck:SetPoint("TOPLEFT", PADDING, y)
    y = y - FORM_ROW

    -- Spacing slider
    local spacingSlider = GUI:CreateFormSlider(mtContent, "Vertical Spacing",
        "spacing", mt, 0, 20, 1, RefreshNewUF)
    spacingSlider:SetPoint("TOPLEFT", PADDING, y)
    y = y - FORM_ROW

    -- Tank Frame section header
    local tankHeader = GUI:CreateSectionHeader(mtContent, "Tank Frame")
    tankHeader:SetPoint("TOPLEFT", PADDING, y)
    y = y - 25

    -- Width/Height sliders
    local widthSlider = GUI:CreateFormSlider(mtContent, "Width",
        "width", mt, 80, 200, 1, RefreshNewUF)
    widthSlider:SetPoint("TOPLEFT", PADDING, y)
    y = y - FORM_ROW

    local heightSlider = GUI:CreateFormSlider(mtContent, "Height",
        "height", mt, 20, 50, 1, RefreshNewUF)
    heightSlider:SetPoint("TOPLEFT", PADDING, y)
    y = y - FORM_ROW

    -- Class color checkbox
    local classColorCheck = GUI:CreateFormCheckbox(mtContent, "Use Class Color",
        "useClassColor", mt, RefreshNewUF)
    classColorCheck:SetPoint("TOPLEFT", PADDING, y)
    y = y - FORM_ROW

    -- Target Frame section header
    local targetHeader = GUI:CreateSectionHeader(mtContent, "Target Frame")
    targetHeader:SetPoint("TOPLEFT", PADDING, y)
    y = y - 25

    -- Target width slider
    local targetWidthSlider = GUI:CreateFormSlider(mtContent, "Target Width",
        "targetWidth", mt, 80, 200, 1, RefreshNewUF)
    targetWidthSlider:SetPoint("TOPLEFT", PADDING, y)
    y = y - FORM_ROW

    -- Target spacing slider
    local targetSpacingSlider = GUI:CreateFormSlider(mtContent, "Target Spacing",
        "targetSpacing", mt, 0, 20, 1, RefreshNewUF)
    targetSpacingSlider:SetPoint("TOPLEFT", PADDING, y)
    y = y - FORM_ROW

    -- Hostility color checkbox
    local hostilityCheck = GUI:CreateFormCheckbox(mtContent, "Color by Hostility",
        "targetUseHostilityColor", mt, RefreshNewUF)
    hostilityCheck:SetPoint("TOPLEFT", PADDING, y)
    y = y - FORM_ROW
end

Summary

Aspect Implementation
Unit IDs maintank1 through maintankN
Target Units maintank1target, maintank2target, etc.
Settings Location db.maintank in quicore_main.lua
Frame Functions CreateMainTankFrame, CreateMainTankTargetFrame
Files Changed 3 (quicore_main.lua, qui_unitframes.lua, qui_options.lua)

Notes:

  • Requires raid group (main tank assignments are raid-only)
  • Frames auto-show/hide based on unit existence
  • Target frames anchor to tank frames and update on UNIT_TARGET
  • Follows boss frames pattern with paired target display
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment