vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
XPerl_MainTanks = {}
MainTankCount = 0
local MainTanks = {}
local Events = {}
local XUnits = {}
local XOtherUnits = {}
local XFreeUnits = {}
local OtherTargetOwners = {}
local UpdateTime = 0
local FrameExpanded = false
local XOtherRows = 0
local XGaps = 0
local XTitle
local MainAssist = nil
local XFind = nil
local bigwigsSlowDown = 0

-- Dup colours used to show which tanks have the same target
local MTdupColours = {  {r = "0.8", g = "0.2", b = "0.2"},
                        {r = "0.2", g = "0.2", b = "0.8"},
                        {r = "0.8", g = "0.2", b = "0.8"},
                        {r = "0.2", g = "0.8", b = "0.2"},
                        {r = "0.2", g = "0.8", b = "0.8"}}

local MAX_UNITS = 50
local MAX_OTHER_ROWS = 10
local GAP_SPACING = 10
XPERL_UNIT_HEIGHT_MIN = 17
XPERL_UNIT_HEIGHT_MAX = 30
XPERL_UNIT_WIDTH_MIN = 50
XPERL_UNIT_WIDTH_MAX = 125

if (not XPerlColourTable) then
        local function MashXX(class)
                local c = RAID_CLASS_COLORS[class]
                XPerlColourTable[class] = string.format("|c00%02X%02X%02X", 255 * c.r, 255 * c.g, 255 * c.b)
        end
        XPerlColourTable = {}
        MashXX("HUNTER")
        MashXX("WARLOCK")
        MashXX("PRIEST")
        MashXX("PALADIN")
        MashXX("MAGE")
        MashXX("ROGUE")
        MashXX("DRUID")
        MashXX("SHAMAN")
        MashXX("WARRIOR")
end

-- Although your own "target" is updated immediately, any reference to ourself via our raid id is updated via the server
-- So, to cure the slow response times, we check if anything is 'me'. Only direct targets are updated immedately,
-- so we don't bother with target's target onwards.
local function SpecialCaseUnit(unit)
        if (unit.unit and (unit.type == "MTT" or unit.type == "OT") and UnitIsUnit("player", unit.unit)) then
                return "target"
        else
                return unit.partyid
        end
end

----------------------------
------- DISPLAY ------------
----------------------------
local function UpdateUnit(unit,forcedUpdate)

        if (forcedUpdate) then
                local time = GetTime()
                if (unit.update and time < unit.update + 0.2) then
                        -- Since we catch UNIT_HEALTH changes, we don't need to update always
                        return
                end
        end

        unit.update = GetTime()

        local xunit = SpecialCaseUnit(unit)

        local name = UnitName(xunit)
        local text = getglobal(unit:GetName().."_Name")
        local bar = getglobal(unit:GetName().."_HealthBar")
        local percent = getglobal(unit:GetName().."_HealthBarText")
        local barBG = getglobal(unit:GetName().."_HealthBarBG")
        local combat = getglobal(unit:GetName().."_Combat")
        local warning = getglobal(unit:GetName().."_Warning")
        local raidIcon = getglobal(unit:GetName().."_RaidIcon")
        local percBar

        barBG:Show()

        if (name and name ~= UNKNOWNOBJECT) then
                -- Name
                text:SetText(name)
                text:SetPoint("BOTTOMRIGHT", unit, "TOPRIGHT", 0, -12)

                local remCount = 1
                while ((text:GetStringWidth() >= (unit:GetWidth() - 2)) and (string.len(name) > remCount)) do
                        name = string.sub(name, 1, string.len(name) - remCount)..".."
                        remCount = 3
                        text:SetText(name)
                end

                if (UnitPlayerControlled(xunit)) then
                        XPerl_ColourFriendlyUnit(text, xunit)
                else
                        XPerl_SetUnitNameColor(xunit, text)
                end

                -- Health
                local healthMax = UnitHealthMax(xunit)
                local health = UnitHealth(xunit)
                percBar = health / healthMax
                local perc = percBar * 100

                bar:SetMinMaxValues(0, healthMax)
                bar:SetValue(health)

                if (UnitIsDead(xunit)) then
                        percent:SetText(XPERL_LOC_DEAD)
                else
                        percent:SetText(math.floor(perc + 0.5).."%")
                end
                if (XPerlConfigHelper.UnitHeight < 23) then
                        percent:Hide()
                else
                        percent:Show()
                end

                if (unit.type == "MTT" or unit.type == "OT") then
                        if (BigWigsTargetMonitor) then
                                if (bigwigsSlowDown == 0) then
                                        BigWigsTargetMonitor:TargetCheck(xunit)
                                end
                        end

                        local index = GetRaidTargetIndex(xunit)
                        if (index) then
                                SetRaidTargetIconTexture(raidIcon, index)
                                raidIcon:Show()
                        else
                                raidIcon:Hide()
                        end
                else
                        raidIcon:Hide()
                end
        else
                text:SetPoint("BOTTOMRIGHT", -2, 1)

                if (unit.type == "MTT") then
                        name = UnitName(unit.unit)

                        if (name) then
                                XPerl_ColourFriendlyUnit(text, unit.unit)
                                text:SetText(string.format(XPERL_XS_TARGET, name))
                                barBG:Hide()
                        end
                else
                        text:SetText(XPERL_NO_TARGET)
                        text:SetTextColor(0.5, 0.5, 0.5, 1)
                end
                bar:SetMinMaxValues(0, 1)
                bar:SetValue(0)
                percBar = 0
                percent:Hide()
                raidIcon:Hide()
        end

        if (UnitAffectingCombat(xunit)) then
                combat:Show()
        else
                combat:Hide()
        end

        if (UnitIsCharmed(xunit)) then
                warning:Show()
        else
                warning:Hide()
        end

        XPerl_SetSmoothBarColor (bar, percBar)
end

-- XPerl_RaidHelp_Show
function XPerl_RaidHelp_Show()
        XPerlConfigHelper.RaidHelper = 1
        XPerl_EnableDisable()
        return true
end

-- XPerl_OnClick
function XPerl_OnClick(button)
        local unitid = this.partyid

        if (UnitName(unitid) or (button == "RightButton" and this.unit)) then
                if (XPerl_OnClick_Handler) then
                        if (not XPerl_OnClick_Handler(button, unitid)) then
                                if (button == "RightButton" and this.unit) then
                                        XPerl_OnClick_Handler("LeftButton", this.unit)
                                end
                        end
                else
                        if (button == "RightButton" and this.unit and not SpellIsTargetting()) then
                                button = "LeftButton"
                        end

                        if (button == "LeftButton") then
                                if (SpellIsTargeting()) then
                                        SpellTargetUnit(unitid)
                                        return true
                                elseif (CursorHasItem()) then
                                        if (UnitIsUnit("player", unitid)) then
                                                AutoEquipCursorItem()
                                        else
                                                DropItemOnUnit(unitid)
                                        end
                                        return true
                                else
                                        TargetUnit(unitid)
                                        return true
                                end

                        elseif (button == "RightButton") then
                                if (SpellIsTargeting()) then
                                        SpellStopTargeting()
                                        return true
                                elseif (CursorHasItem()) then
                                        ClearCursor()
                                        return true
                                else
                                        TargetUnit(this.unit)
                                end
                        end
                end
        end
end

