diff --git a/api/api.lua b/api/api.lua index faa12971..70c29697 100644 --- a/api/api.lua +++ b/api/api.lua @@ -1333,6 +1333,32 @@ function pfUI.api.CreateBackdropShadow(f) f.backdrop_shadow:SetBackdropBorderColor(0, 0, 0, tonumber(pfUI_config.appearance.border.shadow_intensity)) end +-- [ Set Castbar Shield ] +-- Colors a castbar for a cast that none of the player's own interrupts or +-- silences can stop. The bar and the icon's border both take the shield color, +-- so the state still reads on a bar configured without an icon. Not shielded +-- restores the normal cast/channel color and the configured border. +-- 'bar' [frame] the castbar statusbar +-- 'icon' [frame] the icon frame, or nil for a bar without one +-- 'shielded' [bool] whether the cast is uninterruptible +-- 'isChannel' [bool] selects the unshielded color +function pfUI.api.SetCastbarShield(bar, icon, shielded, isChannel) + if shielded then + bar:SetStatusBarColor(pfUI.api.GetStringColor(C.appearance.castbar.shieldcolor)) + else + bar:SetStatusBarColor(pfUI.api.GetStringColor(C.appearance.castbar[isChannel and "channelcolor" or "castbarcolor"])) + end + + local iconborder = icon and icon.backdrop + if not iconborder then return end + + if shielded then + iconborder:SetBackdropBorderColor(pfUI.api.GetStringColor(C.appearance.castbar.shieldcolor)) + else + iconborder:SetBackdropBorderColor(pfUI.api.GetStringColor(C.appearance.border.color)) + end +end + -- [ Bar Layout Options ] -- -- 'barsize' size of bar in number of buttons -- returns: array of options as strings for pfUI.gui.bar diff --git a/api/config.lua b/api/config.lua index f7d74e68..3f4ff2fc 100644 --- a/api/config.lua +++ b/api/config.lua @@ -156,6 +156,7 @@ function pfUI:LoadConfig() pfUI:UpdateConfig("appearance", "castbar", "castbarcolor", ".7,.7,.9,.8") pfUI:UpdateConfig("appearance", "castbar", "channelcolor", ".9,.9,.7,.8") pfUI:UpdateConfig("appearance", "castbar", "failcolor", "1,.2,.2,.8") + pfUI:UpdateConfig("appearance", "castbar", "shieldcolor", ".8,.45,.45,.8") pfUI:UpdateConfig("appearance", "castbar", "texture", "Interface\\AddOns\\pfUI\\img\\bar") pfUI:UpdateConfig("appearance", "infight", "screen", "0") pfUI:UpdateConfig("appearance", "infight", "aggro", "0") diff --git a/modules/castbar.lua b/modules/castbar.lua index d52e7ba0..7429eab3 100644 --- a/modules/castbar.lua +++ b/modules/castbar.lua @@ -86,7 +86,7 @@ pfUI:RegisterModule("castbar", function () -- Stamp the bar with cast data and render text/icon/lag once. OnUpdate -- then animates the fill from this state without touching C_Spell. - local function StampBar(cb, name, tex, startMs, endMs, spellID, isChannel, delayMs, isTradeskill, rank) + local function StampBar(cb, name, tex, startMs, endMs, spellID, isChannel, delayMs, isTradeskill, rank, noInterrupt) cb.startTime = startMs cb.endTime = endMs cb.isChannel = isChannel @@ -97,7 +97,10 @@ pfUI:RegisterModule("castbar", function () cb:SetAlpha(1) cb.fadeout = nil - cb.bar:SetStatusBarColor(GetStringColor(C.appearance.castbar[isChannel and "channelcolor" or "castbarcolor"])) + -- Shield an uninterruptible cast. Not on the player's own bar: the flag is + -- measured against the reader's own interrupts and silences, so on your own + -- cast it answers a question nobody asked. + SetCastbarShield(cb.bar, cb.icon, noInterrupt and cb.unitstr ~= "player", isChannel) -- Rank: prefer the value the UNIT_SPELLCAST_* event delivered (arg5, passed -- through by RefreshBar). Only the retarget re-poll has no event in hand, so @@ -152,10 +155,10 @@ pfUI:RegisterModule("castbar", function () ClearBar(cb) return end - local name, _, tex, startMs, endMs, isTradeskill, _, _, spellID, _, delayMs = C_Spell.UnitCastingInfo(query) + local name, _, tex, startMs, endMs, isTradeskill, _, noInterrupt, spellID, _, delayMs = C_Spell.UnitCastingInfo(query) local isChan if not name then - name, _, tex, startMs, endMs, _, _, spellID = C_Spell.UnitChannelInfo(query) + name, _, tex, startMs, endMs, _, noInterrupt, spellID = C_Spell.UnitChannelInfo(query) isChan = true end -- Synthetic fallback for abilities the engine treats as instant-cast but @@ -169,7 +172,7 @@ pfUI:RegisterModule("castbar", function () end end if name and startMs and endMs then - StampBar(cb, name, tex, startMs, endMs, spellID, isChan, delayMs, isTradeskill, rank) + StampBar(cb, name, tex, startMs, endMs, spellID, isChan, delayMs, isTradeskill, rank, noInterrupt) else ClearBar(cb) end diff --git a/modules/gui.lua b/modules/gui.lua index 8dcd85e2..457465d3 100644 --- a/modules/gui.lua +++ b/modules/gui.lua @@ -2792,6 +2792,7 @@ pfUI:RegisterModule("gui", function () CreateConfig(nil, T["Use Unit Fonts"], C.castbar, "use_unitfonts", "checkbox") CreateConfig(nil, T["Casting Color"], C.appearance.castbar, "castbarcolor", "color") CreateConfig(nil, T["Channeling Color"], C.appearance.castbar, "channelcolor", "color") + CreateConfig(nil, T["Uninterruptible Color"], C.appearance.castbar, "shieldcolor", "color") CreateConfig(nil, T["Castbar Texture"], C.appearance.castbar, "texture", "dropdown", pfUI.gui.dropdowns.uf_bartexture) CreateConfig(nil, T["Disable Blizzard Castbar"], C.castbar.player, "hide_blizz", "checkbox") end) diff --git a/modules/nameplates.lua b/modules/nameplates.lua index 450dda63..9a2be61d 100644 --- a/modules/nameplates.lua +++ b/modules/nameplates.lua @@ -77,10 +77,10 @@ pfUI:RegisterModule("nameplates", function () -- vs channel itself. Never called per frame. local function PollCastInfo(unit) if not unit then return nil end - local name, _, texture, startMs, endMs, _, _, _, spellID = C_Spell.UnitCastingInfo(unit) + local name, _, texture, startMs, endMs, _, _, noInterrupt, spellID = C_Spell.UnitCastingInfo(unit) local isChannel if not name then - name, _, texture, startMs, endMs, _, _, spellID = C_Spell.UnitChannelInfo(unit) + name, _, texture, startMs, endMs, _, noInterrupt, spellID = C_Spell.UnitChannelInfo(unit) isChannel = true end if not name or not startMs or not endMs then return nil end @@ -92,6 +92,7 @@ pfUI:RegisterModule("nameplates", function () endTime = endMs / 1000, duration = (endMs - startMs) / 1000, isChannel = isChannel, + noInterrupt = noInterrupt, } end @@ -1751,7 +1752,7 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE") -- Relative 0..duration range to avoid float precision loss with large -- absolute timestamps. nameplate.castbar:SetMinMaxValues(0, duration) - nameplate.castbar:SetStatusBarColor(GetStringColor(C.appearance.castbar[(isChannel and "channelcolor" or "castbarcolor")])) + SetCastbarShield(nameplate.castbar, nameplate.castbar.icon, castInfo.noInterrupt, isChannel) if castInfo.icon then nameplate.castbar.icon.tex:SetTexture(castInfo.icon) nameplate.castbar.icon.tex:SetTexCoord(.1,.9,.1,.9)