2d815b1132
Points de combo : ComboFrame, le seul affichage de 3.3.5, était supprimé sans remplaçant ; voleurs et druides félins n'en voyaient aucun. Il est gardé et posé sur notre portrait, au décalage de ComboFrame.xml. Joueur en véhicule : les barres montrent "vehicle", mais seuls les événements de "player" étaient lus ; la vie et l'énergie du véhicule se figeaient (Oculus, Ulduar, Joug-d'hiver). Les textes suivent aussi. Groupe : un membre sorti de son véhicule gardait le jeton partypetN, et son cadre ne se mettait plus jamais à jour ; le test porte sur partyN, et le nom est celui du membre, comme le client. Barre d'incantation : STOP, FAILED et INTERRUPTED ne visent plus que l'incantation affichée (son castID), comme CastingBarFrame : une touche pressée de nouveau pendant un sort affichait « Échec » et effaçait la vraie barre ; un sort instantané refusé montrait une barre rouge. Cible de la cible : "targettarget" n'a aucun événement en 3.3.5 ; elle est interrogée cinq fois par seconde tant qu'elle est montrée (le client le fait à chaque image). Après un rechargement en combat, les cadres joueur et cible du client sont masqués à la sortie du combat. Raid : chaque événement d'unité reconstruisait tout le bouton (barres, rôle, auras, onze icônes réancrées, une table allouée) ; santé, ressource, auras et menace ne refont plus que leur partie, et les grilles d'auras ne bougent que si le décalage des icônes de dissipation change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KxRZNHkq453dyUMcWsyUf1
201 lines
5.9 KiB
Lua
201 lines
5.9 KiB
Lua
-- ForeverUI: the player cast bar. Art: interface/castingbar/uicastingbar.blp (ui-castingbar-*).
|
|
-- Data as in 3.3.5 CastingBarFrame.lua: UnitCastingInfo / UnitChannelInfo (times in ms) and
|
|
-- the UNIT_SPELLCAST_* events. A cast fills, a channel drains.
|
|
-- The bar is its own layout system, moved apart from the unit frames, as in camelot's editor.
|
|
|
|
local BAR_WIDTH, BAR_HEIGHT = 214, 16
|
|
local FILL_WIDTH = 209
|
|
local L = ForeverUI.L
|
|
|
|
local FILL = {
|
|
standard = "ui-castingbar-filling-standard",
|
|
channel = "ui-castingbar-filling-channel",
|
|
uninterruptible = "ui-castingbar-uninterruptable",
|
|
interrupted = "ui-castingbar-interrupted",
|
|
}
|
|
|
|
local HOLD_AFTER_END = 1.0
|
|
|
|
local frame = CreateFrame("Frame", "ForeverUICastBar", UIParent)
|
|
frame:SetWidth(BAR_WIDTH)
|
|
frame:SetHeight(BAR_HEIGHT)
|
|
frame:SetFrameStrata("MEDIUM")
|
|
frame:Hide()
|
|
|
|
local background = frame:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(background, "ui-castingbar-background")
|
|
background:SetPoint("CENTER")
|
|
|
|
local fill = frame:CreateTexture(nil, "BORDER")
|
|
fill:SetPoint("LEFT", background, "LEFT", 0, 0)
|
|
|
|
local border = frame:CreateTexture(nil, "ARTWORK")
|
|
ForeverUI.SetAtlas(border, "ui-castingbar-frame")
|
|
border:SetPoint("CENTER")
|
|
|
|
local shield = frame:CreateTexture(nil, "OVERLAY")
|
|
ForeverUI.SetAtlas(shield, "ui-castingbar-shield")
|
|
shield:SetPoint("CENTER", frame, "LEFT", 2, -1)
|
|
shield:Hide()
|
|
|
|
local spellText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
|
spellText:SetPoint("CENTER", frame, "CENTER", 0, 0)
|
|
|
|
local timeText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
|
timeText:SetPoint("RIGHT", frame, "RIGHT", -6, 0)
|
|
|
|
frame.background = background
|
|
frame.fill = fill
|
|
frame.border = border
|
|
frame.shield = shield
|
|
frame.spellText = spellText
|
|
frame.timeText = timeText
|
|
|
|
local function stopBar()
|
|
frame.casting = false
|
|
frame.channeling = false
|
|
frame.holdUntil = nil
|
|
frame:Hide()
|
|
end
|
|
|
|
-- Shows the failed bar for HOLD_AFTER_END seconds.
|
|
-- atlasKey: key in FILL; message: text shown on the bar
|
|
local function showFailure(atlasKey, message)
|
|
frame.casting = false
|
|
frame.channeling = false
|
|
frame.holdUntil = GetTime() + HOLD_AFTER_END
|
|
ForeverUI.SetAtlasFill(fill, FILL[atlasKey], 1, FILL_WIDTH)
|
|
spellText:SetText(message or "")
|
|
timeText:SetText("")
|
|
shield:Hide()
|
|
frame:Show()
|
|
end
|
|
|
|
-- Starts the bar from the client's current cast. channel: true for a channeled spell
|
|
local function startCast(channel)
|
|
local name, _subtext, text, texture, startTime, endTime, _isTrade, castID, notInterruptible
|
|
if channel then
|
|
name, _subtext, text, texture, startTime, endTime, _isTrade, notInterruptible = UnitChannelInfo("player")
|
|
else
|
|
name, _subtext, text, texture, startTime, endTime, _isTrade, castID, notInterruptible = UnitCastingInfo("player")
|
|
end
|
|
|
|
if not name then
|
|
stopBar()
|
|
return
|
|
end
|
|
|
|
frame.casting = not channel
|
|
frame.channeling = channel and true or false
|
|
frame.castID = castID
|
|
frame.startTime = startTime / 1000
|
|
frame.endTime = endTime / 1000
|
|
frame.holdUntil = nil
|
|
frame.fillKey = notInterruptible and "uninterruptible" or (channel and "channel" or "standard")
|
|
|
|
spellText:SetText(text or name)
|
|
if notInterruptible then
|
|
shield:Show()
|
|
else
|
|
shield:Hide()
|
|
end
|
|
frame:Show()
|
|
end
|
|
|
|
frame:SetScript("OnEvent", function(_self, event, unit, _spell, _rank, castID)
|
|
if event == "PLAYER_ENTERING_WORLD" then
|
|
ForeverUI.Suppress(CastingBarFrame)
|
|
stopBar()
|
|
return
|
|
end
|
|
|
|
if unit ~= "player" then
|
|
return
|
|
end
|
|
|
|
if event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_DELAYED" then
|
|
startCast(false)
|
|
elseif event == "UNIT_SPELLCAST_CHANNEL_START" or event == "UNIT_SPELLCAST_CHANNEL_UPDATE" then
|
|
startCast(true)
|
|
elseif event == "UNIT_SPELLCAST_STOP" then
|
|
-- As 3.3.5's CastingBarFrame_OnEvent: only the cast on the bar (its castID), and not
|
|
-- after a failure, whose red bar stays HOLD_AFTER_END
|
|
if frame.casting and castID == frame.castID then
|
|
stopBar()
|
|
end
|
|
elseif event == "UNIT_SPELLCAST_CHANNEL_STOP" then
|
|
if frame.channeling then
|
|
stopBar()
|
|
end
|
|
elseif event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_INTERRUPTED" then
|
|
-- A refused attempt (a key pressed again during a cast, an instant spell out of range)
|
|
-- carries another castID, or comes with no cast on the bar
|
|
if frame.casting and castID == frame.castID then
|
|
showFailure("interrupted", event == "UNIT_SPELLCAST_FAILED" and FAILED or INTERRUPTED)
|
|
end
|
|
elseif event == "UNIT_SPELLCAST_INTERRUPTIBLE" then
|
|
shield:Hide()
|
|
frame.fillKey = frame.channeling and "channel" or "standard"
|
|
elseif event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE" then
|
|
shield:Show()
|
|
frame.fillKey = "uninterruptible"
|
|
end
|
|
end)
|
|
|
|
frame:SetScript("OnUpdate", function(self)
|
|
if self.holdUntil then
|
|
if GetTime() > self.holdUntil then
|
|
stopBar()
|
|
end
|
|
return
|
|
end
|
|
|
|
if not (self.casting or self.channeling) then
|
|
return
|
|
end
|
|
|
|
local now = GetTime()
|
|
local total = self.endTime - self.startTime
|
|
if total <= 0 then
|
|
stopBar()
|
|
return
|
|
end
|
|
|
|
local elapsed = now - self.startTime
|
|
if elapsed < 0 then
|
|
elapsed = 0
|
|
end
|
|
|
|
local fraction = elapsed / total
|
|
if fraction > 1 then
|
|
fraction = 1
|
|
end
|
|
|
|
-- A cast fills, a channel drains.
|
|
if self.channeling then
|
|
fraction = 1 - fraction
|
|
end
|
|
|
|
ForeverUI.SetAtlasFill(fill, FILL[self.fillKey or "standard"], fraction, FILL_WIDTH)
|
|
timeText:SetText(string.format("%.1f", math.max(0, self.endTime - now)))
|
|
|
|
if now >= self.endTime then
|
|
stopBar()
|
|
end
|
|
end)
|
|
|
|
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
frame:RegisterEvent("UNIT_SPELLCAST_START")
|
|
frame:RegisterEvent("UNIT_SPELLCAST_STOP")
|
|
frame:RegisterEvent("UNIT_SPELLCAST_DELAYED")
|
|
frame:RegisterEvent("UNIT_SPELLCAST_FAILED")
|
|
frame:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
|
|
frame:RegisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE")
|
|
frame:RegisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE")
|
|
frame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
|
|
frame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
|
|
frame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
|
|
|
|
ForeverUI.CastBar = frame
|
|
ForeverUI.Layout.Register(frame, "castbar", L.CASTBAR_EDIT_LABEL, "BOTTOM", "BOTTOM", 0, 190)
|