-- XPerl_OnEnter
function XPerl_OnEnter()

        local x = XPerl_Frame:GetCenter()
        local a1, a2 = "ANCHOR_LEFT", "ANCHOR_TOPLEFT"
        if ( x < (GetScreenWidth() / 2)) then
                a1, a2 = "ANCHOR_RIGHT", "ANCHOR_TOPRIGHT"
        end

        if (SpellIsTargeting()) then
                if (SpellCanTargetUnit(this.partyid)) then
                        SetCursor("CAST_CURSOR")
                else
                        SetCursor("CAST_ERROR_CURSOR")
                end
        end

        if (XPerlConfigHelper.Tooltips == 1) then
                if (this.partyid and UnitName(this.partyid)) then
                        GameTooltip:SetOwner(this, a1)
                        GameTooltip:SetUnit(this.partyid)

                        if (this.unit and (this.type == "MTT" or this.type == "OT")) then
                                local extra = 10
                                if (TinyTipExtrasExists) then
                                        extra = 20
                                end

                                XPerl_BottomTip:SetOwner(GameTooltip, a2, 0, extra)
                                XPerl_BottomTip:SetUnit(this.unit)
                                XPerl_BottomTip:SetBackdropColor(0.1, 0.4, 0.1, 0.75)
                        end
                else
                        if (this.type == "MTT" or this.type == "OT") then
                                GameTooltip:SetOwner(this, a1)
                                GameTooltip:SetUnit(this.unit)
                                GameTooltip:SetBackdropColor(0.1, 0.4, 0.1, 0.75)
                        end
                end
        end
end

-- ListChanged1
local function ListChanged1(list1, list2)
        if (getn(list1) == getn(list2)) then
                for k,v in pairs(list1) do
                        if (v == list2[k]) then
                                return true
                        end
                end
                return false
        end
        return true
end

-- XPerl_SetupFrameSimple
function XPerl_SetupFrameSimple(argFrame, alpha)
        argFrame:SetBackdropBorderColor(0.5, 0.5, 0.5, alpha or 0.8)
        argFrame:SetBackdropColor(0, 0, 0, alpha or 0.8)
end

-- AllocateUnit
local AllocateUnitNum = 0
local LastUnitWarning
local function AllocateUnit(list, parent)

        local unit = XFreeUnits[1]
        if (unit) then
                tremove(XFreeUnits, 1)
                tinsert(list, unit)
                unit:SetParent(parent)
        else
                if (AllocateUnitNum < MAX_UNITS) then
                        AllocateUnitNum = AllocateUnitNum + 1
                        unit = CreateFrame("Button", "XPerl_Unit"..AllocateUnitNum, parent, "XPerl_UnitTemplate")

                        if (unit) then
                                XPerl_SetupFrameSimple(unit, XPerlConfigHelper.Background_Transparency)
                                unit:SetAlpha(XPerlConfigHelper.Targets_Transparency)
                                tinsert(list, unit)

                                if (XPerl_RegisterHighlight) then
                                        XPerl_RegisterHighlight(unit, 3)
                                else
                                        local tex = unit:GetHighlightTexture()
                                        tex:SetVertexColor(0.86, 0.82, 0.41)
                                end
                        else
                                XPerl_Notice("Error creating frame called 'XPerl_Unit"..AllocateUnitNum.."' from template 'XPerl_UnitTemplate'")
                        end
                else
                        if (not LastUnitWarning or GetTime() > LastUnitWarning + 600) then
                                LastUnitWarning = GetTime()
                                XPerl_Notice("Maximum number of units reached ("..MAX_UNITS..")")
                        end
                end
        end

        if (unit) then
                if (XPerl_GetBarTexture) then
                        local tex = XPerl_GetBarTexture()
                        getglobal(unit:GetName().."_HealthBarTex"):SetTexture(tex)

                        if (XPerlConfig.BackgroundTextures == 1) then
                                getglobal(unit:GetName().."_HealthBarBG"):SetTexture(tex)
                        else
                                getglobal(unit:GetName().."_HealthBarBG"):SetTexture("Interface\\TargetingFrame\\UI-StatusBar")
                        end
                end

                local t = getglobal(unit:GetName().."_HealthBarText");          t:Hide()
                t = getglobal(unit:GetName().."_Label");        t:SetText("");  t:Hide()
                t = getglobal(unit:GetName().."_Name");                         t:Show()

                XPerl_SetupFrameSimple(unit, XPerlConfigHelper.Background_Transparency)

                unit:SetScale(1)
                unit:SetWidth(XPerlConfigHelper.UnitWidth)
                unit:SetHeight(XPerlConfigHelper.UnitHeight)

                local bar = getglobal(unit:GetName().."_HealthBar")
                bar:ClearAllPoints()
                if (XPerlConfigHelper.UnitHeight > 16) then
                        bar:SetPoint("TOPLEFT", 3, -14)
                        bar:SetPoint("BOTTOMRIGHT", -3, 2)
                else
                        bar:SetPoint("TOPLEFT", 4, -4)
                        bar:SetPoint("BOTTOMRIGHT", -4, 4)
                end

                unit:Show()
        end

        return unit
end

-- Remove units from list and place back into available unit pool
local function UnallocateUnits(list)

        while (getn(list) > 0) do
                local unit = list[1]

                unit:ClearAllPoints()
                unit:Hide()

                unit.partyid = nil
                unit.unit = nil
                unit.OtherTarget = nil
                unit.collapseable = nil
                unit.type = nil

                tremove(list, 1)
                tinsert(XFreeUnits, unit)
        end
end

-- XPerl_HelperBarTextures
if (XPerl_GetBarTexture) then
function XPerl_HelperBarTextures(tex)
        local function UnitTex(v, tex)
                local f = getglobal(v:GetName().."_HealthBarTex")
                f:SetTexture(tex)
                f = getglobal(v:GetName().."_HealthBarBG")
                if (XPerlConfig and XPerlConfig.BackgroundTextures == 1) then
                        f:SetTexture(tex)
                else
                        f:SetTexture("Interface\\TargetingFrame\\UI-StatusBar")
                end
        end

        XPerl_MyThreatTex:SetTexture(tex)
        XPerl_MyThreatBG:SetTexture(tex)

        for k,v in pairs(XUnits) do
                UnitTex(v, tex)
        end
        for k,v in pairs(XOtherUnits) do
                UnitTex(v, tex)
        end
        for k,v in pairs(XFreeUnits) do
                UnitTex(v, tex)
        end
end
end

-- XPerl_SetMainAssist
function XPerl_SetMainAssist(msg, ma, quiet)

        if (ma == "broadcast") then
                if (IsRaidOfficer()) then
                        SendAddonMessage(XPERL_COMMS_PREFIX, "MA "..UnitName("player").." "..UnitName(MainAssist.unit), "RAID")
                else
                        XPerl_Message("You must be promoted to set the Main Assist")
                end
        else
                if (not ma) then
                        ma = 0
                end

                if (string.lower(ma) == "target") then
                        ma = UnitName(ma)
                end

                if (ma) then
                        for i,tank in pairs(MainTanks) do
                                if (string.lower(UnitName("raid"..tank[1])) == string.lower(ma)) then
                                        ma = i
                                        break
                                end
                        end

                        ma = tonumber(ma)

                        if (MainTanks[ma]) then
                                local maUnit = "raid"..MainTanks[ma][1]
                                MainAssist = {unit = maUnit, name = UnitName(maUnit)}
                                local _, class = UnitClass(maUnit)
                                MainAssist.class = class
                        else
                                MainAssist = nil
                        end
                else
                        MainAssist = nil
                end

                if (MainAssist) then
                        XPerlConfigHelper.LastMainAssist = MainAssist.name
                else
                        XPerlConfigHelper.LastMainAssist = nil
                end

                if (not quiet) then
                        if (MainAssist) then
                                XPerl_Message("Main Assist set to "..XPerlColourTable[MainAssist.class]..MainAssist.name)
                        else
                                XPerl_Message("Main Assist |c00FF0000cleared!")
                        end
                end
        end

        return true
end

-- RemoveDupMT
local function RemoveDupMT(name)
        for k, v in pairs(XPerl_MainTanks) do
                if (v[2] == name) then
                        XPerl_MainTanks[k] = nil
                        return true
                end
        end
end

