d110de1cbe
- 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>
714 lines
25 KiB
Lua
714 lines
25 KiB
Lua
-- ForeverUI : les cadres de groupe (etape 1 du chantier des groupes, memoire
|
|
-- foreverui-groupes).
|
|
--
|
|
-- RELEVE -- camelot charge pour son groupe les fichiers de blizzard_unitframe
|
|
-- shared/partyframe.* et mainline/partyframetemplates.xml, partymemberframe.lua
|
|
-- (aucun fichier camelot/ ne les remplace). Valeurs du code, pas d'estimation.
|
|
--
|
|
-- conteneur PartyFrame, empile vertical, haut vers le bas : membre de
|
|
-- 120 x 53, espacement 10 -- 26 si la CVar showPartyPets est
|
|
-- active --, donc un pas de 63 (79 avec familiers) ; ancre sur le
|
|
-- TOPRIGHT du gestionnaire de raid en (0, -7), lequel est plie a
|
|
-- (-200, -140) pour 222 de large : (22, -147) sur l'ecran.
|
|
-- membre PartyMemberFrameTemplate, SecureUnitButtonTemplate :
|
|
-- portrait 37 x 37 (7, -6) ; art UI-HUD-UnitFrame-Party-PortraitOn
|
|
-- (1, -2) ; vie 70 x 10 (45, -19), atlas ...-Bar-Health, jamais
|
|
-- teintee (lockColor) ; ressource 74 x 7 (41, -30), atlas
|
|
-- ...-Bar-<Mana|Rage|Focus|Energy|RunicPower> ; nom
|
|
-- GameFontNormalSmall 57 x 12 (46, -6) ; textes des barres
|
|
-- TextStatusBarText au centre ; lueur de menace ...-InCombat
|
|
-- (1, -2) teinte GetThreatStatusColor ; lueur d'affaiblissement
|
|
-- ...-Status (1, -2) teinte du type ; chef / guide 16 x 16, BOTTOM
|
|
-- sur le TOP (-10, -6) ; PvP a l'echelle 0,6, centre (24, -68) a
|
|
-- cette echelle ; deconnexion Disconnect-Icon 64 x 64 LEFT (-7, -1) ;
|
|
-- role roleicon-tiny-* 12 x 12 TOPRIGHT (-5, -5) ; appel 36 x 36
|
|
-- au centre du portrait (0, -2), UI-LFG-*Mark, reste 10 s puis
|
|
-- s'efface en 1,5 s ; 4 affaiblissements de 15 x 15 a (48, -43),
|
|
-- ecart 2, bordure UI-Debuff-Overlays, pile NumberFontNormalSmall.
|
|
-- etats mort : portrait 0,35 ; fantome 0,2 / 0,2 / 0,75 ; vie <= 20 % :
|
|
-- portrait rouge qui bat (alpha 127/255 a 1, demi-periodes de
|
|
-- 0,5 s) ; deconnecte : vie pleine desaturee, portrait desature,
|
|
-- icone ; vehicule : art, lueurs, barres et nom du vehicule, le
|
|
-- cadre suit partypetN, le familier suit le joueur.
|
|
-- familier 64 x 23 a (23, -43) : portrait 18 x 18 (3, -3), art et lueur
|
|
-- a l'echelle 0,5, vie 71 x 10 a l'echelle 0,5 en (43, -18),
|
|
-- teinte (0, 1, 0), grise si deconnecte ; clic droit sans menu.
|
|
-- survol l'infobulle de l'unite (GameTooltip_SetDefaultAnchor, SetUnit)
|
|
-- et celle des buffs, TOPLEFT sur le membre en (47, -25).
|
|
-- visible en groupe, pas en raid (ShouldShowPartyFrames).
|
|
--
|
|
-- CE QUE 3.3.5 NE SAIT PAS FAIRE, ET CE QUI LE REMPLACE :
|
|
-- * pas de masque : les barres sont posees a nu ; le masque de la vie
|
|
-- coincide avec la barre, celui de la ressource lui retire un pixel a
|
|
-- gauche (repris) et un biseau de 1 a 3 pixels en haut a gauche (non
|
|
-- repris) ;
|
|
-- * pas de prediction de soins ni d'absorptions, ni phase, ni invocation,
|
|
-- ni "dans un autre groupe" (l'icone d'absence) ;
|
|
-- * pas d'echelle sur une texture : les tailles a 0,5 / 0,6 sont calculees ;
|
|
-- * l'appel reprend les marques de camelot, decoupees de leur feuille de
|
|
-- 2048 (tools/decouper_marques.py) ;
|
|
-- * pas de ligne UNIT_POPUP_RIGHT_CLICK dans l'infobulle : la chaine
|
|
-- n'existe pas dans la langue du client ;
|
|
-- * l'infobulle des buffs est celle du client (PartyMemberBuffTooltip), a la
|
|
-- place que camelot donne a la sienne.
|
|
--
|
|
-- SECURITE. Les membres et leurs familiers sont des boutons securises, montres
|
|
-- par RegisterUnitWatch ; le conteneur est cache en raid par un pilote d'etat
|
|
-- -- les deux tiennent en combat. Les cadres de groupe du client sont tenus
|
|
-- caches par un pilote d'etat eux aussi : d'autres fonctions (le client,
|
|
-- l'addon HD) peuvent les reafficher, meme en combat.
|
|
|
|
local ForeverUI = ForeverUI or {}
|
|
_G.ForeverUI = ForeverUI
|
|
|
|
local SEP = string.char(92)
|
|
|
|
-- une table : Lua 5.1 limite a 60 les valeurs capturees par une fonction
|
|
local P = {
|
|
membreL = 120, membreH = 53, espacement = 10, espacementFamiliers = 26, bas = 2,
|
|
x = 22, y = -147,
|
|
art = "ui-hud-unitframe-party-portraiton",
|
|
artVehicule = "ui-hud-unitframe-party-portraiton-vehicle",
|
|
lueur = "ui-hud-unitframe-party-portraiton-incombat",
|
|
lueurVehicule = "ui-hud-unitframe-party-portraiton-vehicle-incombat",
|
|
statut = "ui-hud-unitframe-party-portraiton-status",
|
|
statutVehicule = "ui-hud-unitframe-party-portraiton-vehicle-status",
|
|
vie = "ui-hud-unitframe-party-portraiton-bar-health",
|
|
vieVehicule = "ui-hud-unitframe-party-portraiton-vehicle-bar-health",
|
|
chef = "ui-hud-unitframe-player-group-leadericon",
|
|
guide = "ui-hud-unitframe-player-group-guideicon",
|
|
pvpLibre = "ui-hud-unitframe-player-pvp-ffaicon",
|
|
pvpHorde = "ui-hud-unitframe-player-pvp-hordeicon",
|
|
pvpAlliance = "ui-hud-unitframe-player-pvp-allianceicon",
|
|
pvpEchelle = 0.6,
|
|
deconnexion = "Interface" .. SEP .. "CharacterFrame" .. SEP .. "Disconnect-Icon",
|
|
bordureAura = "Interface" .. SEP .. "Buttons" .. SEP .. "UI-Debuff-Overlays",
|
|
marques = {
|
|
ready = "Interface" .. SEP .. "ForeverUI" .. SEP .. "lfgframe" .. SEP .. "ui-lfg-readymark",
|
|
notready = "Interface" .. SEP .. "ForeverUI" .. SEP .. "lfgframe" .. SEP .. "ui-lfg-declinemark",
|
|
waiting = "Interface" .. SEP .. "ForeverUI" .. SEP .. "lfgframe" .. SEP .. "ui-lfg-pendingmark",
|
|
},
|
|
appelReste = 10, appelFondu = 1.5,
|
|
auras = 4, auraCote = 15, auraEcart = 2,
|
|
pouls = 0.5, poulsMin = 127 / 255,
|
|
-- normal / vehicule : ancres et largeurs posees par ToPlayerArt et
|
|
-- ToVehicleArt
|
|
joueur = { art = { 1, -2 }, lueur = { 1, -2 }, statut = { 1, -2 }, vie = { 45, -19, 70 },
|
|
ressource = { 42, -30, 73 }, nom = { 46, -6, 57 } },
|
|
vehicule = { art = { 0, 0 }, lueur = { -4, 4 }, statut = { -3, 3 }, vie = { 48, -18, 67 },
|
|
ressource = { 45, -29, 70 }, nom = { 49, -6, 56 } },
|
|
}
|
|
|
|
-- la ressource : l'atlas se compose du jeton de la ressource
|
|
local RESSOURCE = { MANA = "Mana", RAGE = "Rage", FOCUS = "Focus", ENERGY = "Energy", RUNIC_POWER = "RunicPower" }
|
|
|
|
local function atlasRessource(jeton, vehicule)
|
|
local nom = RESSOURCE[jeton or ""] or "Mana"
|
|
return "ui-hud-unitframe-party-portraiton" .. (vehicule and "-vehicle" or "") .. "-bar-" .. string.lower(nom)
|
|
end
|
|
|
|
local G = {} -- l'etat partage
|
|
ForeverUI.PartyFrame = G
|
|
|
|
-- ----------------------------------------------------------------- le conteneur
|
|
|
|
local conteneur = CreateFrame("Frame", "ForeverUIPartyFrame", UIParent)
|
|
conteneur:SetFrameStrata("LOW")
|
|
conteneur:SetWidth(P.membreL)
|
|
G.conteneur = conteneur
|
|
|
|
local function pas()
|
|
local familiers = GetCVarBool and GetCVarBool("showPartyPets")
|
|
return P.membreH + (familiers and P.espacementFamiliers or P.espacement)
|
|
end
|
|
|
|
-- ------------------------------------------------------------------ les pieces
|
|
|
|
local function champ(parent, couche, police)
|
|
local fs = parent:CreateFontString(nil, couche or "OVERLAY", police)
|
|
return fs
|
|
end
|
|
|
|
local function creerAuras(parent, nom, x, y, unite)
|
|
local auras = {}
|
|
for k = 1, P.auras do
|
|
local b = CreateFrame("Button", nom .. "Debuff" .. k, parent)
|
|
b:SetWidth(P.auraCote)
|
|
b:SetHeight(P.auraCote)
|
|
b:SetPoint("TOPLEFT", parent, "TOPLEFT", x + (k - 1) * (P.auraCote + P.auraEcart), y)
|
|
b.icone = b:CreateTexture(nil, "ARTWORK")
|
|
b.icone:SetAllPoints(b)
|
|
b.bordure = b:CreateTexture(nil, "OVERLAY")
|
|
b.bordure:SetTexture(P.bordureAura)
|
|
b.bordure:SetTexCoord(0.296875, 0.5703125, 0, 0.515625)
|
|
b.bordure:SetPoint("TOPLEFT", b, "TOPLEFT", -1, 1)
|
|
b.bordure:SetPoint("BOTTOMRIGHT", b, "BOTTOMRIGHT", 1, -1)
|
|
b.pile = b:CreateFontString(nil, "OVERLAY", "NumberFontNormalSmall")
|
|
b.pile:SetPoint("BOTTOMRIGHT", b, "BOTTOMRIGHT", 5, 0)
|
|
b.recharge = CreateFrame("Cooldown", nil, b)
|
|
b.recharge:SetReverse(true)
|
|
b.recharge:SetPoint("CENTER", b, "CENTER", 0, -1)
|
|
b.recharge:SetWidth(P.auraCote)
|
|
b.recharge:SetHeight(P.auraCote)
|
|
b:SetScript("OnEnter", function(self)
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
|
GameTooltip:SetUnitDebuff(self.unite, self.indice, self.filtre)
|
|
end)
|
|
b:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
b:Hide()
|
|
auras[k] = b
|
|
end
|
|
return auras
|
|
end
|
|
|
|
-- les affaiblissements : la regle de RefreshDebuffs (le filtre "RAID" si
|
|
-- l'option des affaiblissements dissipables est active et l'unite aidable)
|
|
local function majAuras(auras, unite)
|
|
local filtre
|
|
if GetCVarBool("showDispelDebuffs") and UnitCanAssist("player", unite) then
|
|
filtre = "RAID"
|
|
end
|
|
local couleur
|
|
for k, b in ipairs(auras) do
|
|
local nom, _, icone, pile, type, duree, fin = UnitDebuff(unite, k, filtre)
|
|
if icone then
|
|
b.unite, b.indice, b.filtre = unite, k, filtre
|
|
b.icone:SetTexture(icone)
|
|
local c = DebuffTypeColor[type or "none"] or DebuffTypeColor["none"]
|
|
b.bordure:SetVertexColor(c.r, c.g, c.b)
|
|
if pile and pile > 1 then
|
|
b.pile:SetText(pile > 99 and "*" or pile)
|
|
else
|
|
b.pile:SetText("")
|
|
end
|
|
if duree and duree > 0 and fin then
|
|
CooldownFrame_SetTimer(b.recharge, fin - duree, duree, 1)
|
|
else
|
|
b.recharge:Hide()
|
|
end
|
|
b:Show()
|
|
if type and not couleur then couleur = c end
|
|
else
|
|
b:Hide()
|
|
end
|
|
end
|
|
return couleur
|
|
end
|
|
|
|
-- --------------------------------------------------------------- un familier
|
|
|
|
local function creerFamilier(membre, i)
|
|
local f = CreateFrame("Button", "ForeverUIPartyMemberFrame" .. i .. "PetFrame", membre, "SecureUnitButtonTemplate")
|
|
f:SetWidth(64)
|
|
f:SetHeight(23)
|
|
f:SetFrameStrata("LOW")
|
|
f:SetPoint("TOPLEFT", membre, "TOPLEFT", 23, -43)
|
|
f.unit = "partypet" .. i
|
|
f:SetAttribute("unit", f.unit)
|
|
f:SetAttribute("*type1", "target")
|
|
f:SetAttribute("toggleForVehicle", true)
|
|
f:RegisterForClicks("AnyUp")
|
|
f.portrait = f:CreateTexture(nil, "BACKGROUND")
|
|
f.portrait:SetWidth(18)
|
|
f.portrait:SetHeight(18)
|
|
f.portrait:SetPoint("TOPLEFT", f, "TOPLEFT", 3, -3)
|
|
-- l'art et la lueur a l'echelle 0,5 : 120 x 49 -> 60 x 24,5 ; 114 x 47 -> 57 x 23,5
|
|
f.art = f:CreateTexture(nil, "ARTWORK")
|
|
ForeverUI.SetAtlas(f.art, P.art, true)
|
|
f.art:SetWidth(60)
|
|
f.art:SetHeight(24.5)
|
|
f.art:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -0.5)
|
|
local dessus = CreateFrame("Frame", nil, f)
|
|
dessus:SetAllPoints(f)
|
|
dessus:SetFrameLevel(f:GetFrameLevel() + 1)
|
|
f.lueur = dessus:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(f.lueur, P.lueur, true)
|
|
f.lueur:SetWidth(57)
|
|
f.lueur:SetHeight(23.5)
|
|
f.lueur:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -0.5)
|
|
f.lueur:Hide()
|
|
-- la vie : 71 x 10 a (43, -18), a l'echelle 0,5
|
|
f.vie = dessus:CreateTexture(nil, "BORDER")
|
|
f.vie:SetPoint("TOPLEFT", f, "TOPLEFT", 21.5, -9)
|
|
f.auras = creerAuras(f, f:GetName(), 24, -16)
|
|
f:SetScript("OnEnter", function(self)
|
|
GameTooltip_SetDefaultAnchor(GameTooltip, self)
|
|
GameTooltip:SetUnit(self.affiche or self.unit)
|
|
GameTooltip:Show()
|
|
end)
|
|
f:SetScript("OnLeave", function() GameTooltip:FadeOut() end)
|
|
return f
|
|
end
|
|
|
|
-- ----------------------------------------------------------------- un membre
|
|
|
|
local function creerMembre(i)
|
|
local m = CreateFrame("Button", "ForeverUIPartyMemberFrame" .. i, conteneur, "SecureUnitButtonTemplate")
|
|
m:SetID(i)
|
|
m:SetWidth(P.membreL)
|
|
m:SetHeight(P.membreH)
|
|
m:SetFrameStrata("LOW")
|
|
m.unite = "party" .. i
|
|
m.unit = m.unite
|
|
m:SetAttribute("unit", m.unite)
|
|
m:SetAttribute("*type1", "target")
|
|
m:SetAttribute("*type2", "menu")
|
|
m:SetAttribute("toggleForVehicle", true)
|
|
m:RegisterForClicks("AnyUp")
|
|
-- le menu du client : celui de son cadre de groupe, UnitPopup "PARTY"
|
|
m.menu = function(self)
|
|
ForeverUI.MenuUnite.ouvrir(ToggleDropDownMenu, 1, nil, _G["PartyMemberFrame" .. i .. "DropDown"], self:GetName(), 47, 15)
|
|
end
|
|
|
|
m.portrait = m:CreateTexture(nil, "BACKGROUND")
|
|
m.portrait:SetWidth(37)
|
|
m.portrait:SetHeight(37)
|
|
m.portrait:SetPoint("TOPLEFT", m, "TOPLEFT", 7, -6)
|
|
m.art = m:CreateTexture(nil, "ARTWORK")
|
|
|
|
-- les barres, au-dessus de l'art (camelot les met dans un cadre fils)
|
|
local barres = CreateFrame("Frame", nil, m)
|
|
barres:SetAllPoints(m)
|
|
barres:SetFrameLevel(m:GetFrameLevel() + 1)
|
|
m.vie = barres:CreateTexture(nil, "ARTWORK")
|
|
m.ressource = barres:CreateTexture(nil, "ARTWORK")
|
|
m.texteVie = champ(barres, "OVERLAY", "TextStatusBarText")
|
|
m.texteRessource = champ(barres, "OVERLAY", "TextStatusBarText")
|
|
|
|
-- ce qui passe au-dessus de tout
|
|
local dessus = CreateFrame("Frame", nil, m)
|
|
dessus:SetAllPoints(m)
|
|
dessus:SetFrameLevel(m:GetFrameLevel() + 2)
|
|
m.dessus = dessus
|
|
m.lueur = dessus:CreateTexture(nil, "BACKGROUND")
|
|
m.lueur:Hide()
|
|
m.statut = dessus:CreateTexture(nil, "BACKGROUND")
|
|
m.statut:Hide()
|
|
m.nom = champ(dessus, "OVERLAY", "GameFontNormalSmall")
|
|
m.nom:SetJustifyH("LEFT")
|
|
m.nom:SetHeight(12)
|
|
m.chef = dessus:CreateTexture(nil, "OVERLAY")
|
|
m.chef:SetPoint("BOTTOM", m, "TOP", -10, -6)
|
|
m.chef:Hide()
|
|
m.pvp = dessus:CreateTexture(nil, "OVERLAY")
|
|
m.pvp:Hide()
|
|
m.deconnexion = dessus:CreateTexture(nil, "OVERLAY")
|
|
m.deconnexion:SetTexture(P.deconnexion)
|
|
m.deconnexion:SetWidth(64)
|
|
m.deconnexion:SetHeight(64)
|
|
m.deconnexion:SetPoint("LEFT", m, "LEFT", -7, -1)
|
|
m.deconnexion:Hide()
|
|
m.role = dessus:CreateTexture(nil, "OVERLAY")
|
|
m.role:SetWidth(12)
|
|
m.role:SetHeight(12)
|
|
m.role:SetPoint("TOPRIGHT", m, "TOPRIGHT", -5, -5)
|
|
m.role:Hide()
|
|
|
|
-- l'appel : 36 x 36, deux niveaux au-dessus (RaiseFrameLevelByTwo)
|
|
local appel = CreateFrame("Frame", nil, m)
|
|
appel:SetWidth(36)
|
|
appel:SetHeight(36)
|
|
appel:SetPoint("CENTER", m.portrait, "CENTER", 0, -2)
|
|
appel:SetFrameLevel(m:GetFrameLevel() + 4)
|
|
appel.icone = appel:CreateTexture(nil, "ARTWORK")
|
|
appel.icone:SetAllPoints(appel)
|
|
appel:Hide()
|
|
m.appel = appel
|
|
|
|
m.auras = creerAuras(dessus, m:GetName(), 48, -43)
|
|
m.familier = creerFamilier(m, i)
|
|
|
|
m:SetScript("OnEnter", function(self)
|
|
-- le survol montre les textes des barres (CVar partyStatusText a 0)
|
|
self.survol = true
|
|
G.majMembre(self)
|
|
GameTooltip_SetDefaultAnchor(GameTooltip, self)
|
|
GameTooltip:SetUnit(self.unit)
|
|
GameTooltip:Show()
|
|
-- l'infobulle des buffs, a la place de celle de camelot
|
|
if PartyMemberBuffTooltip and PartyMemberBuffTooltip_Update then
|
|
PartyMemberBuffTooltip:ClearAllPoints()
|
|
PartyMemberBuffTooltip:SetPoint("TOPLEFT", self, "TOPLEFT", 47, -25)
|
|
PartyMemberBuffTooltip_Update(self)
|
|
end
|
|
end)
|
|
m:SetScript("OnLeave", function(self)
|
|
self.survol = nil
|
|
G.majMembre(self)
|
|
GameTooltip:FadeOut()
|
|
if PartyMemberBuffTooltip then PartyMemberBuffTooltip:Hide() end
|
|
end)
|
|
return m
|
|
end
|
|
|
|
G.membres = {}
|
|
for i = 1, 4 do
|
|
G.membres[i] = creerMembre(i)
|
|
end
|
|
|
|
-- ------------------------------------------------------------ les mises a jour
|
|
|
|
-- l'unite affichee : le vehicule s'il y en a un (le cadre suit partypetN)
|
|
local function unites(m)
|
|
local i = m:GetID()
|
|
if UnitHasVehicleUI("party" .. i) then
|
|
return "partypet" .. i, "party" .. i, true
|
|
end
|
|
return "party" .. i, "partypet" .. i, false
|
|
end
|
|
|
|
local function poser(tex, atlas, x, y, rel)
|
|
ForeverUI.SetAtlas(tex, atlas)
|
|
tex:ClearAllPoints()
|
|
tex:SetPoint("TOPLEFT", rel, "TOPLEFT", x, y)
|
|
end
|
|
|
|
-- ToPlayerArt / ToVehicleArt
|
|
local function majArt(m)
|
|
local geo = m.vehicule and P.vehicule or P.joueur
|
|
poser(m.art, m.vehicule and P.artVehicule or P.art, geo.art[1], geo.art[2], m)
|
|
poser(m.lueur, m.vehicule and P.lueurVehicule or P.lueur, geo.lueur[1], geo.lueur[2], m)
|
|
poser(m.statut, m.vehicule and P.statutVehicule or P.statut, geo.statut[1], geo.statut[2], m)
|
|
m.vie:ClearAllPoints()
|
|
m.vie:SetPoint("TOPLEFT", m, "TOPLEFT", geo.vie[1], geo.vie[2])
|
|
m.ressource:ClearAllPoints()
|
|
m.ressource:SetPoint("TOPLEFT", m, "TOPLEFT", geo.ressource[1], geo.ressource[2])
|
|
m.nom:ClearAllPoints()
|
|
m.nom:SetPoint("TOPLEFT", m, "TOPLEFT", geo.nom[1], geo.nom[2])
|
|
m.nom:SetWidth(geo.nom[3])
|
|
end
|
|
|
|
local function fraction(valeur, maximum)
|
|
if not maximum or maximum <= 0 then return 0 end
|
|
return valeur / maximum
|
|
end
|
|
|
|
local function texteBarre(fs, valeur, maximum, survol)
|
|
local toujours = GetCVar("partyStatusText") == "1"
|
|
if not (toujours or survol) or not maximum or maximum <= 0 then
|
|
fs:Hide()
|
|
return
|
|
end
|
|
if GetCVarBool("statusTextPercentage") then
|
|
fs:SetText(math.ceil(valeur / maximum * 100) .. "%")
|
|
else
|
|
fs:SetText(valeur .. " / " .. maximum)
|
|
end
|
|
fs:Show()
|
|
end
|
|
|
|
local function majVie(m)
|
|
local u = m.unit
|
|
local geo = m.vehicule and P.vehicule or P.joueur
|
|
local atlas = m.vehicule and P.vieVehicule or P.vie
|
|
local connecte = UnitIsConnected(m.unite)
|
|
local vie, max = UnitHealth(u), UnitHealthMax(u)
|
|
-- deconnecte : la barre pleine, desaturee
|
|
ForeverUI.SetAtlasFill(m.vie, atlas, connecte and fraction(vie, max) or 1, geo.vie[3])
|
|
m.vie:SetDesaturated(not connecte)
|
|
m.texteVie:ClearAllPoints()
|
|
m.texteVie:SetPoint("CENTER", m, "TOPLEFT", geo.vie[1] + geo.vie[3] / 2, geo.vie[2] - 5)
|
|
if UnitIsDeadOrGhost(u) then
|
|
m.texteVie:SetText(DEAD)
|
|
m.texteVie:Show()
|
|
else
|
|
texteBarre(m.texteVie, vie, max, m.survol)
|
|
end
|
|
-- PartyMemberHealthCheck : la teinte du portrait
|
|
m.pourcent = fraction(vie, max)
|
|
if UnitIsDead(u) then
|
|
m.portrait:SetVertexColor(0.35, 0.35, 0.35, 1)
|
|
elseif UnitIsGhost(u) then
|
|
m.portrait:SetVertexColor(0.2, 0.2, 0.75, 1)
|
|
elseif m.pourcent > 0 and m.pourcent <= 0.2 then
|
|
m.portrait:SetVertexColor(1, 0, 0)
|
|
else
|
|
m.portrait:SetVertexColor(1, 1, 1, 1)
|
|
end
|
|
G.majPouls()
|
|
end
|
|
|
|
local function majRessource(m)
|
|
local u = m.unit
|
|
local geo = m.vehicule and P.vehicule or P.joueur
|
|
local type, jeton = UnitPowerType(u)
|
|
local valeur, max = UnitPower(u, type), UnitPowerMax(u, type)
|
|
ForeverUI.SetAtlasFill(m.ressource, atlasRessource(jeton, m.vehicule), fraction(valeur, max), geo.ressource[3])
|
|
-- le masque de camelot retire le premier pixel de la barre : on la pose
|
|
-- un pixel plus loin, sur 73 (voir l'en-tete)
|
|
m.texteRessource:ClearAllPoints()
|
|
m.texteRessource:SetPoint("CENTER", m, "TOPLEFT", geo.ressource[1] + geo.ressource[3] / 2 + 2, geo.ressource[2] - 3.5)
|
|
texteBarre(m.texteRessource, valeur, max, m.survol)
|
|
end
|
|
|
|
local function majPortrait(m)
|
|
SetPortraitTexture(m.portrait, m.unit)
|
|
m.portrait:SetDesaturated(not UnitIsConnected(m.unite))
|
|
end
|
|
|
|
-- chef ou guide (HasLFGRestrictions : le groupe du chercheur de donjon)
|
|
local function majChef(m)
|
|
if GetPartyLeaderIndex() == m:GetID() then
|
|
ForeverUI.SetAtlas(m.chef, HasLFGRestrictions() and P.guide or P.chef)
|
|
m.chef:Show()
|
|
else
|
|
m.chef:Hide()
|
|
end
|
|
end
|
|
|
|
local function majPvP(m)
|
|
local u = m.unite
|
|
local atlas
|
|
if UnitIsPVPFreeForAll(u) then
|
|
atlas = P.pvpLibre
|
|
elseif UnitIsPVP(u) then
|
|
local faction = UnitFactionGroup(u)
|
|
if faction == "Horde" then atlas = P.pvpHorde elseif faction == "Alliance" then atlas = P.pvpAlliance end
|
|
end
|
|
if atlas and ForeverUI.SetAtlas(m.pvp, atlas) then
|
|
-- a l'echelle 0,6 : la taille de l'atlas et le decalage (24, -68)
|
|
m.pvp:SetWidth(m.pvp:GetWidth() * P.pvpEchelle)
|
|
m.pvp:SetHeight(m.pvp:GetHeight() * P.pvpEchelle)
|
|
m.pvp:ClearAllPoints()
|
|
m.pvp:SetPoint("CENTER", m, "TOPLEFT", 24 * P.pvpEchelle, -68 * P.pvpEchelle)
|
|
m.pvp:Show()
|
|
else
|
|
m.pvp:Hide()
|
|
end
|
|
end
|
|
|
|
-- UnitGroupRolesAssigned rend trois booleens en 3.3.5
|
|
local function majRole(m)
|
|
local tank, soins, degats = UnitGroupRolesAssigned(m.unite)
|
|
local atlas = (tank and "roleicon-tiny-tank") or (soins and "roleicon-tiny-healer") or (degats and "roleicon-tiny-dps")
|
|
if atlas and ForeverUI.SetAtlas(m.role, atlas, true) then
|
|
m.role:Show()
|
|
else
|
|
m.role:Hide()
|
|
end
|
|
end
|
|
|
|
local function majMenace(m)
|
|
local statut = UnitThreatSituation(m.unit)
|
|
if IsThreatWarningEnabled() and statut and statut > 0 and not UnitIsDeadOrGhost(m.unit) then
|
|
m.lueur:SetVertexColor(GetThreatStatusColor(statut))
|
|
m.lueur:Show()
|
|
else
|
|
m.lueur:Hide()
|
|
end
|
|
end
|
|
|
|
local function majAurasMembre(m)
|
|
local couleur = majAuras(m.auras, m.unit)
|
|
if couleur then
|
|
m.statut:SetVertexColor(couleur.r, couleur.g, couleur.b)
|
|
m.statut:Show()
|
|
else
|
|
m.statut:Hide()
|
|
end
|
|
end
|
|
|
|
local function majFamilier(m)
|
|
local f = m.familier
|
|
f.affiche = m.familierUnite
|
|
local u = f.affiche
|
|
if not UnitExists(u) then return end
|
|
SetPortraitTexture(f.portrait, u)
|
|
local connecte = UnitIsConnected(m.unite)
|
|
-- 71 x 10 a l'echelle 0,5 : 35,5 de long, teinte verte (pas de lockColor)
|
|
ForeverUI.SetAtlasFill(f.vie, P.vie, connecte and fraction(UnitHealth(u), UnitHealthMax(u)) or 1, 35.5)
|
|
f.vie:SetHeight(5)
|
|
if connecte then f.vie:SetVertexColor(0, 1, 0) else f.vie:SetVertexColor(0.5, 0.5, 0.5) end
|
|
local statut = UnitThreatSituation(u)
|
|
if IsThreatWarningEnabled() and statut and statut > 0 then
|
|
f.lueur:SetVertexColor(GetThreatStatusColor(statut))
|
|
f.lueur:Show()
|
|
else
|
|
f.lueur:Hide()
|
|
end
|
|
majAuras(f.auras, u)
|
|
end
|
|
|
|
local function majDeconnexion(m)
|
|
if UnitIsConnected(m.unite) then m.deconnexion:Hide() else m.deconnexion:Show() end
|
|
end
|
|
|
|
function G.majMembre(m)
|
|
if not UnitExists(m.unite) then return end
|
|
local affiche, familier, vehicule = unites(m)
|
|
m.unit, m.familierUnite, m.vehicule = affiche, familier, vehicule
|
|
majArt(m)
|
|
m.nom:SetText(GetUnitName(affiche, true))
|
|
majPortrait(m)
|
|
majVie(m)
|
|
majRessource(m)
|
|
majChef(m)
|
|
majPvP(m)
|
|
majRole(m)
|
|
majMenace(m)
|
|
majAurasMembre(m)
|
|
majDeconnexion(m)
|
|
majFamilier(m)
|
|
end
|
|
|
|
-- LE POULS du portrait sous 20 % : l'alpha va de 127/255 a 1 et revient, par
|
|
-- demi-periodes de 0,5 s, tant qu'un membre est dans ce cas
|
|
local pouls = CreateFrame("Frame")
|
|
pouls.temps = 0
|
|
pouls:Hide()
|
|
pouls:SetScript("OnUpdate", function(self, ecoule)
|
|
self.temps = self.temps + ecoule
|
|
local t = (self.temps % (2 * P.pouls)) / P.pouls
|
|
local a = t <= 1 and (1 - t * (1 - P.poulsMin)) or (P.poulsMin + (t - 1) * (1 - P.poulsMin))
|
|
for _, m in ipairs(G.membres) do
|
|
if m.bat then m.portrait:SetAlpha(a) end
|
|
end
|
|
end)
|
|
|
|
function G.majPouls()
|
|
local un = false
|
|
for _, m in ipairs(G.membres) do
|
|
local bat = m:IsShown() and not UnitIsDeadOrGhost(m.unit or m.unite) and m.pourcent
|
|
and m.pourcent > 0 and m.pourcent <= 0.2
|
|
m.bat = bat
|
|
if not bat then m.portrait:SetAlpha(1) end
|
|
un = un or bat
|
|
end
|
|
if un then pouls:Show() else pouls:Hide() end
|
|
end
|
|
|
|
-- ---------------------------------------------------------------------- l'appel
|
|
|
|
local function majAppel(m, fin)
|
|
local etat = GetReadyCheckStatus(m.unite)
|
|
local a = m.appel
|
|
if not etat then
|
|
if not fin then a:Hide() end
|
|
return
|
|
end
|
|
if fin and etat == "waiting" then etat = "notready" end
|
|
a.icone:SetTexture(P.marques[etat] or P.marques.waiting)
|
|
a:SetAlpha(1)
|
|
a.reste = nil
|
|
if fin then a.reste = P.appelReste + P.appelFondu end
|
|
a:Show()
|
|
end
|
|
|
|
local minuterie = CreateFrame("Frame")
|
|
minuterie:SetScript("OnUpdate", function(self, ecoule)
|
|
local actif = false
|
|
for _, m in ipairs(G.membres) do
|
|
local a = m.appel
|
|
if a.reste then
|
|
a.reste = a.reste - ecoule
|
|
if a.reste <= 0 then
|
|
a.reste = nil
|
|
a:Hide()
|
|
else
|
|
if a.reste < P.appelFondu then a:SetAlpha(a.reste / P.appelFondu) end
|
|
actif = true
|
|
end
|
|
end
|
|
end
|
|
if not actif then self:Hide() end
|
|
end)
|
|
minuterie:Hide()
|
|
|
|
-- ------------------------------------------------------------ la disposition
|
|
|
|
-- le pas depend de l'option des familiers ; hors combat seulement
|
|
function G.disposer()
|
|
if InCombatLockdown() then
|
|
G.aDisposer = true
|
|
return
|
|
end
|
|
G.aDisposer = nil
|
|
local p = pas()
|
|
for i, m in ipairs(G.membres) do
|
|
m:ClearAllPoints()
|
|
m:SetPoint("TOPLEFT", conteneur, "TOPLEFT", 0, -(i - 1) * p)
|
|
local f = m.familier
|
|
UnregisterUnitWatch(f)
|
|
if GetCVarBool("showPartyPets") then
|
|
RegisterUnitWatch(f)
|
|
else
|
|
f:Hide()
|
|
end
|
|
end
|
|
conteneur:SetHeight(4 * P.membreH + 3 * (p - P.membreH) + P.bas)
|
|
end
|
|
|
|
-- les cadres de groupe du client : sans evenement, et tenus caches par un
|
|
-- pilote d'etat (un Show venu d'ailleurs, meme en combat, est defait)
|
|
local function cacherClient()
|
|
if InCombatLockdown() or G.clientCache then return end
|
|
for i = 1, 4 do
|
|
local f = _G["PartyMemberFrame" .. i]
|
|
if f then
|
|
f:UnregisterAllEvents()
|
|
f:Hide()
|
|
RegisterStateDriver(f, "visibility", "hide")
|
|
end
|
|
end
|
|
if PartyMemberBackground then ForeverUI.Suppress(PartyMemberBackground) end
|
|
G.clientCache = true
|
|
end
|
|
|
|
-- ---------------------------------------------------------------- les evenements
|
|
|
|
local function membreDe(unite)
|
|
if not unite then return nil end
|
|
local i = unite:match("^party(%d)$") or unite:match("^partypet(%d)$")
|
|
return i and G.membres[tonumber(i)]
|
|
end
|
|
|
|
local veilleur = CreateFrame("Frame")
|
|
G.veilleur = veilleur
|
|
for _, ev in ipairs({ "PLAYER_ENTERING_WORLD", "PARTY_MEMBERS_CHANGED", "PARTY_LEADER_CHANGED",
|
|
"PARTY_MEMBER_ENABLE", "PARTY_MEMBER_DISABLE", "UNIT_HEALTH", "UNIT_MAXHEALTH", "UNIT_DISPLAYPOWER",
|
|
"UNIT_MANA", "UNIT_RAGE", "UNIT_FOCUS", "UNIT_ENERGY", "UNIT_RUNIC_POWER", "UNIT_MAXMANA",
|
|
"UNIT_MAXRAGE", "UNIT_MAXFOCUS", "UNIT_MAXENERGY", "UNIT_MAXRUNIC_POWER", "UNIT_NAME_UPDATE",
|
|
"UNIT_PORTRAIT_UPDATE", "UNIT_AURA", "UNIT_PET", "UNIT_FACTION", "UNIT_THREAT_SITUATION_UPDATE",
|
|
"UNIT_ENTERED_VEHICLE", "UNIT_EXITED_VEHICLE", "READY_CHECK", "READY_CHECK_CONFIRM",
|
|
"READY_CHECK_FINISHED", "PLAYER_ROLES_ASSIGNED", "CVAR_UPDATE", "PLAYER_REGEN_ENABLED" }) do
|
|
veilleur:RegisterEvent(ev)
|
|
end
|
|
|
|
local function tout()
|
|
for _, m in ipairs(G.membres) do G.majMembre(m) end
|
|
end
|
|
|
|
veilleur:SetScript("OnEvent", function(self, ev, unite)
|
|
if ev == "PLAYER_ENTERING_WORLD" then
|
|
cacherClient()
|
|
G.disposer()
|
|
tout()
|
|
elseif ev == "PLAYER_REGEN_ENABLED" then
|
|
cacherClient()
|
|
if G.aDisposer then G.disposer() end
|
|
elseif ev == "PARTY_MEMBERS_CHANGED" or ev == "PARTY_LEADER_CHANGED" or ev == "PLAYER_ROLES_ASSIGNED" then
|
|
tout()
|
|
elseif ev == "CVAR_UPDATE" then
|
|
G.disposer()
|
|
tout()
|
|
elseif ev == "READY_CHECK" or ev == "READY_CHECK_CONFIRM" then
|
|
for _, m in ipairs(G.membres) do majAppel(m) end
|
|
elseif ev == "READY_CHECK_FINISHED" then
|
|
for _, m in ipairs(G.membres) do majAppel(m, true) end
|
|
minuterie:Show()
|
|
else
|
|
local m = membreDe(unite)
|
|
if m then G.majMembre(m) end
|
|
end
|
|
end)
|
|
|
|
for _, m in ipairs(G.membres) do
|
|
RegisterUnitWatch(m)
|
|
end
|
|
|
|
-- en groupe, pas en raid (ShouldShowPartyFrames)
|
|
RegisterStateDriver(conteneur, "visibility", "[group:raid] hide; [group] show; hide")
|
|
|
|
G.disposer()
|
|
ForeverUI.Layout.Register(conteneur, "partyframe", "Cadres de groupe", "TOPLEFT", "TOPLEFT", P.x, P.y)
|