115de7ed41
The addon and the art it needs, read from a modern client and served to 3.3.5 through texture coordinates, since that client has no atlas. What is in place: player frame with its states, death knight runes, target frame and its classification rings, cast bar, action bar with its page block and end caps, micro menu, bags bar, experience and reputation bars. Every piece registers itself as a movable system. This folder is the workspace. The addon in a client and the art in patch-Z are copies tools/deployer.py makes, and what sits under Interface\ForeverUI in the patch is exactly what data/art holds -- the deployer removes from the archive anything this folder no longer carries. Each .blp comes with the .png that shows what it holds. docs/AMELIORATIONS.md lists what is known to be improvable: where the reproduction departs from the reference and why, what the 2010 client cannot do, and the debts left in the tooling. The repository README also gains the row for mod-limit-break, which was written earlier and had not been committed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
209 lines
7.3 KiB
Lua
209 lines
7.3 KiB
Lua
-- ForeverUI : les runes du chevalier de la mort.
|
|
--
|
|
-- RELEVE DES SOURCES
|
|
-- art mainline/RuneFrame.xml : un bouton de 24x24 empile, du fond
|
|
-- vers l'avant, UF-DKRunes-BGShadow (centre, y -3), BGDis ou
|
|
-- BGActive, le crane SkullDis ou <type>-SkullActive, puis la
|
|
-- lueur <type>-FilledGlwA. Toutes ces images sont sur la feuille
|
|
-- interface/hud/uideathknightrunes.blp.
|
|
-- donnees 3.3.5 RuneFrame.lua : GetRuneCooldown(i) rend debut, duree et
|
|
-- disponibilite ; GetRuneType(i) rend 1 sang, 2 impie, 3 givre,
|
|
-- 4 mort. Evenements RUNE_POWER_UPDATE et RUNE_TYPE_UPDATE.
|
|
-- cadre camelot bascule l'art du cadre sur la variante ClassResource
|
|
-- des qu'une ressource de classe s'affiche sous les barres.
|
|
-- entorse la source habille le balayage de recharge avec l'atlas
|
|
-- UF-DKRunes-<type>-LevelBar ; 3.3.5 n'a ni SetSwipeTexture ni
|
|
-- SetTexCoordRange, le balayage reste donc celui du client.
|
|
--
|
|
-- Le type 4 (rune de mort), propre a 3.3.5, n'a pas d'art dedie sur la feuille
|
|
-- moderne : il prend le jeu "default", qui est justement le crane neutre.
|
|
|
|
local CLASS = select(2, UnitClass("player"))
|
|
if CLASS ~= "DEATHKNIGHT" then
|
|
return
|
|
end
|
|
|
|
local frame = ForeverUI.PlayerFrame
|
|
|
|
-- RELEVE DE PLACEMENT, recopie des deux fichiers
|
|
-- mainline/PlayerFrame.xml : PlayerBottomManagedFrameContainer, largeur
|
|
-- fixe 160, TOP ancre sur le BOTTOM du cadre joueur en (30, 25).
|
|
-- mainline/RuneFrame.xml : RuneFrame 130 x 24, scale 0.95, et ses runes
|
|
-- rangees avec un espacement de -1 ; chaque bouton fait 24 x 24, la
|
|
-- minuterie 27 x 27 centree.
|
|
local RUNE_COUNT = 6
|
|
local RUNE_SIZE = 24
|
|
local RUNE_SPACING = -1
|
|
local COOLDOWN_SIZE = 27
|
|
local BAR_WIDTH, BAR_HEIGHT = 130, 24
|
|
local BAR_SCALE = 0.95
|
|
local CONTAINER_WIDTH = 160
|
|
|
|
local TYPE_PREFIX = {
|
|
[1] = "blood",
|
|
[2] = "unholy",
|
|
[3] = "frost",
|
|
[4] = "default",
|
|
}
|
|
|
|
-- Le cadre joueur prend sa variante a ressource de classe : elle est trois
|
|
-- pixels plus haute et menage la bande ou se posent les runes.
|
|
ForeverUI.PlayerFrameSetArt("ui-hud-unitframe-player-portraiton-classresource")
|
|
|
|
-- Le cadre de runes du client se superposait au notre : il faut le
|
|
-- neutraliser, et pas seulement le masquer -- RuneFrame se reaffiche a chaque
|
|
-- mise a jour de rune.
|
|
ForeverUI.Suppress(RuneFrame)
|
|
|
|
-- Le conteneur reprend la bande des ressources de classe : il n'est pas mis a
|
|
-- l'echelle, sinon son ancrage le serait aussi. C'est la barre de runes qui
|
|
-- porte le 0,95 de la source.
|
|
local container = CreateFrame("Frame", "ForeverUIClassResourceContainer", frame)
|
|
container:SetWidth(CONTAINER_WIDTH)
|
|
container:SetHeight(BAR_HEIGHT)
|
|
container:SetPoint("TOP", frame, "BOTTOM", 30, 25)
|
|
container:SetFrameLevel(frame:GetFrameLevel() + 1)
|
|
|
|
local runeBar = CreateFrame("Frame", "ForeverUIRuneBar", container)
|
|
runeBar:SetWidth(BAR_WIDTH)
|
|
runeBar:SetHeight(BAR_HEIGHT)
|
|
runeBar:SetScale(BAR_SCALE)
|
|
runeBar:SetPoint("CENTER", container, "CENTER", 0, 0)
|
|
|
|
local buttons = {}
|
|
|
|
-- Les calques, dans l'ordre et avec les melanges du XML : tous en BLEND, pas
|
|
-- un seul en additif. Les calques Mid, Eyes, Glow, Glow2 et Smoke ne servent
|
|
-- qu'aux transitions et finissent tous a 0 : ils ne sont pas construits.
|
|
for index = 1, RUNE_COUNT do
|
|
local button = CreateFrame("Frame", nil, runeBar)
|
|
button:SetWidth(RUNE_SIZE)
|
|
button:SetHeight(RUNE_SIZE)
|
|
-- six boutons de 24 espaces de -1 : 139 de large, centres dans les 130
|
|
-- declares par la source.
|
|
button:SetPoint("LEFT", runeBar, "LEFT",
|
|
(BAR_WIDTH - (RUNE_COUNT * RUNE_SIZE + (RUNE_COUNT - 1) * RUNE_SPACING)) / 2
|
|
+ (index - 1) * (RUNE_SIZE + RUNE_SPACING), 0)
|
|
|
|
button.shadow = button:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(button.shadow, "uf-dkrunes-bgshadow")
|
|
button.shadow:SetPoint("CENTER", 0, -3)
|
|
|
|
button.bgInactive = button:CreateTexture(nil, "BORDER")
|
|
ForeverUI.SetAtlas(button.bgInactive, "uf-dkrunes-bgdis")
|
|
button.bgInactive:SetPoint("CENTER")
|
|
|
|
button.bgActive = button:CreateTexture(nil, "BORDER")
|
|
ForeverUI.SetAtlas(button.bgActive, "uf-dkrunes-bgactive")
|
|
button.bgActive:SetPoint("CENTER")
|
|
|
|
button.runeInactive = button:CreateTexture(nil, "ARTWORK")
|
|
ForeverUI.SetAtlas(button.runeInactive, "uf-dkrunes-skulldis")
|
|
button.runeInactive:SetPoint("CENTER")
|
|
|
|
button.runeGrad = button:CreateTexture(nil, "ARTWORK")
|
|
button.runeGrad:SetPoint("CENTER")
|
|
|
|
button.runeLines = button:CreateTexture(nil, "ARTWORK")
|
|
button.runeLines:SetPoint("CENTER")
|
|
|
|
button.runeActive = button:CreateTexture(nil, "ARTWORK")
|
|
button.runeActive:SetPoint("CENTER")
|
|
|
|
button.cooldown = CreateFrame("Cooldown", nil, button, "CooldownFrameTemplate")
|
|
button.cooldown:SetWidth(COOLDOWN_SIZE)
|
|
button.cooldown:SetHeight(COOLDOWN_SIZE)
|
|
button.cooldown:SetPoint("CENTER")
|
|
|
|
buttons[index] = button
|
|
end
|
|
|
|
-- ALPHAS FINAUX, releves dans les groupes d'animation du XML (setToFinalAlpha) :
|
|
-- pret (CooldownEndingAnim) : BG_Active 1, BG_Inactive 0, Rune_Active 1,
|
|
-- Rune_Inactive 0, et tout le reste -- lueurs comprises -- a 0.
|
|
-- vide (EmptyAnim) : BG_Active 0, BG_Inactive 1, Rune_Active 0,
|
|
-- Rune_Inactive 0.4, Rune_Lines 0.
|
|
-- en recharge (CooldownFillAnim) : par-dessus l'etat vide, Rune_Grad 0.3 et
|
|
-- Rune_Lines 0.3. Rien d'autre ne s'allume.
|
|
local function updateRune(index)
|
|
local button = buttons[index]
|
|
if not button then
|
|
return
|
|
end
|
|
|
|
local start, duration, ready = GetRuneCooldown(index)
|
|
local prefix = TYPE_PREFIX[GetRuneType(index) or 1] or "default"
|
|
|
|
ForeverUI.SetAtlas(button.runeGrad, "uf-dkrunes-" .. prefix .. "-skullgrad")
|
|
ForeverUI.SetAtlas(button.runeLines, "uf-dkrunes-" .. prefix .. "-skulllines")
|
|
ForeverUI.SetAtlas(button.runeActive, "uf-dkrunes-" .. prefix .. "-skullactive")
|
|
|
|
if ready then
|
|
button.bgActive:SetAlpha(1)
|
|
button.bgInactive:SetAlpha(0)
|
|
button.runeActive:SetAlpha(1)
|
|
button.runeInactive:SetAlpha(0)
|
|
button.runeGrad:SetAlpha(0)
|
|
button.runeLines:SetAlpha(0)
|
|
else
|
|
button.bgActive:SetAlpha(0)
|
|
button.bgInactive:SetAlpha(1)
|
|
button.runeActive:SetAlpha(0)
|
|
button.runeInactive:SetAlpha(0.4)
|
|
|
|
local recharge = (start and duration and duration > 0) and 0.3 or 0
|
|
button.runeGrad:SetAlpha(recharge)
|
|
button.runeLines:SetAlpha(recharge)
|
|
end
|
|
|
|
if start and duration and duration > 0 and CooldownFrame_SetTimer then
|
|
CooldownFrame_SetTimer(button.cooldown, start, duration, ready and 0 or 1)
|
|
end
|
|
|
|
button.ready = ready and true or false
|
|
end
|
|
|
|
local function updateAllRunes()
|
|
for index = 1, RUNE_COUNT do
|
|
updateRune(index)
|
|
end
|
|
end
|
|
|
|
runeBar:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
runeBar:RegisterEvent("RUNE_POWER_UPDATE")
|
|
runeBar:RegisterEvent("RUNE_TYPE_UPDATE")
|
|
|
|
runeBar:SetScript("OnEvent", function(_self, event, rune)
|
|
if event == "PLAYER_ENTERING_WORLD" then
|
|
ForeverUI.Suppress(RuneFrame)
|
|
updateAllRunes()
|
|
elseif rune then
|
|
updateRune(rune)
|
|
else
|
|
updateAllRunes()
|
|
end
|
|
end)
|
|
|
|
-- La fin d'une recharge ne previent pas toujours : tant qu'une rune tourne, on
|
|
-- relit dix fois par seconde. Rien ne tourne quand tout est pret.
|
|
runeBar:SetScript("OnUpdate", function(self, elapsed)
|
|
self.elapsed = (self.elapsed or 0) + elapsed
|
|
if self.elapsed < 0.1 then
|
|
return
|
|
end
|
|
self.elapsed = 0
|
|
|
|
for index = 1, RUNE_COUNT do
|
|
if not buttons[index].ready then
|
|
updateAllRunes()
|
|
return
|
|
end
|
|
end
|
|
end)
|
|
|
|
updateAllRunes()
|
|
|
|
ForeverUI.RuneBar = runeBar
|
|
ForeverUI.ClassResourceContainer = container
|
|
ForeverUI.RuneButtons = buttons
|