-- GetRaidIDByName
local function GetRaidIDByName(name)
        for i = 1, GetNumRaidMembers() do
                if (UnitName("raid"..i) == name) then
                        return i
                end
        end
end

-- GetUnitRank
local function GetUnitRank(name)
        local index = GetRaidIDByName(name)
        if (index) then
                local _, rank = GetRaidRosterInfo(index)
                return rank
        end
        return 0
end

-- ValidateTankList
-- Check the roster for any tanks that have left the raid
local function ValidateTankList()
        for index,entry in pairs(XPerl_MainTanks) do
                local found
                for i = 1,GetNumRaidMembers() do
                        if (UnitName("raid"..i) == entry[2]) then
                                found = true
                                break
                        end
                end

                if (not found) then
                        XPerl_MainTanks[index] = nil
                end
        end
end

-- XPerl_MTRosterChanged()
function XPerl_MTRosterChanged()
        ValidateTankList()

        MainTankCount = 0
        for i in pairs(XPerl_MainTanks) do
                MainTankCount = MainTankCount + 1
        end

        if (MainTankCount == 0 or XPerlConfigHelper.UseCTRATargets == 0) then
                -- If no defined tanks, then make a list from the warriors in raid
                MainTanks = {}
                MainTankCount = 0

                for i = 1,GetNumRaidMembers() do
                        local _, class = UnitClass("raid"..i)
                        if (class == "WARRIOR") then
                                tinsert(MainTanks, {i, UnitName("raid"..i)})
                                MainTankCount = MainTankCount + 1
                        end
                end
        else
                MainTankCount = 0
                for index,entry in pairs(XPerl_MainTanks) do
                        local raidid = GetRaidIDByName(entry[2])
                        if (raidid) then
                                MainTankCount = MainTankCount + 1
                                entry[1] = raidid
                        end
                end

                MainTanks = XPerl_MainTanks
        end

        XPerl_MakeTankList()

        if (XPerlConfigHelper.LastMainAssist) then
                if (not MainAssist) then
                        XPerl_SetMainAssist("", XPerlConfigHelper.LastMainAssist, true)
                        if (not MainAssist) then
                                XPerlConfigHelper.LastMainAssist = nil
                        end
                end
        end
end

-- CT_RA_IsSendingWithVersion override
-- Override this so that we get the MT list if there's only us in the raid with a CTRA version registered
local old_CT_RA_IsSendingWithVersion
if (CT_RA_IsSendingWithVersion) then
        if (CT_RA_IsSendingWithVersion ~= XPerl_IsSendingWithVersion) then
                old_CT_RA_IsSendingWithVersion = CT_RA_IsSendingWithVersion
                CT_RA_IsSendingWithVersion = function(version)
                        if (version == 1.08) then
                                return 1
                        end
                        return old_CT_RA_IsSendingWithVersion(version)
                end
        end
end

-- ProcessCTRAMessage
local function ProcessCTRAMessage(unitName, msg)

        local mtListUpdate

        if (strsub(msg, 1, 4) == "SET ") then
                local rankSender = GetUnitRank(unitName)
                if (rankSender < 1) then
                        return
                end

                local useless, useless, num, name = strfind(msg, "^SET (%d+) (.+)$")
                if (num and name) then
                        num = tonumber(num)
                        local mtID = 0
                        for i = 1, GetNumRaidMembers() do
                                if (UnitName("raid"..i) == name) then
                                        mtID = i
                                        break
                                end
                        end

                        if (XPerl_MainTanks[num]) then
                                if (XPerl_MainTanks[num][1] == mtID and XPerl_MainTanks[num][2] == name) then
                                        return                  -- No Change
                                end
                        end

                        RemoveDupMT(name)

                        XPerl_MainTanks[tonumber(num)] = {mtID, name}

                        mtListUpdate = true
                end

        elseif (strsub(msg, 1, 2) == "R ") then
                local rankSender = GetUnitRank(unitName)
                if (rankSender < 1) then
                        return
                end

                local useless, useless, name = strfind(msg, "^R (.+)$")
                if (name) then
                        mtListUpdate = RemoveDupMT(name)
                end
        end

        if (mtListUpdate) then
                XPerl_MTRosterChanged()
        end
end

-- XPerl_SplitCTRAMessage
function XPerl_SplitCTRAMessage(msg, char)
        local arr = { }
        while (strfind(msg, char) ) do
                local iStart, iEnd = strfind(msg, char)
                tinsert(arr, strsub(msg, 1, iStart-1))
                msg = strsub(msg, iEnd+1, strlen(msg))
        end
        if ( strlen(msg) > 0 ) then
                tinsert(arr, msg)
        end
        return arr
end

-- XPerl_ParseCTRA
function XPerl_ParseCTRA(nick, msg, func)
        if (strfind(msg, "#")) then
                local arr = XPerl_SplitCTRAMessage(msg, "#")
                for i,subMsg in pairs(arr) do
                        func(nick, subMsg)
                end
        else
                func(nick, msg)
        end
end

-- CHAT_MSG_ADDON
function Events:CHAT_MSG_ADDON()
        if (arg1 == XPERL_COMMS_PREFIX and arg3 == "RAID") then
                local msg = arg2
                local cmds = {}
                for x in string.gfind(msg, "[^ ]+") do
                        tinsert(cmds, x)
                end

                if (cmds[1] == "MA") then
                        local from = cmds[2]
                        local newMA = cmds[3]
                        local fromID, maID

                        -- Pick up raid id for sender and new MA
                        for i = 1,GetNumRaidMembers() do
                                local name, rank, group, level, classLocal, class = GetRaidRosterInfo(i)

                                if (name == from) then
                                        if (rank > 0) then      -- Make sure someone who is promoted sent the message
                                                fromID = "raid"..i
                                        else
                                                return
                                        end
                                end
                                if (name == newMA) then
                                        maID = "raid"..i
                                end
                        end

                        if (fromID and maID) then
                                if (not UnitIsUnit(fromID, "player")) then
                                        local _, fromClass = UnitClass(fromID)
                                        local __, maClass = UnitClass(maID)

                                        MainAssist = {unit = maID, name = UnitName(maID), class = maClass}
                                        XPerlConfigHelper.LastMainAssist = MainAssist.name
                                        XPerl_Message(XPerlColourTable[fromClass]..from.." has assigned the Main Assist to be "..XPerlColourTable[maClass]..MainAssist.name)
                                end
                        end
                end
        elseif (arg1 == "CTRA" and arg3 == "RAID") then
                XPerl_ParseCTRA(arg4, arg2, ProcessCTRAMessage)
        end
end

----------------------------
---------- EVENTS ----------
----------------------------

-- OnEvent
function XPerl_OnEvent()
        local Event = Events[event]
        if (Event) then
                Event()
        else
XPerl_ShowMessage("EXTRA EVENT")
        end
end

local function IsDPSClass(unit)
        local _, class = UnitClass(unit)
        return (class == "ROGUE" or class == "WARRIOR" or class == "MAGE" or class == "WARLOCK" or class == "HUNTER")
end

local function IsMT1(unit)
        if (MainAssist and UnitName(MainAssist.unit) == MainAssist.name) then
                return UnitIsUnit(unit, MainAssist.unit)
        elseif (MainTanks[1]) then
                return UnitIsUnit(unit, "raid"..MainTanks[1][1])
        end
end

local function IsMT(unit)
        for k, tank in pairs(MainTanks) do
                if (UnitIsUnit(unit, "raid"..tank[1])) then
                        return true
                end
        end
end

local function IsTanked(checkUnit)
        for k, tank in pairs(MainTanks) do
                if (UnitIsUnit("raid"..tank[1].."target", checkUnit)) then
                        return true
                end
        end
end

