Files
moon-well-ui/data/addon/ForeverUI/TargetFrame.lua
T
Adrestie eb681aa9cd Aucun texte en dur : anglais en base, francais, langues extensibles
- socle : Textes.lua (ForeverUI.L) et ForeverUIGlueTextes.lua (G.L) ; les
  textes dans Textes_enUS / Textes_frFR (325 cles en jeu) et
  ForeverUIGlueTextes_enUS / _frFR (41 cles aux ecrans d'accueil) ; une cle
  absente prend l'anglais, une langue sans fichier lit l'anglais ; ajouter
  une langue = un fichier de plus
- les textes que le client 3.3.5 connait se lisent dans ses globales
  (GlobalStrings, GlueStrings en glue) ; les textes de secours sont retires
- tous les fichiers repris : libelles, infobulles, mode edition, messages et
  aide de /fui, erreurs internes ; .toc : Notes + Notes-frFR
- selection des personnages : race et classe traduites ramenees a leur jeton
  par les tables de langue (GetAvailableRaces / GetAvailableClasses font
  planter le client hors de la creation)
- tools/cartes_instances.py : noms des instances dans toutes les langues de
  la LibBabble-Zone de WDM (portails de la carte sur tout client)
- banc : toute cle employee existe en anglais et en francais, memes cles dans
  les deux, bascule frFR / deDE essayee ; chaines 3.3.5 ajoutees au faux client
- README : etat des sections mis a jour, langues, glue, deploiement --glue

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 03:22:30 +02:00

571 lines
19 KiB
Lua

-- ForeverUI : le cadre de cible.
--
-- RELEVE DES SOURCES -- tout ce qui suit vient du code extrait, pas d'une
-- mesure ni d'une estimation.
--
-- mainline/TargetFrame.xml
-- cadre 232 x 100, portrait 58 x 58 ancre TOPRIGHT (-26, -19), art du cadre
-- centre, bandeau de reputation UI-HUD-UnitFrame-Target-PortraitOn-Type
-- ancre TOPRIGHT (-75, -25), cercle de niveau BOTTOMRIGHT (-13, 7).
--
-- mainline/TargetFrame.lua, TargetFrameMixin:CheckClassification
-- C'est le code, et non le XML, qui pose les barres -- il les replace a
-- chaque changement de cible :
-- ordinaire et rare : barre de vie 126 x 20, BOTTOMRIGHT sur le point
-- LEFT du conteneur en (149, -10) ; le point LEFT vaut (0, 50) dans un
-- cadre de 232 x 100, donc le coin bas droit tombe en (149, 40) et le
-- haut de la barre a 40 du haut : TOPLEFT (23, -40).
-- negligeable (minus) : barre 125 x 12 en (148, -1), soit TOPLEFT
-- (23, -39), et la barre de ressource est MASQUEE.
-- La barre de ressource suit le XML : TOPRIGHT sur le BOTTOMRIGHT de la
-- barre de vie en (8, -1), soit TOPLEFT (23, -61) pour 134 x 10.
-- Art du cadre : MinusMob si negligeable, Rare si rare ou rare elite,
-- PortraitOn sinon. Lueur de menace : la variante MinusMob ou la normale.
--
-- camelot/TargetFrameUtils.lua, GetBossPortraitFrameData
-- boss : Boss-Gold-Winged, ancre TOPRIGHT/TOPRIGHT (11, -4)
-- rare/rare elite : Boss-Rare-Silver-Winged (8, -7)
-- elite : Boss-Gold (0, 1)
-- et ShouldShowStar rend toujours faux : pas d'etoile sur camelot.
-- NOTE : la variante ailee argentee n'existe pas dans la table d'atlas de ce
-- build du client (seulement en c60) ; on prend donc l'argente simple aux
-- memes decalages, faute de mieux.
--
-- camelot/TargetFrame.lua, TargetFrameMixin:OnLoad et CheckFaction
-- nom : largeur 117, TOPLEFT sur le TOPRIGHT du bandeau en (-133, -1),
-- soit (24, -26) dans le cadre ; niveau centre sur son cercle a (0, -0.5).
-- LA COULEUR DE REACTION VA SUR LE BANDEAU, pas sur la barre de vie :
-- ReputationColor prend UnitSelectionColor, et passe en gris (0.5) avec le
-- portrait quand la cible est verrouillee par quelqu'un d'autre.
local FRAME_WIDTH, FRAME_HEIGHT = 232, 100
local L = ForeverUI.L
local ART = {
normal = "ui-hud-unitframe-target-portraiton",
rare = "ui-hud-unitframe-target-rare-portraiton",
minus = "ui-hud-unitframe-target-minusmob-portraiton",
}
local THREAT_GLOW = {
normal = "ui-hud-unitframe-target-portraiton-incombat",
minus = "ui-hud-unitframe-target-minusmob-portraiton-incombat",
}
local HEALTH_FILL = {
normal = "ui-hud-unitframe-target-portraiton-bar-health",
minus = "ui-hud-unitframe-target-minusmob-portraiton-bar-health",
}
-- Geometrie posee par CheckClassification, reprise telle quelle.
local BAR_LAYOUT = {
normal = { health = { 23, -40, 126, 20 }, power = { 23, -61, 134, 10 }, showPower = true },
minus = { health = { 23, -39, 125, 12 }, power = nil, showPower = false },
}
local POWER_FILL = {
normal = {
MANA = "ui-hud-unitframe-target-portraiton-bar-mana",
RAGE = "ui-hud-unitframe-target-portraiton-bar-rage",
FOCUS = "ui-hud-unitframe-target-portraiton-bar-focus",
ENERGY = "ui-hud-unitframe-target-portraiton-bar-energy",
RUNIC_POWER = "ui-hud-unitframe-target-portraiton-bar-runicpower",
},
minus = {
MANA = "ui-hud-unitframe-target-minusmob-portraiton-bar-mana",
RAGE = "ui-hud-unitframe-target-minusmob-portraiton-bar-rage",
FOCUS = "ui-hud-unitframe-target-minusmob-portraiton-bar-focus",
ENERGY = "ui-hud-unitframe-target-minusmob-portraiton-bar-energy",
RUNIC_POWER = "ui-hud-unitframe-target-minusmob-portraiton-bar-runicpower",
},
}
-- Les couleurs de reaction du client 3.3.5 : rouge, orange, jaune, vert.
-- L'elite ne change pas le cadre mais l'anneau du portrait : un dragon dore,
-- argente pour un rare elite, aile pour un boss de monde. C'est la meme
-- logique que BossPortraitFrameTexture dans la source. Feuille :
-- interface/hud/uiunitframeboss.blp.
-- CE SONT LES VARIANTES c60 QU'IL FAUT PRENDRE. Le code camelot demande
-- Boss-Rare-Silver-Winged, un nom qui n'existe QUE sous la forme c60 dans la
-- table d'atlas du client : c'est donc ce jeu-la que camelot utilise. Les
-- variantes de base sont plus petites (80x79 contre 100x100), et comme
-- l'ancrage se fait par le coin haut droit, chacune tombait a cote d'une
-- distance differente -- exactement le defaut constate.
local CLASS_RING = {
worldboss = { "ui-hud-unitframe-target-portraiton-boss-gold-winged-c60", 11, -4 },
rareelite = { "ui-hud-unitframe-target-portraiton-boss-rare-silver-winged-c60", 8, -7 },
rare = { "ui-hud-unitframe-target-portraiton-boss-rare-silver-winged-c60", 8, -7 },
elite = { "ui-hud-unitframe-target-portraiton-boss-gold-c60", 0, 1 },
}
local REACTION_COLOR = {
[1] = { 1.0, 0.0, 0.0 }, -- hostile
[2] = { 1.0, 0.0, 0.0 },
[3] = { 1.0, 0.5, 0.0 }, -- prudent
[4] = { 1.0, 1.0, 0.0 }, -- neutre
[5] = { 0.0, 1.0, 0.0 }, -- amical
[6] = { 0.0, 1.0, 0.0 },
[7] = { 0.0, 1.0, 0.0 },
[8] = { 0.0, 1.0, 0.0 },
}
local frame = CreateFrame("Button", "ForeverUITargetFrame", UIParent, "SecureUnitButtonTemplate")
frame:SetWidth(FRAME_WIDTH)
frame:SetHeight(FRAME_HEIGHT)
frame:SetFrameStrata("LOW")
frame:SetHitRectInsets(20, 20, 16, 17)
frame.unit = "target"
frame:SetAttribute("unit", "target")
frame:SetAttribute("*type1", "target")
frame:SetAttribute("*type2", "menu")
frame:RegisterForClicks("AnyUp")
frame.menu = function(self)
ForeverUI.MenuUnite.ouvrir(ToggleDropDownMenu, 1, nil, TargetFrameDropDown, self, 120, 10)
end
local portrait = frame:CreateTexture(nil, "BACKGROUND")
portrait:SetWidth(58)
portrait:SetHeight(58)
portrait:SetPoint("TOPRIGHT", -26, -19)
local healthFill = frame:CreateTexture(nil, "BORDER")
healthFill:SetPoint("TOPLEFT", 23, -39)
local powerFill = frame:CreateTexture(nil, "BORDER")
powerFill:SetPoint("TOPLEFT", 23, -60)
local art = frame:CreateTexture(nil, "ARTWORK")
art:SetPoint("CENTER", 0, 0)
ForeverUI.SetAtlas(art, ART.normal)
-- Le bandeau de reputation : c'est LUI qui porte la couleur de reaction.
local reputation = frame:CreateTexture(nil, "BACKGROUND")
reputation:SetPoint("TOPRIGHT", -75, -25)
ForeverUI.SetAtlas(reputation, "ui-hud-unitframe-target-portraiton-type")
-- Comme pour le cadre joueur : tout ce qui doit rester au-dessus de l'art vit
-- dans un cadre fils, jamais dans le meme calque.
local overlayHolder = CreateFrame("Frame", nil, frame)
overlayHolder:SetAllPoints(frame)
overlayHolder:SetFrameLevel(frame:GetFrameLevel() + 1)
local threatGlow = overlayHolder:CreateTexture(nil, "BACKGROUND")
threatGlow:SetPoint("CENTER", frame, "CENTER", 1.5, 1)
ForeverUI.SetAtlas(threatGlow, THREAT_GLOW.normal)
threatGlow:Hide()
-- L'anneau : GetBossPortraitFrameData l'ancre TOPRIGHT sur le TOPRIGHT du
-- conteneur, avec ses propres decalages. Calque : la source le met en
-- ARTWORK sous-niveau 2 du conteneur, donc au-dessus de l'art du cadre et de
-- la lueur de menace, mais SOUS le contenu -- barres, nom et cercle de
-- niveau, qui vivent dans un cadre frere pose par-dessus. Ici : BORDER du
-- porteur, donc au-dessus de la lueur (BACKGROUND) et sous le cercle de
-- niveau (ARTWORK) et le texte (OVERLAY).
local classRing = overlayHolder:CreateTexture(nil, "BORDER")
classRing:Hide()
local levelCircle = overlayHolder:CreateTexture(nil, "ARTWORK")
levelCircle:SetPoint("BOTTOMRIGHT", -13, 7)
ForeverUI.SetAtlas(levelCircle, "ui-hud-unitframe-smallcircle")
local levelText = overlayHolder:CreateFontString(nil, "OVERLAY", "GameFontNormal")
levelText:SetPoint("CENTER", levelCircle, "CENTER", 0, -0.5)
local nameText = overlayHolder:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
nameText:SetWidth(117)
nameText:SetHeight(12)
nameText:SetJustifyH("LEFT")
nameText:SetPoint("TOPLEFT", 24, -26)
local healthText = overlayHolder:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
healthText:SetPoint("CENTER", frame, "TOPLEFT", 23 + 63, -40 - 10)
healthText:Hide()
local powerText = overlayHolder:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
powerText:SetPoint("CENTER", frame, "TOPLEFT", 23 + 67, -61 - 5)
powerText:Hide()
frame.portrait = portrait
frame.healthFill = healthFill
frame.powerFill = powerFill
frame.art = art
frame.threatGlow = threatGlow
frame.classRing = classRing
frame.reputation = reputation
frame.nameText = nameText
frame.levelText = levelText
frame.healthText = healthText
frame.powerText = powerText
frame.overlayHolder = overlayHolder
-- Quelle famille d'art pour cette cible : negligeable, rare, ou ordinaire.
-- Deux choses distinctes : la famille d'art du cadre (ordinaire, rare,
-- negligeable) et l'anneau porte par le portrait (elite, rare, boss).
local function classification()
return (UnitClassification and UnitClassification("target")) or "normal"
end
local function artKindFor(class)
if class == "minus" then
return "minus"
end
if class == "rare" or class == "rareelite" then
return "rare"
end
return "normal"
end
-- Eclaircir sans deteindre : on multiplie jusqu'a ce que la composante la
-- plus forte atteigne 1, sans depasser ce que l'image grise retire. Un simple
-- facteur commun ecreterait les couleurs claires -- le brun du guerrier
-- virerait au jaune pale.
-- CheckFaction de camelot : le bandeau prend la couleur de selection, et le
-- bandeau comme le portrait passent au gris quand la cible est verrouillee
-- par quelqu'un d'autre. En 3.3.5 "verrouillee" se lit avec UnitIsTapped et
-- UnitIsTappedByPlayer, la fonction UnitIsTapDenied n'existant pas.
local function updateFaction()
local tapDenied = UnitIsTapped and UnitIsTapped("target")
and not UnitIsTappedByPlayer("target") and not UnitPlayerControlled("target")
if tapDenied then
reputation:SetVertexColor(0.5, 0.5, 0.5)
portrait:SetVertexColor(0.5, 0.5, 0.5)
else
if UnitSelectionColor then
reputation:SetVertexColor(UnitSelectionColor("target"))
end
portrait:SetVertexColor(1.0, 1.0, 1.0)
end
end
-- Recopie de TargetFrameMixin:CheckClassification : l'art, la lueur, mais
-- aussi la taille ET la position des barres, que le code repose a chaque fois.
local function updateArt()
local class = classification()
local artKind = artKindFor(class)
local barKind = (artKind == "minus") and "minus" or "normal"
local layout = BAR_LAYOUT[barKind]
ForeverUI.SetAtlas(art, ART[artKind] or ART.normal)
ForeverUI.SetAtlas(threatGlow, THREAT_GLOW[barKind] or THREAT_GLOW.normal)
healthFill:ClearAllPoints()
healthFill:SetPoint("TOPLEFT", layout.health[1], layout.health[2])
if layout.showPower then
powerFill:ClearAllPoints()
powerFill:SetPoint("TOPLEFT", layout.power[1], layout.power[2])
powerFill:Show()
powerText:Show()
else
powerFill:Hide()
powerText:Hide()
end
frame.barKind = barKind
frame.classification = class
frame.layout = layout
local ring = CLASS_RING[class]
if ring and ForeverUI.SetAtlas(classRing, ring[1]) then
classRing:ClearAllPoints()
classRing:SetPoint("TOPRIGHT", frame, "TOPRIGHT", ring[2], ring[3])
classRing:Show()
else
classRing:Hide()
end
end
local function updateHealth()
local maximum = UnitHealthMax("target")
local fraction = 0
if maximum and maximum > 0 then
fraction = UnitHealth("target") / maximum
end
local layout = frame.layout or BAR_LAYOUT.normal
ForeverUI.SetAtlasFill(healthFill, HEALTH_FILL[frame.barKind or "normal"], fraction, layout.health[3])
end
local function updatePower()
local layout = frame.layout or BAR_LAYOUT.normal
if not layout.showPower then
powerFill:Hide()
return
end
local powerType, powerToken = UnitPowerType("target")
local set = POWER_FILL[frame.barKind or "normal"]
local atlas = set[powerToken or ""] or set.MANA
local maximum = UnitPowerMax("target", powerType)
local fraction = 0
if maximum and maximum > 0 then
fraction = UnitPower("target", powerType) / maximum
end
ForeverUI.SetAtlasFill(powerFill, atlas, fraction, layout.power[3])
end
local function updateTexts()
local always = GetCVar and GetCVar("targetStatusText") == "1"
if not (always or frame.hovered) then
healthText:Hide()
powerText:Hide()
return
end
local function format(value, maximum)
if not maximum or maximum <= 0 then
return ""
end
if GetCVarBool and GetCVarBool("statusTextPercentage") then
return tostring(math.ceil(value / maximum * 100)) .. "%"
end
return value .. " / " .. maximum
end
local powerType = UnitPowerType("target")
healthText:SetText(format(UnitHealth("target"), UnitHealthMax("target")))
powerText:SetText(format(UnitPower("target", powerType), UnitPowerMax("target", powerType)))
healthText:Show()
powerText:Show()
end
local function updateName()
nameText:SetText(UnitName("target"))
end
local function updateLevel()
local level = UnitLevel("target")
if level and level > 0 then
levelText:SetText(level)
else
levelText:SetText("??")
end
end
local function updatePortrait()
SetPortraitTexture(portrait, "target")
end
-- Menace : la cible tient-elle l'aggro sur quelqu'un. Meme lecture de secours
-- que sur le cadre joueur, les donnees de menace n'etant pas garanties.
local function updateThreat()
if not UnitExists("target") then
threatGlow:Hide()
return
end
local status = UnitThreatSituation and UnitThreatSituation("target")
local engaged = UnitAffectingCombat("target")
if status and status >= 2 then
threatGlow:SetVertexColor(1.0, 0.0, 0.0)
threatGlow:SetAlpha(1.0)
threatGlow:Show()
elseif engaged or (status and status > 0) then
threatGlow:SetVertexColor(1.0, 0.0, 0.0)
threatGlow:SetAlpha(0.45)
threatGlow:Show()
else
threatGlow:Hide()
end
end
local function updateAll()
if not UnitExists("target") then
return
end
updateArt()
updateFaction()
updateHealth()
updatePower()
updateName()
updateLevel()
updatePortrait()
updateThreat()
updateTexts()
end
local function hideDefaultTargetFrame()
if InCombatLockdown() or not TargetFrame then
return
end
ForeverUI.Suppress(TargetFrame)
ForeverUI.Suppress(ComboFrame)
end
frame:SetScript("OnEnter", function(self)
self.hovered = true
updateTexts()
end)
frame:SetScript("OnLeave", function(self)
self.hovered = false
updateTexts()
end)
frame:SetScript("OnEvent", function(self, event, unit)
if event == "PLAYER_ENTERING_WORLD" then
hideDefaultTargetFrame()
updateAll()
return
end
if event == "PLAYER_TARGET_CHANGED" then
updateAll()
return
end
if event == "CVAR_UPDATE" then
updateTexts()
return
end
if unit ~= "target" then
return
end
if event == "UNIT_HEALTH" or event == "UNIT_MAXHEALTH" then
updateHealth()
updateTexts()
elseif event == "UNIT_NAME_UPDATE" then
updateName()
elseif event == "UNIT_PORTRAIT_UPDATE" then
updatePortrait()
elseif event == "UNIT_LEVEL" then
updateLevel()
elseif event == "UNIT_CLASSIFICATION_CHANGED" then
updateArt()
updateHealth()
updatePower()
elseif event == "UNIT_FACTION" then
updateFaction()
elseif event == "UNIT_THREAT_SITUATION_UPDATE" then
updateThreat()
else
updatePower()
updateTexts()
end
end)
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:RegisterEvent("PLAYER_TARGET_CHANGED")
frame:RegisterEvent("CVAR_UPDATE")
frame:RegisterEvent("UNIT_HEALTH")
frame:RegisterEvent("UNIT_MAXHEALTH")
frame:RegisterEvent("UNIT_NAME_UPDATE")
frame:RegisterEvent("UNIT_PORTRAIT_UPDATE")
frame:RegisterEvent("UNIT_LEVEL")
frame:RegisterEvent("UNIT_CLASSIFICATION_CHANGED")
frame:RegisterEvent("UNIT_FACTION")
frame:RegisterEvent("UNIT_DISPLAYPOWER")
frame:RegisterEvent("UNIT_THREAT_SITUATION_UPDATE")
frame:RegisterEvent("UNIT_MANA")
frame:RegisterEvent("UNIT_RAGE")
frame:RegisterEvent("UNIT_FOCUS")
frame:RegisterEvent("UNIT_ENERGY")
frame:RegisterEvent("UNIT_RUNIC_POWER")
frame:RegisterEvent("UNIT_MAXMANA")
frame:RegisterEvent("UNIT_MAXRAGE")
frame:RegisterEvent("UNIT_MAXFOCUS")
frame:RegisterEvent("UNIT_MAXENERGY")
frame:RegisterEvent("UNIT_MAXRUNIC_POWER")
-- Le cadre n'existe que quand une cible existe : c'est le client qui le
-- montre et le cache, comme pour n'importe quel cadre d'unite securise.
if RegisterUnitWatch then
RegisterUnitWatch(frame)
end
-- ------------------------------------------------- cible de la cible
-- RELEVE : mainline/TargetFrame.xml TargetofTargetFrameTemplate -- 120 x 49,
-- ancre TOPRIGHT sur le BOTTOMRIGHT du cadre de cible en (12, 10), portrait
-- 37 x 37 en (5, -5), nom a droite du portrait, barre de vie 70 x 10 ancree
-- BOTTOMRIGHT sur le point RIGHT du cadre en (-6, -2.5), soit TOPLEFT (44, -17).
local tot = CreateFrame("Button", "ForeverUITargetOfTarget", frame, "SecureUnitButtonTemplate")
tot:SetWidth(120)
tot:SetHeight(49)
tot:SetPoint("TOPRIGHT", frame, "BOTTOMRIGHT", 12, 10)
tot:SetAttribute("unit", "targettarget")
tot:SetAttribute("*type1", "target")
tot:RegisterForClicks("AnyUp")
tot.unit = "targettarget"
local totPortrait = tot:CreateTexture(nil, "BACKGROUND")
totPortrait:SetWidth(37)
totPortrait:SetHeight(37)
totPortrait:SetPoint("TOPLEFT", 5, -5)
local totHealth = tot:CreateTexture(nil, "BORDER")
totHealth:SetPoint("TOPLEFT", 44, -17)
local totPower = tot:CreateTexture(nil, "BORDER")
totPower:SetPoint("TOPLEFT", 44, -29)
local totArt = tot:CreateTexture(nil, "ARTWORK")
totArt:SetPoint("CENTER")
ForeverUI.SetAtlas(totArt, "ui-hud-unitframe-targetoftarget-portraiton")
local totName = tot:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
totName:SetWidth(68)
totName:SetHeight(10)
totName:SetJustifyH("LEFT")
totName:SetPoint("TOPLEFT", totPortrait, "TOPRIGHT", 2, 0)
local TOT_POWER = {
MANA = "ui-hud-unitframe-targetoftarget-portraiton-bar-mana",
RAGE = "ui-hud-unitframe-targetoftarget-portraiton-bar-rage",
FOCUS = "ui-hud-unitframe-targetoftarget-portraiton-bar-focus",
ENERGY = "ui-hud-unitframe-targetoftarget-portraiton-bar-energy",
RUNIC_POWER = "ui-hud-unitframe-targetoftarget-portraiton-bar-runicpower",
}
local function updateTargetOfTarget()
if not UnitExists("targettarget") then
return
end
local maximum = UnitHealthMax("targettarget")
local fraction = 0
if maximum and maximum > 0 then
fraction = UnitHealth("targettarget") / maximum
end
ForeverUI.SetAtlasFill(totHealth, "ui-hud-unitframe-targetoftarget-portraiton-bar-health", fraction)
local powerType, powerToken = UnitPowerType("targettarget")
local powerMax = UnitPowerMax("targettarget", powerType)
local powerFraction = 0
if powerMax and powerMax > 0 then
powerFraction = UnitPower("targettarget", powerType) / powerMax
end
ForeverUI.SetAtlasFill(totPower, TOT_POWER[powerToken or ""] or TOT_POWER.MANA, powerFraction)
totName:SetText(UnitName("targettarget"))
SetPortraitTexture(totPortrait, "targettarget")
end
tot:SetScript("OnEvent", function(_self, event, unit)
if event == "PLAYER_TARGET_CHANGED" or unit == "target" or unit == "targettarget" then
updateTargetOfTarget()
end
end)
tot:RegisterEvent("PLAYER_TARGET_CHANGED")
tot:RegisterEvent("UNIT_TARGET")
tot:RegisterEvent("UNIT_HEALTH")
tot:RegisterEvent("UNIT_MAXHEALTH")
if RegisterUnitWatch then
RegisterUnitWatch(tot)
end
tot.portrait = totPortrait
tot.healthFill = totHealth
tot.powerFill = totPower
tot.art = totArt
tot.nameText = totName
ForeverUI.TargetOfTarget = tot
ForeverUI.TargetOfTargetUpdate = updateTargetOfTarget
ForeverUI.TargetFrame = frame
ForeverUI.Layout.Register(frame, "targetframe", L.TARGETFRAME_EDIT_LABEL, "TOPLEFT", "TOPLEFT", 250, -10)