866 lines
23 KiB
Lua
866 lines
23 KiB
Lua
if not Cursive.superwow then
|
|
return
|
|
end
|
|
|
|
local L = AceLibrary("AceLocale-2.2"):new("Cursive")
|
|
|
|
local utils = Cursive.utils
|
|
local filter = Cursive.filter
|
|
|
|
local ui = CreateFrame("Frame", "CursiveUI", UIParent)
|
|
|
|
ui.border = {
|
|
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
|
tile = true, tileSize = 16, edgeSize = 8,
|
|
insets = { left = 2, right = 2, top = 2, bottom = 2 }
|
|
}
|
|
|
|
ui.background = {
|
|
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
|
tile = true, tileSize = 16, edgeSize = 8,
|
|
insets = { left = 0, right = 0, top = 0, bottom = 0 }
|
|
}
|
|
|
|
ui.rootBarFrame = nil
|
|
ui.targetIndicatorSize = 8
|
|
ui.padding = 2
|
|
|
|
ui.row = 1
|
|
ui.col = 1
|
|
ui.maxBarsDisplayed = false
|
|
ui.numDisplayed = 0
|
|
|
|
local function GetBarFirstSectionWidth()
|
|
local config = Cursive.db.profile
|
|
|
|
local size = 1
|
|
if config.showraidicons then
|
|
size = size + config.raidiconsize
|
|
end
|
|
if config.showtargetindicator then
|
|
size = size + ui.targetIndicatorSize
|
|
end
|
|
if size > 0 then
|
|
size = size + ui.padding
|
|
end
|
|
|
|
return size
|
|
end
|
|
|
|
local function GetBarSecondSectionWidth()
|
|
local config = Cursive.db.profile
|
|
|
|
if config.showhealthbar == false and config.showunitname == false then
|
|
return 1
|
|
end
|
|
|
|
return config.healthwidth + ui.padding
|
|
end
|
|
|
|
local function GetBarThirdSectionWidth()
|
|
local config = Cursive.db.profile
|
|
|
|
return config.maxcurses * (config.curseiconsize + ui.padding)
|
|
end
|
|
|
|
local function GetBarWidth()
|
|
return GetBarFirstSectionWidth() +
|
|
GetBarSecondSectionWidth() +
|
|
GetBarThirdSectionWidth()
|
|
end
|
|
|
|
local function UpdateRootBarFrame()
|
|
local config = Cursive.db.profile
|
|
|
|
if config.showbackdrop then
|
|
ui.rootBarFrame:SetBackdrop(ui.background)
|
|
else
|
|
ui.rootBarFrame:SetBackdrop(nil)
|
|
end
|
|
|
|
ui.rootBarFrame:EnableMouse(not config.clickthrough)
|
|
|
|
ui.rootBarFrame.pos = config.anchor .. config.x .. config.y .. config.scale
|
|
ui.rootBarFrame:ClearAllPoints()
|
|
ui.rootBarFrame:SetPoint(config.anchor, config.x, config.y)
|
|
|
|
ui.rootBarFrame:SetScale(config.scale)
|
|
|
|
ui.rootBarFrame.caption:SetFont(STANDARD_TEXT_FONT, Cursive.db.profile.textsize, "THINOUTLINE")
|
|
ui.rootBarFrame.caption:SetText(Cursive.db.profile.caption)
|
|
if Cursive.db.profile.showtitle then
|
|
ui.rootBarFrame.caption:Show()
|
|
else
|
|
ui.rootBarFrame.caption:Hide()
|
|
end
|
|
|
|
ui.rootBarFrame:SetWidth(config.maxcol * GetBarWidth())
|
|
-- Calculate height: title area + all rows + extra spacing
|
|
local title_size = 12 + config.spacing
|
|
local total_height = title_size + (config.maxrow * (config.height + config.spacing)) + config.spacing
|
|
ui.rootBarFrame:SetHeight(total_height)
|
|
end
|
|
|
|
local function CreateRoot()
|
|
local frame = CreateFrame("Frame", Cursive.db.profile.caption, UIParent)
|
|
ui.rootBarFrame = frame
|
|
|
|
frame.id = Cursive.db.profile.caption
|
|
|
|
frame:RegisterForDrag("LeftButton")
|
|
frame:SetMovable(true)
|
|
|
|
frame:SetScript("OnDragStart", function()
|
|
this.lock = true
|
|
this:StartMoving()
|
|
end)
|
|
|
|
frame:SetScript("OnDragStop", function()
|
|
-- convert to best anchor depending on position
|
|
local new_anchor = utils.GetBestAnchor(this)
|
|
local anchor, x, y = utils.ConvertFrameAnchor(this, new_anchor)
|
|
this:ClearAllPoints()
|
|
this:SetPoint(anchor, UIParent, anchor, x, y)
|
|
|
|
-- save new position
|
|
anchor, _, _, x, y = this:GetPoint()
|
|
Cursive.db.profile.anchor, Cursive.db.profile.x, Cursive.db.profile.y = anchor, x, y
|
|
|
|
-- stop drag
|
|
this:StopMovingOrSizing()
|
|
this.lock = false
|
|
|
|
this:ClearAllPoints()
|
|
this:SetPoint(anchor, x, y)
|
|
end)
|
|
|
|
-- create title text
|
|
frame.caption = frame:CreateFontString(nil, "HIGH", "GameFontWhite")
|
|
frame.caption:SetPoint("TOPLEFT", frame, "TOPLEFT", 10, -2)
|
|
frame.caption:SetTextColor(1, 1, 1, 1)
|
|
|
|
UpdateRootBarFrame()
|
|
|
|
frame:Show()
|
|
|
|
return frame
|
|
end
|
|
|
|
ui.unitFrames = {} -- holds all unitFrames for all columns/rows
|
|
|
|
Cursive.UpdateFramesFromConfig = function()
|
|
for col, rows in pairs(ui.unitFrames) do
|
|
for row, unitFrame in pairs(rows) do
|
|
if unitFrame and unitFrame:IsShown() then
|
|
unitFrame:Hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
if ui.rootBarFrame then
|
|
UpdateRootBarFrame()
|
|
end
|
|
|
|
-- after 3 seconds reset the unit frames so all changes are applied
|
|
Cursive:ScheduleEvent("resetUnitFrames", Cursive.ResetUnitFrames, 3)
|
|
end
|
|
|
|
Cursive.ResetUnitFrames = function()
|
|
-- hide all existing unit frames
|
|
for col, rows in pairs(ui.unitFrames) do
|
|
for row, unitFrame in pairs(rows) do
|
|
if unitFrame and unitFrame:IsShown() then
|
|
unitFrame:Hide()
|
|
end
|
|
end
|
|
end
|
|
-- clear cached frames so they are recreated
|
|
ui.unitFrames = {}
|
|
end
|
|
|
|
ui.BarEnter = function()
|
|
if this.parent.healthBar then
|
|
this.parent.healthBar.border:SetBackdropBorderColor(1, 1, 1, 1)
|
|
end
|
|
this.parent.hover = true
|
|
|
|
GameTooltip_SetDefaultAnchor(GameTooltip, this)
|
|
GameTooltip:SetUnit(this.parent.guid)
|
|
GameTooltip:Show()
|
|
end
|
|
|
|
ui.BarLeave = function()
|
|
this.parent.hover = false
|
|
GameTooltip:Hide()
|
|
end
|
|
|
|
ui.BarUpdate = function()
|
|
if not this.guid or this.guid == 0 then
|
|
this:Hide()
|
|
return
|
|
end
|
|
|
|
if (this.tick or 1) > GetTime() then
|
|
return
|
|
else
|
|
this.tick = GetTime() + 0.05
|
|
end
|
|
|
|
-- update statusbar values if it exists
|
|
if this.healthBar then
|
|
this.healthBar:SetMinMaxValues(0, UnitHealthMax(this.guid))
|
|
this.healthBar:SetValue(UnitHealth(this.guid))
|
|
|
|
-- update health bar color
|
|
local hex, r, g, b, a = utils.GetUnitColor(this.guid)
|
|
this.healthBar:SetStatusBarColor(r, g, b, a)
|
|
|
|
-- update health bar border
|
|
if this.healthBar.border then
|
|
if this.hover then
|
|
this.healthBar.border:SetBackdropBorderColor(1, 1, 1, 1)
|
|
elseif UnitAffectingCombat(this.guid) then
|
|
this.healthBar.border:SetBackdropBorderColor(.8, .2, .2, 1)
|
|
else
|
|
this.healthBar.border:SetBackdropBorderColor(.2, .2, .2, 1)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- update caption text
|
|
local name = UnitName(this.guid)
|
|
if name and this.nameText then
|
|
this.nameText:SetText(name)
|
|
end
|
|
|
|
if this.hpText then
|
|
local hp = UnitHealth(this.guid)
|
|
if GetLocale() == "zhCN" then
|
|
if hp then
|
|
if hp >= 10000 then
|
|
hp = math.floor(hp / 1000) / 10 .. "万"
|
|
-- elseif hp >= 1000 then
|
|
-- hp = math.floor(hp / 100) / 10 .. "k"
|
|
end
|
|
end
|
|
else
|
|
-- convert hp to k if > 1000
|
|
if hp then
|
|
if hp >= 1000000 then
|
|
hp = math.floor(hp / 100000) / 10 .. "m"
|
|
elseif hp >= 1000 then
|
|
hp = math.floor(hp / 100) / 10 .. "k"
|
|
end
|
|
end
|
|
end
|
|
|
|
if hp then
|
|
this.hpText:SetText(hp)
|
|
end
|
|
end
|
|
|
|
-- show raid icon if existing
|
|
if this.icon then
|
|
if GetRaidTargetIndex(this.guid) and Cursive.filter.alive(this.guid) then
|
|
SetRaidTargetIconTexture(this.icon, GetRaidTargetIndex(this.guid))
|
|
this.icon:Show()
|
|
else
|
|
this.icon:Hide()
|
|
end
|
|
end
|
|
|
|
-- update target indicator
|
|
if this.target_left then
|
|
if UnitIsUnit("target", this.guid) then
|
|
this.target_left:Show()
|
|
else
|
|
this.target_left:Hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
ui.BarClick = function()
|
|
if arg1 == "LeftButton" then
|
|
TargetUnit(this.parent.guid)
|
|
elseif arg1 == "RightButton" then
|
|
TargetUnit(this.parent.guid)
|
|
if (not PlayerFrame.inCombat) then
|
|
AttackTarget()
|
|
end
|
|
end
|
|
end
|
|
|
|
local function CreateBarFirstSection(unitFrame, guid)
|
|
local config = Cursive.db.profile
|
|
local firstSection = CreateFrame("Frame", "Cursive1stSection", unitFrame)
|
|
|
|
if config.invertbars then
|
|
-- When inverted, position relative to second section (rightmost)
|
|
firstSection:SetPoint("LEFT", unitFrame.secondSection, "RIGHT", 0, 0)
|
|
else
|
|
-- Normal positioning (leftmost)
|
|
firstSection:SetPoint("LEFT", unitFrame, "LEFT", 0, 0)
|
|
end
|
|
|
|
firstSection:SetWidth(GetBarFirstSectionWidth())
|
|
firstSection:SetHeight(config.height)
|
|
firstSection:EnableMouse(false)
|
|
unitFrame.firstSection = firstSection
|
|
|
|
-- create target indicator
|
|
if config.showtargetindicator then
|
|
local targetLeft = firstSection:CreateTexture(nil, "OVERLAY")
|
|
targetLeft:SetWidth(ui.targetIndicatorSize)
|
|
targetLeft:SetHeight(8)
|
|
if config.invertbars then
|
|
targetLeft:SetPoint("RIGHT", firstSection, "RIGHT", 0, 0)
|
|
targetLeft:SetTexture("Interface\\AddOns\\Cursive\\img\\target-right")
|
|
else
|
|
targetLeft:SetPoint("LEFT", unitFrame, "LEFT", 0, 0)
|
|
targetLeft:SetTexture("Interface\\AddOns\\Cursive\\img\\target-left")
|
|
end
|
|
targetLeft:Hide()
|
|
unitFrame.target_left = targetLeft
|
|
end
|
|
|
|
-- create raid icon textures
|
|
if config.showraidicons then
|
|
local icon = firstSection:CreateTexture(nil, "OVERLAY")
|
|
icon:SetWidth(config.raidiconsize)
|
|
icon:SetHeight(config.raidiconsize)
|
|
if config.invertbars then
|
|
icon:SetPoint("LEFT", firstSection, "LEFT", 0, 0)
|
|
else
|
|
icon:SetPoint("RIGHT", firstSection, "RIGHT", 0, 0)
|
|
end
|
|
icon:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons")
|
|
icon:Hide()
|
|
unitFrame.icon = icon
|
|
end
|
|
end
|
|
|
|
local function CreateBarSecondSection(unitFrame, guid)
|
|
local config = Cursive.db.profile
|
|
local secondSection = CreateFrame("Button", "Cursive2ndSection", unitFrame)
|
|
|
|
if config.invertbars then
|
|
-- When inverted, position relative to third section (which is created first)
|
|
secondSection:SetPoint("LEFT", unitFrame.thirdSection, "RIGHT", 0, 0)
|
|
else
|
|
-- Normal positioning relative to first section
|
|
secondSection:SetPoint("LEFT", unitFrame.firstSection, "RIGHT", 0, 0)
|
|
end
|
|
|
|
secondSection:SetWidth(GetBarSecondSectionWidth())
|
|
secondSection:SetHeight(config.height)
|
|
unitFrame.secondSection = secondSection
|
|
secondSection.parent = unitFrame
|
|
|
|
secondSection:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
secondSection:SetScript("OnClick", ui.BarClick)
|
|
secondSection:SetScript("OnEnter", ui.BarEnter)
|
|
secondSection:SetScript("OnLeave", ui.BarLeave)
|
|
|
|
-- create health bar
|
|
if config.showhealthbar then
|
|
local healthBar = CreateFrame("StatusBar", "CursiveHealthBar", secondSection)
|
|
healthBar:SetStatusBarTexture(config.bartexture)
|
|
healthBar:SetStatusBarColor(1, .8, .2, 1)
|
|
healthBar:SetMinMaxValues(0, 100)
|
|
healthBar:SetValue(20)
|
|
healthBar:SetPoint("LEFT", secondSection, "LEFT", ui.padding, 0)
|
|
healthBar:SetWidth(config.healthwidth)
|
|
healthBar:SetHeight(config.height)
|
|
unitFrame.healthBar = healthBar
|
|
|
|
local hp = healthBar:CreateFontString(nil, "HIGH", "GameFontWhite")
|
|
hp:SetPoint("TOPRIGHT", healthBar, "TOPRIGHT", -2, -2)
|
|
hp:SetWidth(30)
|
|
hp:SetHeight(config.height - 4)
|
|
hp:SetFont(STANDARD_TEXT_FONT, config.textsize, "THINOUTLINE")
|
|
hp:SetJustifyH("RIGHT")
|
|
unitFrame.hpText = hp
|
|
|
|
if config.showunitname then
|
|
local name = healthBar:CreateFontString(nil, "HIGH", "GameFontWhite")
|
|
name:SetPoint("TOPLEFT", healthBar, "TOPLEFT", 2, -2)
|
|
name:SetPoint("BOTTOMRIGHT", hp, "BOTTOMLEFT", 2, 0)
|
|
name:SetFont(STANDARD_TEXT_FONT, config.textsize, "THINOUTLINE")
|
|
name:SetJustifyH("LEFT")
|
|
unitFrame.nameText = name
|
|
end
|
|
|
|
-- create health bar backdrops
|
|
if pfUI and pfUI.uf then
|
|
pfUI.api.CreateBackdrop(healthBar)
|
|
healthBar.border = healthBar.backdrop
|
|
else
|
|
healthBar:SetBackdrop(ui.background)
|
|
healthBar:SetBackdropColor(0, 0, 0, 1)
|
|
|
|
local border = CreateFrame("Frame", "CursiveBorder", healthBar.bar)
|
|
border:SetBackdrop(ui.border)
|
|
border:SetBackdropColor(.2, .2, .2, 1)
|
|
border:SetPoint("TOPLEFT", healthBar.bar, "TOPLEFT", -2, 2)
|
|
border:SetPoint("BOTTOMRIGHT", healthBar.bar, "BOTTOMRIGHT", 2, -2)
|
|
healthBar.border = border
|
|
end
|
|
else
|
|
if config.showunitname then
|
|
local name = secondSection:CreateFontString(nil, "HIGH", "GameFontWhite")
|
|
name:SetPoint("TOPLEFT", secondSection, "TOPLEFT", 2, -2)
|
|
name:SetPoint("BOTTOMRIGHT", secondSection, "BOTTOMRIGHT", 2, 0)
|
|
name:SetFont(STANDARD_TEXT_FONT, config.textsize, "THINOUTLINE")
|
|
name:SetWidth(config.healthwidth)
|
|
name:SetHeight(config.height - 4)
|
|
name:SetJustifyH("LEFT")
|
|
unitFrame.nameText = name
|
|
end
|
|
end
|
|
end
|
|
|
|
local function CreateBarThirdSection(unitFrame, guid)
|
|
local config = Cursive.db.profile
|
|
|
|
local thirdSection = CreateFrame("Frame", "Cursive3rdSection", unitFrame)
|
|
|
|
if config.invertbars then
|
|
-- When inverted, this is positioned first (leftmost)
|
|
thirdSection:SetPoint("LEFT", unitFrame, "LEFT", 0, 0)
|
|
else
|
|
-- Normal positioning relative to second section
|
|
thirdSection:SetPoint("LEFT", unitFrame.secondSection, "RIGHT", 0, 0)
|
|
end
|
|
|
|
thirdSection:SetWidth(GetBarThirdSectionWidth())
|
|
thirdSection:SetHeight(config.height)
|
|
thirdSection:EnableMouse(false)
|
|
unitFrame.thirdSection = thirdSection
|
|
|
|
-- display up to maxcurses curses
|
|
for i = 1, config.maxcurses do
|
|
local curse = thirdSection:CreateTexture(nil, "OVERLAY")
|
|
curse:SetWidth(config.curseiconsize)
|
|
curse:SetHeight(config.curseiconsize)
|
|
|
|
if config.invertbars then
|
|
-- When inverted, position from right to left
|
|
local rightOffset = i * ui.padding + ((i - 1) * config.curseiconsize)
|
|
curse:SetPoint("RIGHT", thirdSection, "RIGHT", -rightOffset, 0)
|
|
else
|
|
-- Normal positioning from left to right
|
|
curse:SetPoint("LEFT", thirdSection, "LEFT", i * ui.padding + ((i - 1) * config.curseiconsize), 0)
|
|
end
|
|
|
|
curse.timer = thirdSection:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
curse.timer:SetFontObject(GameFontHighlight)
|
|
curse.timer:SetFont(STANDARD_TEXT_FONT, config.cursetimersize, "OUTLINE")
|
|
curse.timer:SetTextColor(1, 1, 1)
|
|
curse.timer:SetAllPoints(curse)
|
|
|
|
curse.timer:Hide()
|
|
curse:Hide()
|
|
unitFrame["curse" .. i] = curse
|
|
end
|
|
end
|
|
|
|
local function CreateBar(row, col, guid)
|
|
local unitFrame = CreateFrame("Frame", "CursiveUnitFrame", ui.rootBarFrame)
|
|
unitFrame.guid = guid
|
|
|
|
unitFrame:SetScript("OnUpdate", ui.BarUpdate)
|
|
|
|
local config = Cursive.db.profile
|
|
local width = GetBarWidth()
|
|
unitFrame:SetWidth(width)
|
|
unitFrame:SetHeight(config.height)
|
|
|
|
local config = Cursive.db.profile
|
|
if config.invertbars then
|
|
-- Create sections in reverse order: 3 -> 2 -> 1
|
|
CreateBarThirdSection(unitFrame, guid)
|
|
CreateBarSecondSection(unitFrame, guid)
|
|
CreateBarFirstSection(unitFrame, guid)
|
|
else
|
|
-- Normal order: 1 -> 2 -> 3
|
|
CreateBarFirstSection(unitFrame, guid)
|
|
CreateBarSecondSection(unitFrame, guid)
|
|
CreateBarThirdSection(unitFrame, guid)
|
|
end
|
|
|
|
ui.unitFrames[col][row] = unitFrame
|
|
return unitFrame
|
|
end
|
|
|
|
local function GetBarCords(row, col)
|
|
local config = Cursive.db.profile
|
|
local x = (col - 1) * GetBarWidth()
|
|
local y
|
|
if config.expandupwards then
|
|
-- For upward expansion: start from bottom with spacing, then go up
|
|
y = config.spacing + ((row - 1) * (config.height + config.spacing))
|
|
else
|
|
-- For downward expansion: use original logic (don't subtract 1 to account for header)
|
|
y = -(row * (config.height + config.spacing))
|
|
end
|
|
return x, y
|
|
end
|
|
|
|
local function hasAnySpellId(guid, spellIds)
|
|
for i = 1, 16 do
|
|
local texture, stacks, spellSchool, spellId = UnitDebuff(guid, i);
|
|
if not spellId then
|
|
break
|
|
end
|
|
if spellIds[spellId] then
|
|
return spellId
|
|
end
|
|
end
|
|
|
|
for i = 1, 32 do
|
|
local texture, stacks, spellId = UnitBuff(guid, i);
|
|
if not spellId then
|
|
break
|
|
end
|
|
if spellIds[spellId] then
|
|
return spellId
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
local function GetSortedCurses(guidCurses)
|
|
-- Collect keys
|
|
local curseNames = {}
|
|
for key in pairs(guidCurses) do
|
|
table.insert(curseNames, key)
|
|
end
|
|
|
|
if Cursive.db.profile.curseordering == L["Order applied"] then
|
|
table.sort(curseNames, function(a, b)
|
|
return guidCurses[a].start < guidCurses[b].start
|
|
end)
|
|
elseif Cursive.db.profile.curseordering == L["Expiring soonest -> latest"] then
|
|
table.sort(curseNames, function(a, b)
|
|
return Cursive.curses:TimeRemaining(guidCurses[a]) < Cursive.curses:TimeRemaining(guidCurses[b])
|
|
end)
|
|
elseif Cursive.db.profile.curseordering == L["Expiring latest -> soonest"] then
|
|
table.sort(curseNames, function(a, b)
|
|
return Cursive.curses:TimeRemaining(guidCurses[a]) > Cursive.curses:TimeRemaining(guidCurses[b])
|
|
end)
|
|
end
|
|
|
|
local i = 0
|
|
return function()
|
|
i = i + 1
|
|
local key = curseNames[i]
|
|
if key then
|
|
return key, guidCurses[key]
|
|
end
|
|
end
|
|
end
|
|
|
|
local function DisplayGuid(guid)
|
|
if not ui.unitFrames[ui.col] then
|
|
ui.unitFrames[ui.col] = {}
|
|
end
|
|
|
|
local unitFrame
|
|
if ui.unitFrames[ui.col][ui.row] then
|
|
unitFrame = ui.unitFrames[ui.col][ui.row]
|
|
unitFrame.guid = guid
|
|
else
|
|
unitFrame = CreateBar(ui.row, ui.col, guid)
|
|
ui.unitFrames[ui.col][ui.row] = unitFrame
|
|
end
|
|
|
|
local x, y = GetBarCords(ui.row, ui.col)
|
|
|
|
-- update position if required
|
|
local config = Cursive.db.profile
|
|
if not unitFrame.pos or unitFrame.pos ~= x .. y then
|
|
unitFrame:ClearAllPoints()
|
|
if config.expandupwards then
|
|
unitFrame:SetPoint("BOTTOMLEFT", ui.rootBarFrame, "BOTTOMLEFT", x, y)
|
|
else
|
|
unitFrame:SetPoint("TOPLEFT", ui.rootBarFrame, "TOPLEFT", x, y)
|
|
end
|
|
unitFrame.pos = x .. y
|
|
end
|
|
|
|
-- check for shared debuffs
|
|
for sharedDebuffKey, guids in pairs(Cursive.curses.sharedDebuffGuids) do
|
|
if guids[guid] then
|
|
local sharedDebuffSpellIds = Cursive.curses.sharedDebuffs[sharedDebuffKey]
|
|
local spellId = hasAnySpellId(guid, sharedDebuffSpellIds)
|
|
if spellId ~= nil then
|
|
-- add curse to curses
|
|
Cursive.curses:ApplySharedCurse(sharedDebuffKey, spellId, guid, GetTime())
|
|
-- remove guid
|
|
Cursive.curses.sharedDebuffGuids[sharedDebuffKey][guid] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
-- update curses
|
|
local curseNumber = 1
|
|
|
|
-- make sure old curses are hidden
|
|
for i = 1, Cursive.db.profile.maxcurses do
|
|
local curse = unitFrame["curse" .. i]
|
|
curse:Hide()
|
|
curse.timer:Hide()
|
|
end
|
|
|
|
local guidCurses = Cursive.curses.guids[guid]
|
|
if guidCurses then
|
|
for curseName, curseData in GetSortedCurses(guidCurses) do
|
|
if curseNumber > Cursive.db.profile.maxcurses then
|
|
break
|
|
end
|
|
|
|
local remaining = Cursive.curses:TimeRemaining(curseData)
|
|
local curse = unitFrame["curse" .. curseNumber]
|
|
if remaining >= 0 then
|
|
curse:SetTexture(Cursive.curses.trackedCurseIds[curseData.spellID].texture)
|
|
|
|
if curseData["currentPlayer"] == false then
|
|
curse:SetDesaturated(true); -- desaturate if not applied by current player
|
|
else
|
|
curse:SetDesaturated(false); -- saturate if applied by current player
|
|
end
|
|
|
|
-- curse:SetTexCoord(.078, .92, .079, .937) rounded icons
|
|
curse.timer:SetText(remaining)
|
|
curse.timer:Show()
|
|
curse:Show()
|
|
|
|
if remaining < 1 then
|
|
if Cursive.curses:ShouldPlayExpiringSound(curseName, guid) then
|
|
PlaySoundFile("Interface\\AddOns\\Cursive\\sounds\\expiring.mp3")
|
|
end
|
|
elseif Cursive.curses:HasRequestedExpiringSound(curseName, guid) then
|
|
Cursive.curses:EnableExpiringSound(curseName, guid)
|
|
end
|
|
curseNumber = curseNumber + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
unitFrame:Show()
|
|
ui.numDisplayed = ui.numDisplayed + 1
|
|
|
|
local config = Cursive.db.profile
|
|
|
|
-- update row/col
|
|
ui.row = ui.row + 1
|
|
if ui.row > config.maxrow then
|
|
ui.row = 1
|
|
ui.col = ui.col + 1
|
|
if ui.col > config.maxcol then
|
|
ui.maxBarsDisplayed = true
|
|
end
|
|
end
|
|
end
|
|
|
|
local function CheckForCleanup(guid, time)
|
|
local active = UnitExists(guid) and Cursive.filter.alive(guid)
|
|
if active then
|
|
local old = GetTime() - time >= 900 -- >= 15 minutes old
|
|
if old and not UnitIsVisible(guid) then
|
|
active = false
|
|
end
|
|
end
|
|
|
|
if not active then
|
|
-- remove from core
|
|
Cursive.core.remove(guid)
|
|
-- remove from curses
|
|
Cursive.curses:RemoveGuid(guid)
|
|
|
|
-- remove from sharedDebuffGuids
|
|
for sharedDebuffKey, guids in pairs(Cursive.curses.sharedDebuffGuids) do
|
|
if guids[guid] then
|
|
Cursive.curses.sharedDebuffGuids[sharedDebuffKey][guid] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local shouldDisplayGuids = {};
|
|
local displayedGuids = {};
|
|
|
|
ui:SetAllPoints()
|
|
ui:SetScript("OnUpdate", function()
|
|
local config = Cursive.db.profile
|
|
|
|
if not config.enabled then
|
|
return
|
|
end
|
|
|
|
if (this.tick or 1) > GetTime() then
|
|
return
|
|
else
|
|
this.tick = GetTime() + 0.1
|
|
end
|
|
|
|
if not ui.rootBarFrame then
|
|
ui.rootBarFrame = CreateRoot()
|
|
end
|
|
|
|
-- skip if locked (due to moving)
|
|
if ui.rootBarFrame.lock then
|
|
return
|
|
end
|
|
|
|
-- reset display data
|
|
ui.row = 1
|
|
ui.col = 1
|
|
ui.maxBarsDisplayed = false
|
|
ui.numDisplayed = 0
|
|
|
|
-- clear shouldDisplayGuids
|
|
for guid, _ in pairs(shouldDisplayGuids) do
|
|
shouldDisplayGuids[guid] = nil
|
|
end
|
|
|
|
-- clear displayedGuids
|
|
for guid, _ in pairs(displayedGuids) do
|
|
displayedGuids[guid] = nil
|
|
end
|
|
|
|
-- run through all guids and fill with bars
|
|
local title_size = 12 + config.spacing
|
|
|
|
local topMaxHp = 0
|
|
local secondMaxHp = 0
|
|
local thirdMaxHp = 0
|
|
|
|
local topMaxGuid = 0
|
|
local secondMaxGuid = 0
|
|
local thirdMaxGuid = 0
|
|
|
|
local numDisplayable = 0
|
|
|
|
local averageMaxHp = 0
|
|
|
|
local _, currentTargetGuid = UnitExists("target")
|
|
|
|
-- first consider raid marks
|
|
for i = 8, 1, -1 do
|
|
local _, guid = UnitExists("mark" .. i)
|
|
if guid then
|
|
if Cursive:ShouldDisplayGuid(guid) then
|
|
numDisplayable = numDisplayable + 1
|
|
|
|
-- display guid
|
|
displayedGuids[guid] = true
|
|
DisplayGuid(guid)
|
|
if ui.maxBarsDisplayed then
|
|
break
|
|
end
|
|
end
|
|
-- don't try to display this guid again
|
|
shouldDisplayGuids[guid] = false
|
|
end
|
|
end
|
|
|
|
for guid, time in pairs(Cursive.core.guids) do
|
|
-- calculate shouldDisplay
|
|
local shouldDisplay = false
|
|
if shouldDisplayGuids[guid] == nil then
|
|
shouldDisplay = Cursive:ShouldDisplayGuid(guid)
|
|
shouldDisplayGuids[guid] = shouldDisplay
|
|
|
|
if shouldDisplay then
|
|
numDisplayable = numDisplayable + 1
|
|
end
|
|
else
|
|
shouldDisplay = shouldDisplayGuids[guid]
|
|
end
|
|
|
|
-- calculate top 3 max hps
|
|
if shouldDisplay then
|
|
local maxHp = UnitHealthMax(guid)
|
|
if maxHp > topMaxHp then
|
|
thirdMaxHp = secondMaxHp
|
|
thirdMaxGuid = secondMaxGuid
|
|
secondMaxHp = topMaxHp
|
|
secondMaxGuid = topMaxGuid
|
|
topMaxHp = maxHp
|
|
topMaxGuid = guid
|
|
elseif maxHp > secondMaxHp then
|
|
thirdMaxHp = secondMaxHp
|
|
thirdMaxGuid = secondMaxGuid
|
|
secondMaxHp = maxHp
|
|
secondMaxGuid = guid
|
|
elseif maxHp > thirdMaxHp then
|
|
thirdMaxHp = maxHp
|
|
thirdMaxGuid = guid
|
|
end
|
|
else
|
|
CheckForCleanup(guid, time)
|
|
end
|
|
end
|
|
|
|
-- top max hp
|
|
if not ui.maxBarsDisplayed and numDisplayable > ui.numDisplayed and not displayedGuids[topMaxGuid] then
|
|
displayedGuids[topMaxGuid] = true
|
|
DisplayGuid(topMaxGuid)
|
|
end
|
|
|
|
-- second max hp
|
|
if not ui.maxBarsDisplayed and numDisplayable > ui.numDisplayed and not displayedGuids[secondMaxGuid] then
|
|
displayedGuids[secondMaxGuid] = true
|
|
DisplayGuid(secondMaxGuid)
|
|
end
|
|
|
|
-- third max hp
|
|
if not ui.maxBarsDisplayed and numDisplayable > ui.numDisplayed and not displayedGuids[thirdMaxGuid] then
|
|
displayedGuids[thirdMaxGuid] = true
|
|
|
|
DisplayGuid(thirdMaxGuid)
|
|
end
|
|
|
|
-- fill in remaining slots
|
|
for guid, time in pairs(Cursive.core.guids) do
|
|
if ui.maxBarsDisplayed or numDisplayable <= ui.numDisplayed then
|
|
break
|
|
end
|
|
|
|
if not displayedGuids[guid] and shouldDisplayGuids[guid] == true then
|
|
displayedGuids[guid] = true
|
|
DisplayGuid(guid)
|
|
end
|
|
end
|
|
|
|
-- if current target not yet displayed, show it at maxrow/maxcol
|
|
if currentTargetGuid and
|
|
shouldDisplayGuids[currentTargetGuid] and
|
|
not displayedGuids[currentTargetGuid] and
|
|
Cursive.db.profile.alwaysshowcurrenttarget then
|
|
-- replace the last displayed guid with the current target
|
|
displayedGuids[currentTargetGuid] = true
|
|
ui.col = config.maxcol
|
|
ui.row = config.maxrow
|
|
DisplayGuid(currentTargetGuid)
|
|
end
|
|
|
|
-- hide any remaining unit frames
|
|
for col, rows in pairs(ui.unitFrames) do
|
|
for row, unitFrame in pairs(rows) do
|
|
if unitFrame:IsShown() then
|
|
if not displayedGuids[unitFrame.guid] then
|
|
unitFrame:Hide()
|
|
else
|
|
displayedGuids[unitFrame.guid] = nil -- avoid displaying duplicate rows
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end)
|
|
|
|
Cursive.ui = ui
|