-- ScanForTargets
local function ScanForTargets()

        if (XPerlConfigHelper.CollectOtherTargets == 0 or UnitIsCharmed("player")) then
                return {}
        end

        local NewList = {}

        local function FoundAlready(checkUnit)
                for j, owner in pairs(NewList) do
                        if (UnitIsUnit(owner.."target", checkUnit.."target")) then
                                return true
                        end
                end
        end

        local function Check(unitid, doStats)
                if (UnitLevel(unitid.."target") ~= 1 and (UnitReaction("player", unitid.."target") or 5) <= 4 and not UnitIsDeadOrGhost(unitid.."target")) then
                        if (not FoundAlready(unitid)) then
                                if (not IsTanked(unitid.."target")) then
                                        tinsert(NewList, unitid)
                                end
                        end
                end
        end

        local doStats = XPerl_Stats:IsShown()

        if (doStats) then
                XPerl_Stats_List.NoTarget = {}
                XPerl_Stats_List.NotAssistingMT1 = {}
                XPerl_Stats_List.NotAssistingAnyMT = {}
                XPerl_Stats_List.HealersOnMT1 = {}
                XPerl_Stats_List.HealersOnOtherMTs = {}
                XPerl_Stats_List.HealersNotOnMTs = {}
        end

        for i = 1,GetNumRaidMembers() do
                local checkUnit = "raid"..i
                if (doStats) then
                        if (UnitIsConnected(checkUnit) and UnitIsVisible(checkUnit) and not UnitIsDeadOrGhost(checkUnit)) then
                                if (not UnitName(checkUnit.."target") and UnitName(checkUnit.."target") ~= UNKNOWNOBJECT) then
                                        -- No target, slacker
                                        tinsert(XPerl_Stats_List.NoTarget, checkUnit)
                                else
                                        if (IsDPSClass(checkUnit)) then
                                                -- DPS statistics
                                                --if (UnitCanAttack(checkUnit, checkUnit.."target")) then
                                                if ((UnitReaction("player", checkUnit.."target") or 5) <= 4) then
                                                        if (not IsMT(checkUnit)) then
                                                                if (MainTanks[1] and not UnitIsUnit(checkUnit.."target", "raid"..MainTanks[1][1].."target")) then
                                                                        -- They're not assisting MT1
                                                                        tinsert(XPerl_Stats_List.NotAssistingMT1, checkUnit)
                                                                        tinsert(XPerl_Stats_List.NotAssistingAnyMT, checkUnit)

                                                                elseif (not IsTanked(checkUnit.."target")) then
                                                                        -- They're not assisting any of the MTs
                                                                        tinsert(XPerl_Stats_List.NotAssistingAnyMT, checkUnit)
                                                                end
                                                        end
                                                else
                                                        -- DPS targetting friendly, count it as useless
                                                        tinsert(XPerl_Stats_List.NoTarget, checkUnit)
                                                end
                                        else
                                                -- Healer statistics
                                                if (IsMT1(checkUnit.."target")) then
                                                        -- Healer targetting MT1
                                                        tinsert(XPerl_Stats_List.HealersOnMT1, checkUnit)

                                                elseif (IsMT(checkUnit.."target")) then
                                                        -- Healer targetting another MT
                                                        tinsert(XPerl_Stats_List.HealersOnOtherMTs, checkUnit)

                                                else
                                                        tinsert(XPerl_Stats_List.HealersNotOnMTs, checkUnit)
                                                end
                                        end
                                end
                        end
                end

                Check(checkUnit)
                Check("raidpet"..i)
        end

        if (doStats) then
                local function Colour(num, good)
                        if (num > 10) then
                                if (good) then
                                        return "|c0000FF00"..num.."|r"
                                else
                                        return "|c00FF0000"..num.."|r"
                                end
                        elseif (num > 0) then
                                return "|c00FFFF00"..num.."|r"
                        else
                                if (good) then
                                        return "|c00FF0000"..num.."|r"
                                else
                                        return "|c0000FF00"..num.."|r"
                                end
                        end
                end

                local MT1 = "MT1"
                if (MainAssist and UnitName(MainAssist.unit) == MainAssist.name) then
                        MT1 = "MA"
                end

                XPerl_Stats1:SetText(string.format(XPERL_STATS_NO_TARGET, Colour(getn(XPerl_Stats_List.NoTarget))))
                XPerl_Stats2:SetText(string.format(XPERL_STATS_NOT_ASSIST_MT1, Colour(getn(XPerl_Stats_List.NotAssistingMT1)), MT1))
                XPerl_Stats3:SetText(string.format(XPERL_STATS_NOT_ASSIST_ANY, Colour(getn(XPerl_Stats_List.NotAssistingAnyMT))))
                XPerl_Stats4:SetText(string.format(XPERL_STATS_HEALERS_MT1, Colour(getn(XPerl_Stats_List.HealersOnMT1), true), MT1))
                XPerl_Stats5:SetText(string.format(XPERL_STATS_HEALERS_ANY, Colour(getn(XPerl_Stats_List.HealersOnOtherMTs), true)))
                XPerl_Stats6:SetText(string.format(XPERL_STATS_HEALERS_NON_MT, Colour(getn(XPerl_Stats_List.HealersNotOnMTs))))

                if (XPerl_Stats_List.shownStats ~= 0) then
                        XPerl_SetStatDetails()
                end
        end

        return NewList
end

-- XPerl_GetUnit
local function XPerl_GetUnit(unit)
        for i,search in pairs(XUnits) do
                if (search.unit == unit) then
                        return search
                end
        end
end

-- ScanForMTDups
-- Check MTs all have unique targets
local function ScanForMTDups()
        local dup = 1
        local dups = {}

        for i,unit in pairs(XUnits) do
                XPerl_SetupFrameSimple(unit, XPerlConfigHelper.Background_Transparency)
        end

        for i,t1 in pairs(MainTanks) do
                local any = false

                if (UnitName("raid"..t1[1].."target") and UnitName("raid"..t1[1].."target") ~= UNKNOWNOBJECT and not UnitIsDeadOrGhost("raid"..t1[1])) then
                        for j,t2 in pairs(MainTanks) do
                                if (j > i and not dups["raid"..t2[1]]) then
                                        if (UnitIsUnit("raid"..t1[1].."target", "raid"..t2[1].."target")) then
                                                dups["raid"..t2[1]] = 1

                                                local unit1 = XPerl_GetUnit("raid"..t1[1])
                                                local unit2 = XPerl_GetUnit("raid"..t2[1])

                                                if (unit1) then
                                                        unit1:SetBackdropBorderColor(MTdupColours[dup].r, MTdupColours[dup].g, MTdupColours[dup].b)
                                                        unit1:SetBackdropColor(MTdupColours[dup].r, MTdupColours[dup].g, MTdupColours[dup].b)
                                                end
                                                if (unit2) then
                                                        unit2:SetBackdropBorderColor(MTdupColours[dup].r, MTdupColours[dup].g, MTdupColours[dup].b)
                                                        unit2:SetBackdropColor(MTdupColours[dup].r, MTdupColours[dup].g, MTdupColours[dup].b)
                                                end
                                                any = true
                                        end
                                end
                        end

                        if (any and dup < 5) then
                                dup = dup + 1
                        end
                end
        end
end

