Files
moon-well-ui/data/addon/ForeverUI/Buffs.lua
T
Adrestie d110de1cbe Chat et barres d'auras a la DA de camelot ; plus aucune globale du client ecrite par l'addon
- Chat : cadre, barre et bouton de retour, colonne, bouton d'amis de camelot ;
  au repos fond, onglets, colonne et saisie s'effacent, allumage au survol
- Barres d'ameliorations et d'affaiblissements (Buffs.lua) : grille, bordures
  par type, clignotement, repli, regroupement, enchantements d'arme
- Souillure : StaticPopupDialogs n'est plus reaffectee (BindEnchant bloque) ;
  menus deroulants, suivi des objectifs, choix d'icone, ajout de canal et
  carte du monde n'ecrivent plus les globales du client ; menus d'unite :
  lignes protegees servies par des boutons securises hors combat, grisees en
  combat ; seule MAP_QUEST_DIFFICULTY reste, par decision
- Gestionnaire d'ensembles : plus d'appel GetEquipmentSetIconInfo(nil)
- Banc : garde des globales ecrites (bytecode Lua 5.1), faux client durci

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 18:36:19 +02:00

647 lines
23 KiB
Lua

-- ForeverUI : les barres d'ameliorations et d'affaiblissements, a la DA de
-- camelot (demande de l'utilisateur, 2026-09-26 ; memoire foreverui-buffs).
--
-- RELEVE -- blizzard_buffframe (buffframe.lua, buffframe.xml,
-- buffframetemplates.xml : pas de variante camelot/ ni mainline/, le .toc les
-- charge tels quels), blizzard_framexmlutil (aurautil.lua et
-- mainline/aurautil.lua, [Family]), blizzard_editmode (mainline/
-- editmodepresetlayouts.lua, [Family] : la disposition « moderne ») :
-- bouton AuraButtonArtTemplate, 30 x 40 : icone 30 x 30 a TOP, duree
-- GameFontNormalSmall sous l'icone (cachee sans duree) ;
-- OVERLAY : bordure d'affaiblissement 40 x 40 et bordure
-- d'enchantement UI-TempEnchant-Border 32 x 32 centrees sur
-- l'icone, symbole TextStatusBarText TOPLEFT (2,-2) (mode
-- daltonien), piles NumberFontNormal BOTTOMRIGHT de l'icone
-- (-2,2)
-- grille AuraContainerMixin : de droite a gauche puis vers le bas,
-- espacement 5 entre les icones -- une colonne tous les 35,
-- une rangee tous les 45 ; chaque bouton pose son TOPRIGHT sur
-- le TOPRIGHT du conteneur
-- ameliorations TOPRIGHT de l'ecran (-255,-10), 11 par rangee, 32 au plus ;
-- le bouton de repli (15 x 30, fleche bag-arrow 10 x 16,
-- surbrillance a 0,4 en ADD) a TOPRIGHT, le conteneur sur son
-- TOPLEFT ; taille (35 x 11 + 15) x (45 x 3)
-- affaiblissements TOPRIGHT de l'ecran (-270,-155), 8 par rangee, 16 au
-- plus, seuls les affaiblissements presents sont ranges ;
-- bordure par type AVEC son icone (ShowDispelType = 1) :
-- ui-debuff-border-<type>-icon, et -default-noicon sans type
-- clignotement AuraContainerWarningFader : sous 31 s, l'icone va et vient
-- entre 0,3 et 1 en 1,5 s (aller 0,75 s, retour 0,75 s)
-- duree SecondsToTimeAbbrev ; blanche sous 90 s
-- (BUFF_DURATION_WARNING_TIME de camelot), jaune au-dessus ;
-- affichee si l'option « durees » est cochee
-- repli une amelioration sans duree, ou a plus de 90 s, se cache
-- quand la barre est repliee ; elle « retombe » dans la barre
-- a 90 s (verification toutes les 0,2 s). Le bouton ne
-- paraît que s'il y a de quoi cacher ; depliee au chargement
-- regroupement si l'option « regrouper » est cochee, le repli s'efface et
-- ces memes ameliorations passent dans une icone
-- (BuffConsolidation, coordonnees de camelot) dont le survol
-- ouvre une bulle : 5 par rangee, a l'echelle 0,8, en (16,-16),
-- marges 9 a droite et 2 en bas
-- enchantements d'arme, AVANT les ameliorations, bordure
-- UI-TempEnchant-Border ; clic droit pour annuler
-- infobulle ANCHOR_BOTTOMLEFT, un cran au-dessus du bouton ; clic droit
-- sur une amelioration pour l'annuler
--
-- CE QUI VIENT DE 3.3.5 : les donnees (UnitAura, GetWeaponEnchantInfo), les
-- options de l'interface (SHOW_BUFF_DURATIONS, CONSOLIDATE_BUFFS,
-- ENABLE_COLORBLIND_MODE) et leurs changements (BuffFrame_UpdatePositions,
-- BuffFrame_Update, qu'on accroche), l'annulation (CancelUnitBuff,
-- CancelItemTempEnchantment -- libres en 3.3.5, ils ne deviennent proteges
-- qu'avec 4.0). Le BuffFrame du client, ses enchantements et son
-- regroupement sont etouffes. PlayerFrame est etouffe lui aussi :
-- PlayerFrame.unit ne suit plus le vehicule, on le calcule comme le cadre
-- joueur (UnitHasVehicleUI).
--
-- ABSENT DE 3.3.5, donc absent ici : les defenses externes
-- (ExternalDefensivesFrame), les affaiblissements mortels
-- (DeadlyDebuffFrame), les auras privees, le type « Bleed ». Le bouton de
-- repli n'a pas d'option dans 3.3.5 (collapseExpandBuffs) : il est actif
-- tant que le regroupement ne l'est pas, comme dans camelot. La bulle du
-- regroupement prend le fond des infobulles de 3.3.5, comme GameTooltip.
local ForeverUI = ForeverUI or {}
_G.ForeverUI = ForeverUI
local B = {}
ForeverUI.Buffs = B
local SEP = string.char(92)
local G = {
largeur = 30, hauteur = 40, icone = 30,
bordure = 40, bordureEnchant = 32,
espace = 5,
repliL = 15, repliH = 30, flecheL = 10, flecheH = 16, surbrillance = 0.4,
alerte = 31, alerteDuree = 90,
periode = 1.5, alphaMin = 0.3, alphaMax = 1,
verifier = 0.2, infobulle = 0.2,
bulleParLigne = 5, bulleEchelle = 0.8, bulleMarge = 16, bulleDroite = 9, bulleBas = 2,
bulleSortie = 10,
}
local BARRES = {
buffs = { nom = "ForeverUIBuffFrame", filtre = "HELPFUL", max = 32, parLigne = 11,
x = -255, y = -10, libelle = "Améliorations" },
debuffs = { nom = "ForeverUIDebuffFrame", filtre = "HARMFUL", max = 16, parLigne = 8,
x = -270, y = -155, libelle = "Affaiblissements", typeVisible = true },
}
-- la bordure par type (DEBUFF_DISPLAY_INFO de camelot)
local TYPES = {
Magic = { "ui-debuff-border-magic-noicon", "ui-debuff-border-magic-icon", "DEBUFF_SYMBOL_MAGIC" },
Curse = { "ui-debuff-border-curse-noicon", "ui-debuff-border-curse-icon", "DEBUFF_SYMBOL_CURSE" },
Disease = { "ui-debuff-border-disease-noicon", "ui-debuff-border-disease-icon", "DEBUFF_SYMBOL_DISEASE" },
Poison = { "ui-debuff-border-poison-noicon", "ui-debuff-border-poison-icon", "DEBUFF_SYMBOL_POISON" },
None = { "ui-debuff-border-default-noicon" },
}
local ENCHANT_BORDURE = "Interface" .. SEP .. "Buttons" .. SEP .. "UI-TempEnchant-Border"
local REGROUPEMENT = "Interface" .. SEP .. "Buttons" .. SEP .. "BuffConsolidation"
-- ------------------------------------------------------------ les options
local function durees() return SHOW_BUFF_DURATIONS == "1" end
local function regrouper() return CONSOLIDATE_BUFFS == "1" end
local function daltonien() return ENABLE_COLORBLIND_MODE == "1" end
-- camelot : repli et regroupement s'excluent
local function repliActif() return not regrouper() end
-- l'unite affichee : le vehicule quand on le pilote
function B.unite()
if UnitHasVehicleUI and UnitHasVehicleUI("player") and UnitExists("vehicle") then
return "vehicle"
end
return "player"
end
-- ------------------------------------------------------------ le clignotement
-- un aller-retour de 1,5 s entre 0,3 et 1, commun a toutes les icones
function B.alphaAlerte(reste)
if reste and reste < G.alerte then
local demi = G.periode / 2
local t = (GetTime() or 0) % G.periode
local p = (t < demi) and (t / demi) or ((G.periode - t) / demi)
return G.alphaMin + (G.alphaMax - G.alphaMin) * p
end
return G.alphaMax
end
-- ------------------------------------------------------------ un bouton
local function filtreDe(b)
if b.auraType == "Buff" or b.auraType == "TempEnchant" then return "HELPFUL" end
if b.auraType == "Debuff" then return "HARMFUL" end
end
local function infobulle(b)
if b.auraType == "TempEnchant" then
GameTooltip:SetOwner(b, "ANCHOR_BOTTOMLEFT")
GameTooltip:SetInventoryItem("player", b.info.ID)
return
end
GameTooltip:SetOwner(b, "ANCHOR_BOTTOMLEFT")
GameTooltip:SetFrameLevel(b:GetFrameLevel() + 2)
GameTooltip:SetUnitAura(b.unite, b.info.index, filtreDe(b))
end
local function majDuree(b, reste)
local montrer = reste and durees()
if montrer then
b.Duration:SetFormattedText(SecondsToTimeAbbrev(reste))
local c = (reste < G.alerteDuree) and HIGHLIGHT_FONT_COLOR or NORMAL_FONT_COLOR
b.Duration:SetVertexColor(c.r, c.g, c.b)
b.Duration:Show()
else
b.Duration:Hide()
end
end
local function surMaj(b, ecoule)
if not b.info then return end
if b.auraType == "TempEnchant" and B.unite() ~= "player" then
b:Hide()
return
end
b:SetAlpha(B.alphaAlerte(b.reste))
b.reste = math.max((b.info.expirationTime or 0) - GetTime(), 0)
majDuree(b, b.reste)
b.tempsBulle = (b.tempsBulle or 0) - (ecoule or 0)
if b.tempsBulle <= 0 then
b.tempsBulle = G.infobulle
if GameTooltip:IsOwned(b) then infobulle(b) end
end
end
local function poserType(b, auraType)
b.auraType = auraType
b.Symbol:Hide()
if auraType == "Buff" then
b.DebuffBorder:Hide()
b.TempEnchantBorder:Hide()
elseif auraType == "Debuff" then
ForeverUI.SetAtlas(b.DebuffBorder, TYPES.None[1])
b.DebuffBorder:Show()
b.TempEnchantBorder:Hide()
elseif auraType == "TempEnchant" then
b.DebuffBorder:Hide()
b.TempEnchantBorder:Show()
end
end
local function poserExpiration(b, info)
if info.expirationTime and info.expirationTime > 0 then
if durees() then b.Duration:Show() else b.Duration:Hide() end
b.reste = info.expirationTime - GetTime()
b:SetScript("OnUpdate", surMaj)
else
b.Duration:Hide()
b:SetScript("OnUpdate", nil)
b.reste = nil
b:SetAlpha(1)
end
end
-- AuraButtonMixin:Update
function B.remplir(b, info, typeVisible)
poserType(b, info.auraType)
b.info = info
b.unite = B.unite()
if info.auraType == "Debuff" then
local t = TYPES[info.debuffType or ""] or TYPES.None
ForeverUI.SetAtlas(b.DebuffBorder, (typeVisible and t[2]) or t[1])
if daltonien() and t[3] then
b.Symbol:SetText(_G[t[3]] or "")
b.Symbol:Show()
end
end
poserExpiration(b, info)
b.Icon:SetTexture(info.texture)
if (info.count or 0) > 1 then
b.Count:SetText(info.count)
b.Count:Show()
else
b.Count:Hide()
end
if GameTooltip:IsOwned(b) then infobulle(b) end
end
function B.creerBouton(parent, nom)
local b = CreateFrame("Button", nom, parent)
b:SetWidth(G.largeur)
b:SetHeight(G.hauteur)
b.Icon = b:CreateTexture(nil, "BACKGROUND")
b.Icon:SetWidth(G.icone)
b.Icon:SetHeight(G.icone)
b.Icon:SetPoint("TOP", b, "TOP", 0, 0)
b.Duration = b:CreateFontString(nil, "BACKGROUND", "GameFontNormalSmall")
b.Duration:SetPoint("TOP", b.Icon, "BOTTOM", 0, 0)
b.Duration:Hide()
b.DebuffBorder = b:CreateTexture(nil, "OVERLAY")
b.DebuffBorder:SetWidth(G.bordure)
b.DebuffBorder:SetHeight(G.bordure)
b.DebuffBorder:SetPoint("CENTER", b.Icon, "CENTER", 0, 0)
b.TempEnchantBorder = b:CreateTexture(nil, "OVERLAY")
b.TempEnchantBorder:SetTexture(ENCHANT_BORDURE)
b.TempEnchantBorder:SetWidth(G.bordureEnchant)
b.TempEnchantBorder:SetHeight(G.bordureEnchant)
b.TempEnchantBorder:SetPoint("CENTER", b.Icon, "CENTER", 0, 0)
b.Symbol = b:CreateFontString(nil, "OVERLAY", "TextStatusBarText")
b.Symbol:SetPoint("TOPLEFT", b, "TOPLEFT", 2, -2)
b.Count = b:CreateFontString(nil, "OVERLAY", "NumberFontNormal")
b.Count:SetPoint("BOTTOMRIGHT", b.Icon, "BOTTOMRIGHT", -2, 2)
poserType(b, nil)
b:RegisterForClicks("RightButtonUp")
b:SetScript("OnClick", function(self, bouton)
if bouton ~= "RightButton" or not self.info then return end
if self.auraType == "Buff" then
CancelUnitBuff(self.unite, self.info.index, "HELPFUL")
elseif self.auraType == "TempEnchant" then
CancelItemTempEnchantment(self.info.ID == 16 and 1 or 2)
end
end)
b:SetScript("OnEnter", function(self) if self.info then infobulle(self) end end)
b:SetScript("OnLeave", function() GameTooltip:Hide() end)
b:Hide()
return b
end
-- ------------------------------------------------------------ la grille
-- de droite a gauche puis vers le bas ; ranges = les boutons a poser
local function ranger(conteneur, boutons, parLigne)
for i, b in ipairs(boutons) do
local col, ligne = (i - 1) % parLigne, math.floor((i - 1) / parLigne)
b:ClearAllPoints()
b:SetPoint("TOPRIGHT", conteneur, "TOPRIGHT",
-col * (G.largeur + G.espace), -ligne * (G.hauteur + G.espace))
end
end
-- ------------------------------------------------------------ une barre
local function creerBarre(cle)
local c = BARRES[cle]
local f = CreateFrame("Frame", c.nom, UIParent)
f:SetFrameStrata("LOW")
f.cle, f.c = cle, c
f.conteneur = CreateFrame("Frame", nil, f)
f.conteneur:SetWidth(1)
f.conteneur:SetHeight(1)
f.boutons = {}
for i = 1, c.max do
f.boutons[i] = B.creerBouton(f.conteneur, c.nom .. "Button" .. i)
end
local lignes = math.ceil(c.max / c.parLigne)
local largeur = (G.largeur + G.espace) * c.parLigne
if cle == "buffs" then largeur = largeur + G.repliL end
f:SetWidth(largeur)
f:SetHeight((G.hauteur + G.espace) * lignes)
f.auras = {}
return f
end
-- le bouton de repli : bag-arrow, retourne quand la barre est depliee
local function orienterFleche(t, retourne)
local e = ForeverUI.AtlasEntry("bag-arrow")
if not e then return end
t:SetTexture(e[1])
local u1, u2, v1, v2 = e[2], e[3], e[4], e[5]
if retourne then
t:SetTexCoord(u2, v2, u2, v1, u1, v2, u1, v1)
else
t:SetTexCoord(u1, v1, u1, v2, u2, v1, u2, v2)
end
end
function B.orienterRepli()
local r = B.buffs.repli
-- les icones vont vers la gauche : depliee, la fleche est retournee (pi)
local deplie = r:GetChecked() and true or false
for _, t in ipairs({ r:GetNormalTexture(), r:GetPushedTexture(), r:GetHighlightTexture() }) do
orienterFleche(t, deplie)
end
end
local function creerRepli(f)
local r = CreateFrame("CheckButton", f.c.nom .. "CollapseAndExpandButton", f)
r:SetWidth(G.repliL)
r:SetHeight(G.repliH)
r:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, 0)
local e = ForeverUI.AtlasEntry("bag-arrow")
r:SetNormalTexture(e and e[1] or "")
r:SetPushedTexture(e and e[1] or "")
r:SetHighlightTexture(e and e[1] or "", "ADD")
for _, t in ipairs({ r:GetNormalTexture(), r:GetPushedTexture(), r:GetHighlightTexture() }) do
t:ClearAllPoints()
t:SetWidth(G.flecheL)
t:SetHeight(G.flecheH)
t:SetPoint("CENTER", r, "CENTER", 0, 0)
end
r:GetHighlightTexture():SetAlpha(G.surbrillance)
r:SetChecked(true)
r:SetScript("OnClick", function(self)
B.deplie = self:GetChecked() and true or false
B.orienterRepli()
B.maj()
end)
f.repli = r
f.conteneur:SetPoint("TOPRIGHT", r, "TOPLEFT", 0, 0)
return r
end
-- l'icone du regroupement et sa bulle
local function creerRegroupement(f)
local b = B.creerBouton(f.conteneur, f.c.nom .. "ConsolidatedBuffs")
poserType(b, "Buff")
b.Icon:SetTexture(REGROUPEMENT)
b.Icon:SetTexCoord(0.109375, 0.390625, 0.21875, 0.78125)
b:SetScript("OnClick", nil)
b:SetScript("OnLeave", nil)
b.nombre = 0
local bulle = CreateFrame("Frame", f.c.nom .. "ConsolidatedBuffsTooltip", b)
bulle:SetFrameStrata("TOOLTIP")
bulle:SetClampedToScreen(true)
bulle:SetPoint("TOPLEFT", b.Icon, "BOTTOMLEFT", 0, 0)
bulle:SetBackdrop({
bgFile = "Interface" .. SEP .. "Tooltips" .. SEP .. "UI-Tooltip-Background",
edgeFile = "Interface" .. SEP .. "Tooltips" .. SEP .. "UI-Tooltip-Border",
tile = true, tileSize = 16, edgeSize = 16,
insets = { left = 4, right = 4, top = 4, bottom = 4 },
})
bulle:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
bulle:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
bulle:Hide()
local auras = CreateFrame("Frame", nil, bulle)
auras:SetScale(G.bulleEchelle)
auras:SetPoint("TOPLEFT", bulle, "TOPLEFT", G.bulleMarge, -G.bulleMarge)
auras:SetWidth(1)
auras:SetHeight(1)
bulle.auras = auras
bulle.boutons = {}
for i = 1, BARRES.buffs.max do
bulle.boutons[i] = B.creerBouton(auras, f.c.nom .. "ConsolidatedBuffsTooltipButton" .. i)
end
bulle:SetScript("OnUpdate", function(self)
local m = G.bulleSortie
if not self:IsMouseOver(m, -m, -m, m) and not b:IsMouseOver(m, -m, -m, m) then
self:Hide()
end
end)
b:SetScript("OnEnter", function() B.remplirBulle(); bulle:Show() end)
b:SetScript("OnHide", function() bulle:Hide() end)
b.bulle = bulle
f.regroupement = b
return b
end
-- la bulle : les ameliorations cachees, 5 par rangee de gauche a droite
function B.remplirBulle()
local b = B.buffs.regroupement
local bulle = b.bulle
local n = 0
for _, info in ipairs(B.buffs.auras) do
if info.cachable then
n = n + 1
local bouton = bulle.boutons[n]
if not bouton then break end
B.remplir(bouton, info)
bouton:Show()
local col, ligne = (n - 1) % G.bulleParLigne, math.floor((n - 1) / G.bulleParLigne)
bouton:ClearAllPoints()
bouton:SetPoint("TOPLEFT", bulle.auras, "TOPLEFT",
col * (G.largeur + G.espace), -ligne * (G.hauteur + G.espace))
end
end
for i = n + 1, #bulle.boutons do
bulle.boutons[i].info = nil
bulle.boutons[i]:Hide()
end
local l = (G.largeur + G.espace) * math.min(G.bulleParLigne, n)
local h = (G.hauteur + G.espace) * math.ceil(n / G.bulleParLigne)
bulle:SetWidth((G.bulleMarge + l) * G.bulleEchelle + G.bulleDroite)
bulle:SetHeight((G.bulleMarge + h) * G.bulleEchelle + G.bulleBas)
end
-- ------------------------------------------------------------ les donnees
-- les enchantements d'arme : main droite, puis main gauche
local function enchantements(liste)
local maintenant = GetTime()
local aMain, expMain, chMain, aGauche, expGauche, chGauche = GetWeaponEnchantInfo()
for _, e in ipairs({ { aMain, expMain, chMain, 16 }, { aGauche, expGauche, chGauche, 17 } }) do
if e[1] then
local reste = (e[2] or 0) / 1000
local info = {
auraType = "TempEnchant",
texture = GetInventoryItemTexture("player", e[4]),
count = e[3] or 0,
expirationTime = maintenant + reste,
ID = e[4],
}
info.cachable = reste > G.alerteDuree
table.insert(liste, info)
end
end
end
local function auras(unite, filtre, max, liste)
local maintenant = GetTime()
for i = 1, max do
local nom, _, icone, piles, typeDissip, duree, expiration = UnitAura(unite, i, filtre)
if not nom then break end
local info = {
auraType = (filtre == "HELPFUL") and "Buff" or "Debuff",
index = i,
texture = icone,
count = piles or 0,
debuffType = typeDissip,
duration = duree or 0,
expirationTime = expiration or 0,
}
if filtre == "HELPFUL" then
info.cachable = (info.duration == 0) or (info.expirationTime == 0)
or ((info.expirationTime - maintenant) > G.alerteDuree)
end
table.insert(liste, info)
end
end
-- ------------------------------------------------------------ la mise a jour
B.deplie = true
local function deplie()
if repliActif() then return B.deplie end
return false
end
function B.majBuffs()
local f = B.buffs
local liste = {}
if B.unite() == "player" then enchantements(liste) end
auras(B.unite(), "HELPFUL", f.c.max, liste)
f.auras = liste
local cachables = 0
for _, info in ipairs(liste) do
if info.cachable then cachables = cachables + 1 end
end
f.cachables = cachables
-- le regroupement
local r = f.regroupement
r.nombre = cachables
r.Count:SetText(cachables)
local avecRegroupement = regrouper() and cachables > 0
if avecRegroupement then r:Show() else r:Hide() end
-- les boutons
local ouvert = deplie()
local suivant = 1
for _, b in ipairs(f.boutons) do
local info
while suivant <= #liste do
local candidat = liste[suivant]
suivant = suivant + 1
if ouvert or not candidat.cachable then
info = candidat
break
end
end
if info then
B.remplir(b, info)
b:Show()
else
b.info = nil
b:SetScript("OnUpdate", nil)
b:Hide()
end
end
local ranges = {}
if avecRegroupement then table.insert(ranges, r) end
for _, b in ipairs(f.boutons) do table.insert(ranges, b) end
ranger(f.conteneur, ranges, f.c.parLigne)
-- le repli : seulement s'il y a de quoi cacher
if repliActif() and cachables > 0 then f.repli:Show() else f.repli:Hide() end
f.repli:SetChecked(B.deplie)
B.orienterRepli()
if r.bulle:IsShown() then B.remplirBulle() end
-- la verification des ameliorations qui retombent
f.attente = (not ouvert and cachables > 0) and G.verifier or nil
end
function B.majDebuffs()
local f = B.debuffs
local liste = {}
auras(B.unite(), "HARMFUL", f.c.max, liste)
f.auras = liste
local ranges = {}
for i, b in ipairs(f.boutons) do
local info = liste[i]
if info then
B.remplir(b, info, f.c.typeVisible)
b:Show()
table.insert(ranges, b)
else
b.info = nil
b:SetScript("OnUpdate", nil)
b:Hide()
end
end
ranger(f.conteneur, ranges, f.c.parLigne)
end
function B.maj()
B.majBuffs()
B.majDebuffs()
end
-- ------------------------------------------------------------ la construction
B.buffs = creerBarre("buffs")
B.debuffs = creerBarre("debuffs")
creerRepli(B.buffs)
creerRegroupement(B.buffs)
B.orienterRepli()
B.debuffs.conteneur:SetPoint("TOPRIGHT", B.debuffs, "TOPRIGHT", 0, 0)
for _, cle in ipairs({ "buffs", "debuffs" }) do
local c = BARRES[cle]
ForeverUI.Layout.Register(B[cle], cle, c.libelle, "TOPRIGHT", "TOPRIGHT", c.x, c.y)
end
-- le BuffFrame du client, ses enchantements, son regroupement
for _, nom in ipairs({ "BuffFrame", "TemporaryEnchantFrame", "ConsolidatedBuffs", "ConsolidatedBuffsTooltip" }) do
ForeverUI.Suppress(_G[nom])
end
-- les options de l'interface (durees, regroupement) passent par ces deux-la
if BuffFrame_UpdatePositions then hooksecurefunc("BuffFrame_UpdatePositions", function() B.maj() end) end
if BuffFrame_Update then hooksecurefunc("BuffFrame_Update", function() B.maj() end) end
local veille = CreateFrame("Frame")
veille:RegisterEvent("UNIT_AURA")
veille:RegisterEvent("PLAYER_ENTERING_WORLD")
veille:RegisterEvent("UNIT_ENTERED_VEHICLE")
veille:RegisterEvent("UNIT_EXITED_VEHICLE")
veille:SetScript("OnEvent", function(self, evenement, unite)
if evenement == "UNIT_AURA" then
if unite == B.unite() then B.maj() end
elseif evenement == "PLAYER_ENTERING_WORLD" or unite == "player" then
B.maj()
end
end)
-- toutes les 0,2 s : les enchantements d'arme (3.3.5 n'a pas d'evenement,
-- son TemporaryEnchantFrame les lit a chaque image) et les ameliorations
-- qui retombent dans la barre repliee
local function signatureEnchants()
if B.unite() ~= "player" then return "" end
local a, _, ca, g, _, cg = GetWeaponEnchantInfo()
return tostring(a) .. ":" .. tostring(ca) .. ":" .. tostring(GetInventoryItemTexture("player", 16))
.. "|" .. tostring(g) .. ":" .. tostring(cg) .. ":" .. tostring(GetInventoryItemTexture("player", 17))
end
veille.temps = 0
veille:SetScript("OnUpdate", function(self, ecoule)
self.temps = self.temps - (ecoule or 0)
if self.temps > 0 then return end
self.temps = G.verifier
local s = signatureEnchants()
if s ~= self.enchants then
self.enchants = s
B.maj()
return
end
local f = B.buffs
if f.attente then
local maintenant = GetTime()
for _, info in ipairs(f.auras) do
if info.cachable and info.expirationTime and info.expirationTime > 0
and (info.expirationTime - maintenant) <= G.alerteDuree then
B.maj()
return
end
end
end
end)
B.veille = veille
B.maj()
-- TEMOIN -- /fui buffs
function ForeverUI.BuffsDebug()
local dire = function(t) DEFAULT_CHAT_FRAME:AddMessage("|cff66ccffForeverUI|r " .. t) end
local f = B.buffs
local montres = 0
for _, b in ipairs(f.boutons) do if b:IsShown() then montres = montres + 1 end end
dire(string.format("ameliorations : unite %s, %d auras, %d cachables, %d montrees | repli %s (deplie %s) | regroupement %s (%d) | durees %s",
B.unite(), #f.auras, f.cachables or 0, montres, f.repli:IsShown() and "visible" or "cache", tostring(B.deplie),
f.regroupement:IsShown() and "visible" or "cache", f.regroupement.nombre or 0, tostring(durees())))
local d = B.debuffs
local types = {}
for _, info in ipairs(d.auras) do table.insert(types, tostring(info.debuffType or "aucun")) end
dire(string.format("affaiblissements : %d (%s)", #d.auras, table.concat(types, ", ")))
end