-- OnUpdate
local function OnUpdate()
        UpdateTime = UpdateTime + arg1
        if (UpdateTime > 0.2) then
                UpdateTime = 0

                local doneArrow = false
                local maDone = false
                XPerl_MyTarget:ClearAllPoints()
                XPerl_MyTarget:Hide()
                XPerl_MainAssist:Hide()

                local arrowType = "MTT"
                local arrowExtra = ""
                if (XPerlConfigHelper.ShowMT == 1) then
                        arrowType = "MT"
                        arrowExtra = "target"
                end

                for i,unit in pairs(XUnits) do
                        UpdateUnit(unit, true)

                        local xunit = SpecialCaseUnit(unit)

                        if (unit.type == arrowType and not doneArrow and UnitIsUnit("target", xunit..arrowExtra) and UnitExists("target")) then -- and not UnitIsPlayer(unit.partyid)) then
                                doneArrow = true
                                XPerl_MyTarget:SetParent(unit)
                                XPerl_MyTarget:SetPoint("RIGHT", unit, "LEFT", 2 - (XPerlConfigHelper.MTLabels * 10), 0)
                                XPerl_MyTarget:Show()
                        end

                        if (not maDone and MainAssist and UnitIsUnit(unit.unit, MainAssist.unit) and UnitName(MainAssist.unit) == MainAssist.name) then
                                maDone = true
                                XPerl_MainAssist:SetParent(getglobal(unit:GetName().."_HealthBar"))
                                XPerl_MainAssist:ClearAllPoints()

                                if (XPerlConfigHelper.MTLabels == 1) then
                                        XPerl_MainAssist:SetPoint("BOTTOMRIGHT", unit, "BOTTOMLEFT", 1, 3)
                                else
                                        XPerl_MainAssist:SetPoint("BOTTOMRIGHT", -1, 1)
                                end
                                XPerl_MainAssist:Show()
                        end
                end

                local NewList = ScanForTargets()

                if (ListChanged1(OtherTargetOwners, NewList)) then
                        OtherTargetOwners = NewList
                        XPerl_MakeOtherTargetList()
                else
                        for i,unit in pairs(XOtherUnits) do
                                UpdateUnit(unit, true)

                                local xunit = SpecialCaseUnit(unit)

                                if (unit.type == "OT" and unit:IsVisible() and not doneArrow and UnitIsUnit("target", xunit) and UnitExists("target") and not UnitIsPlayer(unit.partyid)) then
                                        doneArrow = true
                                        XPerl_MyTarget:SetParent(unit)
                                        XPerl_MyTarget:SetPoint("RIGHT", unit, "LEFT", 2 - (XPerlConfigHelper.MTLabels * XPerlConfigHelper.OtherTargetTargets * 10) * unit:GetScale(), 0)
                                        XPerl_MyTarget:Show()
                                end
                        end
                end

                ScanForMTDups()

                bigwigsSlowDown = bigwigsSlowDown + 1
                if (bigwigsSlowDown > 10) then
                        bigwigsSlowDown = 0
                end

                --XPerl_Frame_Test:SetText(getn(XFreeUnits).." "..getn(XUnits).." "..getn(XOtherUnits))
        end

        if (FrameExpanded or XPerlConfigHelper.ExpandLock == 1) then
                local f = GetMouseFocus()
                if (f) then
                        while (f:GetParent() and f:GetParent() ~= UIParent) do
                                f = f:GetParent()
                        end

                        if (f ~= XPerl_Frame) then
                                XPerl_CollapseOthers()
                        end
                end
        end
end

-- VARIABLES_LOADED
function Events:VARIABLES_LOADED()
        this:UnregisterEvent(event)

        if (type(XPerl_MainTanks) ~= "table") then
                XPerl_MainTanks = {}
        end

        XPerl_Startup()
        XPerl_EnableDisable()
end

-- Registration
local function Registration()
        local list = {  "UNIT_HEALTH",
                        "UNIT_MAXHEALTH",
                        "PLAYER_TARGET_CHANGED",
                        "CHAT_MSG_ADDON"}

        for i,a in pairs(list) do
                if (GetNumRaidMembers() > 0 and XPerlConfigHelper.RaidHelper == 1) then
                        XPerl_Frame:RegisterEvent(a)
                else
                        XPerl_Frame:UnregisterEvent(a)
                end
        end
end

-- XPerl_EnableDisable
function XPerl_EnableDisable()
        if (XPerlConfigHelper and XPerlConfigHelper.RaidHelper == 1 and GetNumRaidMembers() > 0) then
                XPerl_Frame:Show()
                XPerl_Frame:SetScript("OnUpdate", OnUpdate)

                if (CT_RAMenu_Options and CT_RA_UpdateVisibility) then
                        XPerlConfigHelper.OldCTMTListHide = CT_RAMenu_Options["temp"]["HideMTs"]
                        CT_RAMenu_Options["temp"]["HideMTs"] = true
                        CT_RA_UpdateVisibility(1)
                end
        else
                XPerl_Frame:Hide()
                XPerl_Frame:SetScript("OnUpdate", nil)

                if (XPerlConfigHelper and XPerlConfigHelper.RaidHelper == 0 and CT_RAMenu_Options and CT_RA_UpdateVisibility) then
                        if (XPerlConfigHelper.OldCTMTListHide ~= true) then
                                XPerlConfigHelper.OldCTMTListHide = nil
                                CT_RAMenu_Options["temp"]["HideMTs"] = false
                                CT_RA_UpdateVisibility(1)
                        end
                end
        end

        Registration()
        XPerl_MTRosterChanged()
end

-- RAID_ROSTER_UPDATE
function Events:RAID_ROSTER_UPDATE()
        if (GetNumRaidMembers() == 0) then
                MainTanks = {}
        end

        XPerl_EnableDisable()
end

-- UNIT_HEALTH
function Events:UNIT_HEALTH()
        -- scan for a unit we have
        for k,unit in pairs(XUnits) do
                if (UnitIsUnit(unit.partyid, arg1)) then
                        UpdateUnit(unit)
                end
        end

        for k,unit in pairs(XOtherUnits) do
                if (UnitIsUnit(unit.partyid, arg1)) then
                        UpdateUnit(unit)
                end
        end
end

Events.UNIT_MAXHEALTH = Events.UNIT_HEALTH

function Events:PLAYER_TARGET_CHANGED()
        for i,unit in pairs(XUnits) do
                if (UnitIsUnit(unit.partyid, "player")) then
                        UpdateUnit(unit)
                end
        end
end

-- The number of 'Other' colums that can be shown
local function DisplayableColumns()
        local columnsTop = 1 + XPerlConfigHelper.ShowMT + XPerlConfigHelper.MTTargetTargets
        local columnsBottom = 1 + XPerlConfigHelper.OtherTargetTargets

        if (columnsTop == 1 and columnsBottom > 1) then
                if (XPerlConfigHelper.MTTargetTargets == 0) then
                        if (XPerlConfigHelper.MTLabels == 1) then
                                if (XPerlConfigHelper.OtherTargets_Scale > 0.52) then
                                        columnsTop = 2
                                end
                        else
                                if (XPerlConfigHelper.OtherTargets_Scale > 0.49) then
                                        columnsTop = 2
                                end
                        end
                end
        end

        return columnsTop
end

-- XPerl_SetTitle
function XPerl_SetTitle()
        if (DisplayableColumns() > 1 and XPerlConfigHelper.UnitWidth >= 70) then
                if (XPerl_MainTanks == MainTanks) then
                        XPerl_Frame_Title:SetText(XPERL_TITLE_MT_LONG)
                else
                        XPerl_Frame_Title:SetText(XPERL_TITLE_WARRIOR_LONG)
                end
        else
                if (XPerl_MainTanks == MainTanks) then
                        XPerl_Frame_Title:SetText(XPERL_TITLE_MT_SHORT)
                else
                        XPerl_Frame_Title:SetText(XPERL_TITLE_WARRIOR_SHORT)
                end
        end
end

-- XPerl_MakeTankList
function XPerl_MakeTankList()

        if (not XPerlConfigHelper or XPerlConfigHelper.RaidHelper == 0 or GetNumRaidMembers() == 0) then
                XPerl_SetFrameSizes()
                return
        end

        XPerl_SetTitle()

        XPerl_MyTarget:Hide()
        XPerl_MainAssist:Hide()

        --MainTanks = NewTankList

        UnallocateUnits(XUnits)

        XGaps = 0

        local previousUnit
        local previousID = 0
        local first = true
        local foundMA = false
        local mainTanksDisplayed = 0
        for i,tank in pairs(MainTanks) do
                local unit = AllocateUnit(XUnits, XPerl_MTTargets)
                if (not unit) then
                        break
                end
                unit.partyid = "raid"..tank[1].."target"
                unit.unit = "raid"..tank[1];                    -- 1 == id, 2 == name
                unit.type = "MTT"

                mainTanksDisplayed = mainTanksDisplayed + 1

                local rowFrames = {}
                rowFrames[2] = unit

                -- Correct the Main Assist number in case people leave the raid
                if (MainAssist and UnitName("raid"..tank[1]) == MainAssist.name) then
                        MainAssist.unit = "raid"..tank[1]
                        foundMA = true
                end

                if (XPerlConfigHelper.ShowMT == 1) then
                        local unitTank = AllocateUnit(XUnits, XPerl_MTTargets)
                        if (unitTank) then
                                unitTank.partyid = "raid"..tank[1]
                                unitTank.unit = "raid"..tank[1]
                                unitTank.type = "MT"

                                rowFrames[1] = unitTank
                        else
                                break
                        end
                end

                if (XPerlConfigHelper.MTTargetTargets == 1) then
                        local unitTarget = AllocateUnit(XUnits, XPerl_MTTargets)
                        if (unitTarget) then
                                unitTarget.partyid = "raid"..tank[1].."targettarget"
                                unitTarget.unit = "raid"..tank[1]
                                unitTarget.type = "MTTT"

                                rowFrames[3] = unitTarget
                        else
                                break
                        end
                end

                local previousColumn
                for j,frame in pairs(rowFrames) do
                        UpdateUnit(frame)

                        if (not previousColumn) then
                                if (first) then
                                        first = false
                                        frame:SetPoint("TOPLEFT", XPerl_MTTargets, "TOPLEFT", XPerlConfigHelper.MTLabels * 10, 0)
                                else
                                        local gap = 0;          -- Maintain a gap if not sequential numbers
                                        if (i > previousID + 1) then
                                                XGaps = XGaps + 1
                                                gap = -GAP_SPACING
                                        end

                                        frame:SetPoint("TOPLEFT", previousUnit, "BOTTOMLEFT", 0, gap)
                                end
                        else
                                frame:SetPoint("TOPLEFT", previousColumn, "TOPRIGHT", 0, 0)
                        end

                        if (not previousColumn) then
                                local label = getglobal(frame:GetName().."_Label")
                                label:SetText(i)
                                label:SetTextColor(1, 1, 1)
                                if (XPerlConfigHelper.MTLabels == 1) then
                                        label:Show()
                                end

                                previousUnit = frame
                        end
                        previousColumn = frame
                end

                if (mainTanksDisplayed >= XPerlConfigHelper.MaxMainTanks) then
                        break
                end

                previousID = i
        end

        if (MainAssist and not foundMA) then
                -- Main assist left the raid
                XPerl_Message("Main Assist "..XPerlColourTable[MainAssist.class]..MainAssist.name.."|r not found in tank list - removed!")
                MainAssist = nil
        end

        if (previousUnit) then
                XPerl_Frame:Show()
        else
                XPerl_Frame:Hide()
        end

        XPerl_SetFrameSizes()
end

-- XPerl_MakeOtherTargetList
function XPerl_MakeOtherTargetList()

        UnallocateUnits(XOtherUnits)

        local mainWidth = XPerl_Frame:GetWidth()

        if (not IsTanked("target")) then
                XPerl_MyTarget:Hide()
        end

        XOtherRows = 0

        local previousUnit
        local rowStartUnit
        local rowSize = 0
        local firstRowSize
        for i,other in pairs(OtherTargetOwners) do
                if (XOtherRows >= MAX_OTHER_ROWS) then          -- Well, gotta stop somewhere...
                        break
                end

                local unit = AllocateUnit(XOtherUnits, XPerl_OtherTargets)
                if (not unit) then
                        break
                end

                unit:SetScale(XPerlConfigHelper.OtherTargets_Scale)
                local otherWidth = unit:GetWidth() * unit:GetScale()

                unit.partyid = other.."target"
                unit.type = "OT"

                if (i == 1) then
                        rowStartUnit = unit
                        rowSize = otherWidth
                        unit:SetPoint("TOPLEFT", XPerl_OtherTargets, "TOPLEFT", XPerlConfigHelper.MTLabels * XPerlConfigHelper.OtherTargetTargets * 10, 0)
                        XOtherRows = XOtherRows + 1
                else
                        if (XPerlConfigHelper.OtherTargetTargets == 1) then
                                unit:SetPoint("TOPLEFT", previousUnit, "BOTTOMLEFT", 0, 0)
                                XOtherRows = XOtherRows + 1
                        else
                                if (rowSize + otherWidth > mainWidth - 6) then
                                        if (XOtherRows == MAX_OTHER_ROWS) then
                                                break
                                        end

                                        if (not firstRowSize) then
                                                firstRowSize = i - 1
                                        end

                                        unit:SetPoint("TOPLEFT", rowStartUnit, "BOTTOMLEFT", 0, 0)
                                        rowStartUnit = unit
                                        rowSize = otherWidth
                                        XOtherRows = XOtherRows + 1
                                else
                                        rowSize = rowSize + otherWidth
                                        unit:SetPoint("TOPLEFT", previousUnit, "TOPRIGHT", 0, 0)
                                end
                        end
                end
                UpdateUnit(unit)

                if (XOtherRows > 1) then
                        unit.collapseable = true
                end

                if (XOtherRows > 1 and not FrameExpanded and XPerlConfigHelper.ExpandLock == 0) then
                        unit:Hide()
                end

                local label = getglobal(unit:GetName().."_Label")
                label:SetText(i)
                label:SetTextColor(0.8, 0.2, 0.2)
                if (XPerlConfigHelper.OtherTargetTargets == 1) then
                        if (XPerlConfigHelper.MTLabels == 1) then
                                label:Show()
                        end

                        local newUnit = AllocateUnit(XOtherUnits, XPerl_OtherTargets)
                        if (not newUnit) then
                                break
                        end
                        newUnit:SetScale(XPerlConfigHelper.OtherTargets_Scale)
                        newUnit.partyid = unit.partyid.."target"
                        newUnit:SetPoint("TOPLEFT", unit, "TOPRIGHT", 0, 0)
                        newUnit.type = "OTT"

                        UpdateUnit(newUnit)

                        if (XOtherRows > 1) then
                                newUnit.collapseable = true
                        end
                        if (i > 1 and not FrameExpanded and XPerlConfigHelper.ExpandLock == 0) then
                                unit.collapseable = true
                                newUnit:Hide()
                        end

                        unit.OtherTarget = newUnit
                end

                previousUnit = unit
        end

        XPerl_SetFrameSizes()

        if (not firstRowSize) then
                firstRowSize = 1
        end
        XPerl_ExpandArrowFrame_Stats:SetText(string.format(XPERL_FOOTER_MORE, getn(OtherTargetOwners) - firstRowSize))

        local key = GetBindingText(GetBindingKey("TARGETFIRSTOTHER"), "KEY_")
        if (key) then
                XPerl_OtherTargets_Key:SetText(string.format(XPERL_TO_TARGET, "|c0000FF40"..key.."|r"))
        else
                XPerl_OtherTargets_Key:SetText("")
        end
end

-- XPerl_SetFrameSizes
function XPerl_SetFrameSizes()

        local tanks = MainTankCount
        local unitHeight = 20
        local unitHeightOther = 20

        if (tanks > XPerlConfigHelper.MaxMainTanks) then
                tanks = XPerlConfigHelper.MaxMainTanks
        end

        if (XPerl_Unit1) then
                unitHeight = XPerl_Unit1:GetHeight()
                if (XOtherUnits[1]) then
                        unitHeightOther = XOtherUnits[1]:GetHeight() * XOtherUnits[1]:GetScale()
                end
        end

        XPerl_MTTargets:SetHeight((unitHeight * tanks) + (XGaps * GAP_SPACING))

        local otherTargets = getn(OtherTargetOwners)
        local otherTargetsExtraHeight = 0

        if (otherTargets > 0) then
                otherTargetsExtraHeight = 10
                XPerl_OtherTargets:Show()
        else
                XPerl_OtherTargets:Hide()
        end

        if (XOtherRows < 2 or FrameExpanded or XPerlConfigHelper.ExpandLock == 1) then
                XPerl_ExpandArrowFrame:Hide()
        else
                if (otherTargets > 1) then
                        otherTargets = 1
                        otherTargetsExtraHeight = otherTargetsExtraHeight + 10
                        XPerl_ExpandArrowFrame:Show()
                else
                        XPerl_ExpandArrowFrame:Hide()
                end
        end

        local otherRows = XOtherRows
        if (otherRows > MAX_OTHER_ROWS) then
                otherRows = MAX_OTHER_ROWS
        end
        if (otherRows > 1 and not FrameExpanded and XPerlConfigHelper.ExpandLock == 0) then
                otherRows = 1
        end
        XPerl_Frame:SetHeight((unitHeight * tanks) + (XGaps * GAP_SPACING) + (unitHeightOther * otherRows) + 5 + XPerl_Frame_TitleBar:GetHeight() + otherTargetsExtraHeight)

        local ExtraWidth = (XPerlConfigHelper.MTLabels * 10);   -- 0 for off, 10 for on
        XLastColumCount = DisplayableColumns()
        XPerl_Frame:SetWidth(XLastColumCount * XPerlConfigHelper.UnitWidth + 6 + ExtraWidth)
end

-- XPerl_ExpandOthers
function XPerl_ExpandOthers()
        if (not FrameExpanded) then
                FrameExpanded = true
                XPerl_SetFrameSizes()

                for i,unit in pairs(XOtherUnits) do
                        unit:Show()
                end
        end
end

-- XPerl_CollapseOthers
function XPerl_CollapseOthers()
        if (FrameExpanded and XPerlConfigHelper.ExpandLock == 0) then
                FrameExpanded = false
                XPerl_SetFrameSizes()

                for i,unit in pairs(XOtherUnits) do
                        if (unit.collapseable) then
                                unit:Hide()
                        end
                end

                if (XOtherUnits[1] and XOtherUnits[1].OtherTarget) then
                        XOtherUnits[1].OtherTarget:Show()
                end
        end
end

-- XPerl_Toggle_Stats
function XPerl_Toggle_Stats()
        if (XPerl_Stats:IsShown()) then
                XPerl_Stats:Hide()
                if (XPerl_Stats_List.shownStats ~= 0) then
                        getglobal("XPerl_Stats"..XPerl_Stats_List.shownStats):UnlockHighlight()
                        XPerl_Stats_List.shownStats = 0
                end
                XPerl_Stats_List:Hide()
        else
                XPerl_Stats1:SetText("")
                XPerl_Stats2:SetText("")
                XPerl_Stats3:SetText("")
                XPerl_Stats4:SetText("")
                XPerl_Stats5:SetText("")

                XPerl_Stats:Show()
        end
end

-- XPerl_TargetFirstOther
function XPerl_TargetFirstOther()
        if (XOtherUnits[1]) then
                TargetUnit(XOtherUnits[1].partyid)
        end
end

-- XPerl_SmartAssist
local XAssistSkipCount = 0
function XPerl_SmartAssist()

        local function ValidTarget(unit)
                local minor
                if (UnitIsVisible(unit)) then
                        if (UnitExists(unit) and not UnitIsDeadOrGhost(unit)) then
                                if (UnitReaction("player", unit) <= 4) then
                                        if (UnitHealth(unit) <= 10) then
                                                return "minor"
                                        else
                                                return "valid"
                                        end
                                end
                        end
                end
        end

        local function XFindUnit()
                if (XFind) then
                        TargetByName(XFind)

                        if (ValidTarget("target") and strlower(strsub(UnitName("target"),1,strlen(XFind))) == strlower(XFind)) then
                                XPerl_Message("Using FIND found suitable target. ('|c00007F00/xp find|r' to clear).")
                                return true
                        else
                                local r = UnitReaction("player", "target")
                                if (r and r > 4) then
                                        ClearTarget()
                                end
                        end
                end
        end

        if (not UnitName("target")) then
                if (XFindUnit()) then
                        return
                end
        end

        if (not UnitExists("target")) then
                XAssistSkipCount = 0
        end

        local minorUnit
        local valid
        local isMT = IsMT("player")
        local targetCount = 0

        local function Skip()
                targetCount = targetCount + 1
                if (targetCount > XAssistSkipCount) then
                        XAssistSkipCount = XAssistSkipCount + 1
                        return false
                end
                return true
        end

        if (not isMT and MainAssist and UnitName(MainAssist.unit) == MainAssist.name) then
                valid = ValidTarget(MainAssist.unit.."target")
                if (valid and valid == "valid") then
                        if (not Skip()) then
                                TargetUnit(MainAssist.unit.."target")
                                return
                        end
                end
        end

        -- First scan the list of Main Tanks and pick one of their targets if it's health is greater than 10%
        for i,id in pairs(MainTanks) do
                local unit = "raid"..id[1]

                valid = ValidTarget(unit.."target")

                if (valid) then
                        if (valid == "minor") then
                                minorUnit = unit
                                if (not Skip()) then
                                        break
                                end
                        else
                                if (not isMT) then
                                        if (not Skip()) then
                                                TargetUnit(unit.."target")
                                                return
                                        end
                                end
                        end
                end
        end

        -- If we're not an MT, then pick one of the MT targets and assist
        if (minorUnit and not isMT) then
                if (not Skip()) then
                        TargetUnit(minorUnit.."target")
                        return
                end
        else
                -- Otherwise, we're a tank so look for something un-tanked
                for i,unit in pairs(OtherTargetOwners) do
                        local valid = ValidTarget(unit.."target")

                        if (valid) then
                                if (valid == "minor") then
                                        minorUnit = unit
                                        if (not Skip()) then
                                                break
                                        end
                                else
                                        if (not Skip()) then
                                                TargetUnit(unit.."target")
                                                return
                                        end
                                end
                        end
                end
        end

        XAssistSkipCount = 0;           -- If we reached here, there was nothing else to find
        if (minorUnit) then
                TargetUnit(minorUnit.."target")
        else
                -- Nothing found so far, scan through party members in case we've pressed the button when not in a raid
                for i = 1,4 do
                        local unit = "party"..i.."target"

                        local valid = ValidTarget(unit)

                        if (valid) then
                                TargetUnit(unit.."target")
                                break
                        end
                end
        end

        XFindUnit()

        if (not UnitName("target")) then
                TargetNearestEnemy()
        end
end

-- XPerl_SetStatDetails
function XPerl_SetStatDetails(id, event)

        if (id and XPerl_Stats_List.shownStats ~= 0) then
                getglobal("XPerl_Stats"..XPerl_Stats_List.shownStats):UnlockHighlight()
        end

        if (id and XPerl_Stats_List.shownStats == id) then
                XPerl_Stats_List.shownStats = 0
                XPerl_Stats_List:Hide()
                return
        end

        if (not id) then
                id = XPerl_Stats_List.shownStats
        end

        local list
        if (id == 1) then       list = XPerl_Stats_List.NoTarget
        elseif (id == 2) then   list = XPerl_Stats_List.NotAssistingMT1
        elseif (id == 3) then   list = XPerl_Stats_List.NotAssistingAnyMT
        elseif (id == 4) then   list = XPerl_Stats_List.HealersOnMT1
        elseif (id == 5) then   list = XPerl_Stats_List.HealersOnOtherMTs
        elseif (id == 6) then   list = XPerl_Stats_List.HealersNotOnMTs
        end

        local text = ""
        for i,unit in pairs(list) do
                local _, class = UnitClass(unit)
                local name = UnitName(unit)
                text = text..XPerlColourTable[class]..name.." "
        end

        getglobal("XPerl_Stats"..id):LockHighlight()
        XPerl_Stats_ListText:SetText(text)

        XPerl_Stats_List.shownStats = id
        XPerl_Stats_List:Show()
end

-- XPerl_Toggle_UseCTRATargets
function XPerl_Toggle_UseCTRATargets()
        if (XPerlConfigHelper.UseCTRATargets == 1) then
                XPerlConfigHelper.UseCTRATargets = 0
        else
                XPerlConfigHelper.UseCTRATargets = 1
        end

        XPerl_MTRosterChanged()
        return true
end

-- XPerl_Toggle_OtherTargets
function XPerl_Toggle_OtherTargets(noChange)
        if (not noChange) then
                if (XPerlConfigHelper.OtherTargetTargets == 1) then
                        XPerlConfigHelper.OtherTargetTargets = 0
                else
                        XPerlConfigHelper.OtherTargetTargets = 1
                end
        end

        XPerl_MakeTankList()
        XPerl_MakeOtherTargetList()

        XPerl_Frame_ToggleTargets:SetButtonTex()
        return true
end

function XPerl_Toggle_MTTargets(noChange)
        if (not noChange) then
                if (XPerlConfigHelper.MTTargetTargets == 1) then
                        XPerlConfigHelper.MTTargetTargets = 0
                else
                        XPerlConfigHelper.MTTargetTargets = 1
                end
        end

        XPerl_MakeTankList()
        XPerl_MakeOtherTargetList()

        XPerl_Frame_ToggleMTTargets:SetButtonTex()
        return true
end

-- XPerl_Toggle_ExpandLock
function XPerl_Toggle_ExpandLock(noChange)

        if (not noChange) then
                if (XPerlConfigHelper.ExpandLock == 1) then
                        XPerlConfigHelper.ExpandLock = 0
                else
                        XPerlConfigHelper.ExpandLock = 1
                end
        end

        if (XPerlConfigHelper.ExpandLock == 1) then
                XPerl_ExpandOthers()
        else
                XPerl_CollapseOthers()
        end

        XPerl_Frame_ExpandLock:SetButtonTex()
end

-- XPerl_Toggle_ToggleLabels
function XPerl_Toggle_ToggleLabels(noChange)

        if (not noChange) then
                if (XPerlConfigHelper.MTLabels == 1) then
                        XPerlConfigHelper.MTLabels = 0
                else
                        XPerlConfigHelper.MTLabels = 1
                end
        end

        XPerl_MakeTankList()
        XPerl_MakeOtherTargetList()

        XPerl_Frame_ToggleLabels:SetButtonTex()

        return true
end

function XPerl_Toggle_ShowMT(noChange)
        if (not noChange) then
                if (XPerlConfigHelper.ShowMT == 1) then
                        XPerlConfigHelper.ShowMT = 0
                else
                        XPerlConfigHelper.ShowMT = 1
                end
        end

        XPerl_MakeTankList()
        XPerl_MakeOtherTargetList()

        XPerl_Frame_ToggleShowMT:SetButtonTex()

        return true
end

-- XPerl_Toggle_CollectOtherTargets
function XPerl_Toggle_CollectOtherTargets(noChange)

        if (not noChange) then
                if (XPerlConfigHelper.CollectOtherTargets == 1) then
                        XPerlConfigHelper.CollectOtherTargets = 0
                else
                        XPerlConfigHelper.CollectOtherTargets = 1
                end
        end

        XPerl_MakeOtherTargetList()

        return true
end

-- XPerl_SetFind
function XPerl_SetFind(msg)

        local name = ""
        local any
        for x in string.gfind(msg, "[^ ]+") do
                if (any) then
                        if (name ~= "") then
                                name = name.." "
                        end
                        name = name..x
                end
                any = true
        end

        XFind = name

        if (XFind == "") then
                XFind = nil
                XPerl_Message("Find |c00FF0000cleared!|r")
        else
                XPerl_Message("Find set to |c0000FF00"..name.."|r. ('|c00007F00/xp find|r' to clear).")
        end

        return true
end

-- SmoothBarColor
local function SmoothBarColor(bar, barBG)
        local barmin, barmax = bar:GetMinMaxValues()
        local percentage = (bar:GetValue()/(barmax-barmin))

        local r, g
        if (percentage < 0.5) then
                r = 2*percentage
                g = 1
        else
                r = 1
                g = 2*(1 - percentage)
        end

        if ((r>=0) and (g>=0) and (r<=1) and (g<=1)) then
                bar:SetStatusBarColor(r, g, 0)
                barBG:SetVertexColor(r, g, 0, 0.25)
        end
end

-- Redo some of this stuff. too much duplication and work on each frame
local function SetBarToTitle(bar)
        local offset = XPerl_Frame_Title:GetStringWidth() + 25
        bar:SetScale(0.75);             -- Scale it down for the font size
        bar:SetParent(XPerl_Frame_TitleBar)
        bar:Show()
        bar:ClearAllPoints()
        bar:SetPoint("TOPLEFT", XPerl_Frame_TitleBar, "TOPLEFT", offset / 0.75, -3)
        bar:SetPoint("BOTTOMRIGHT", XPerl_Frame_ToggleShowMT, "BOTTOMLEFT", -5, 2)
end

local function SetBarToFrame(bar)
        bar:SetScale(0.75)
        bar:SetParent(XPerl_Threat)
        bar:Show()
        bar:ClearAllPoints()
        bar:SetPoint("TOPLEFT", 3, -3)
        bar:SetPoint("BOTTOMRIGHT", -3, 3)
end

-- XPerl_UpdateThreat
local lastThreat = -1
local lastThreat100
function XPerl_UpdateThreat()

        local data, playerCount, threat100 = KLHTM_GetRaidData()
        if (threat100 > 0) then
                local userThreat = klhtm.table.raiddata[UnitName("player")] or 0

                if (userThreat == lastThreat and threat100 == lastThreat100) then
                        return
                else
                        lastThreat = userThreat
                        lastThreat100 = threat100

                        if (data[1].name == "Aggro Gain") then
                                playerCount = playerCount - 1
                        end

                        if (playerCount > 1) then
                                local titleSpace = (XPerl_Frame_ToggleShowMT:GetLeft() - XPerl_Frame_Title:GetLeft()) - (XPerl_Frame_Title:GetStringWidth() + 25)

                                XPerl_MyThreatText:SetText(userThreat - threat100)              -- Show deficit threat value

                                XPerl_MyThreat:SetMinMaxValues(0, threat100)
                                XPerl_MyThreat:SetValue(userThreat)

                                if (titleSpace >= 10) then
                                        SetBarToTitle(XPerl_MyThreat)
                                        XPerl_Threat:Hide()
                                        XPerl_Threat:SetHeight(2)
                                else
                                        SetBarToFrame(XPerl_MyThreat)
                                        XPerl_Threat:Show()
                                        XPerl_Threat:SetHeight(12)
                                end

                                SmoothBarColor(XPerl_MyThreat, XPerl_MyThreatBG)
                                return
                        end
                end
        end

        if (lastThreat) then
                XPerl_Threat:Hide()
                XPerl_Threat:SetHeight(2)
                XPerl_MyThreat:Hide()
                lastThreat = nil
                lastThreat100 = nil
        end
end