Files
nocode e794c49c84 feat(announcement_menu): add theme-aware outer border color for loader style
introduce OuterCol() function to dynamically determine the outer border color based on the announcement theme configuration (white or blue). update the loader style border to use this function instead of hardcoded white color, allowing theme consistency across the announcement menu.
2026-07-20 18:23:49 +02:00

242 lines
8.7 KiB
Lua

local rndx = include("lib/rndx.lua")
local logo = Material("nocode/announcement/logo.png")
-- client/ charge avant shared/, donc je m'assure que la table est là
BladW = BladW or {}
BladW.Announcement = BladW.Announcement or {}
local COL_ACCENT = Color(76, 119, 200)
local COL_WHITE = Color(255, 255, 255)
local COL_BG = Color(0, 0, 0, 200)
local COL_TRACK = Color(54, 54, 54, 200)
-- couleur des contours extérieurs selon la config ("blue" ou "white")
local function OuterCol()
return (BladW.Announcement.Conf or {}).announcement_theme == "white" and COL_WHITE or COL_ACCENT
end
-- fonts responsives (refaites quand la résolution change)
local function AnnScale()
return math.min(ScrW() / 1920, ScrH() / 1080)
end
-- durées + easing de l'anim d'apparition/disparition
local INTRO_TIME = 0.45
local OUTRO_TIME = 0.35
local function EaseOutCubic(t) return 1 - (1 - t) ^ 3 end
local function BuildFonts()
local s = AnnScale()
surface.CreateFont("bladw_ann_title", {
font = "Poppins-SemiBold", size = math.max(1, math.Round(25 * s)), weight = 600, antialias = true,
})
surface.CreateFont("bladw_ann_text", {
font = "Poppins-SemiBold", size = math.max(1, math.Round(20 * s)), weight = 800, antialias = true,
})
end
BuildFonts()
hook.Add("OnScreenSizeChanged", "BladeWin:AnnouncementFonts", BuildFonts)
-- coupe le texte en lignes qui rentrent dans maxW (px) pour la police donnée
local function WrapText(text, font, maxW)
surface.SetFont(font)
local lines, line = {}, ""
for _, word in ipairs(string.Explode(" ", text or "")) do
local test = (line == "") and word or (line .. " " .. word)
if surface.GetTextSize(test) > maxW and line ~= "" then
lines[#lines + 1] = line
line = word
else
line = test
end
end
if line ~= "" then lines[#lines + 1] = line end
return lines
end
-- le contour du cadre sert de jauge : reste en colRemain, ce qui est passé en colDone (1 = plein, 0 = fini)
local function DrawBorderTimer(x, y, w, h, r, remaining, colRemain, colDone, thickness)
thickness = math.max(1, thickness or 3)
local pts = {}
local function line(x1, y1, x2, y2)
local steps = math.max(1, math.floor(math.Distance(x1, y1, x2, y2) / 4))
for i = 0, steps do
pts[#pts + 1] = { Lerp(i / steps, x1, x2), Lerp(i / steps, y1, y2) }
end
end
local function arc(cx, cy, a0, a1)
for i = 0, 6 do
local a = math.rad(Lerp(i / 6, a0, a1))
pts[#pts + 1] = { cx + math.cos(a) * r, cy + math.sin(a) * r }
end
end
-- sens horaire à partir du bord haut
line(x + r, y, x + w - r, y)
arc (x + w - r, y + r, 270, 360)
line(x + w, y + r, x + w, y + h - r)
arc (x + w - r, y + h - r, 0, 90)
line(x + w - r, y + h, x + r, y + h)
arc (x + r, y + h - r, 90, 180)
line(x, y + h - r, x, y + r)
arc (x + r, y + r, 180, 270)
local total = 0
for i = 1, #pts - 1 do
total = total + math.Distance(pts[i][1], pts[i][2], pts[i + 1][1], pts[i + 1][2])
end
if total == 0 then return end
local consumedLen = (1 - remaining) * total
draw.NoTexture()
local acc = 0
for i = 1, #pts - 1 do
local x1, y1 = pts[i][1], pts[i][2]
local x2, y2 = pts[i + 1][1], pts[i + 1][2]
local segLen = math.Distance(x1, y1, x2, y2)
surface.SetDrawColor(acc < consumedLen and colDone or colRemain)
surface.DrawTexturedRectRotated((x1 + x2) * 0.5, (y1 + y2) * 0.5,
segLen + thickness, thickness, -math.deg(math.atan2(y2 - y1, x2 - x1)))
acc = acc + segLen
end
end
-- état de l'annonce en cours (survit au reload)
BladW.Announcement.Active = BladW.Announcement.Active or false
BladW.Announcement.Title = BladW.Announcement.Title or "Annonce"
BladW.Announcement.Text = BladW.Announcement.Text or ""
BladW.Announcement.Style = BladW.Announcement.Style or "loader"
BladW.Announcement.Duration = BladW.Announcement.Duration or 10
BladW.Announcement.StartTime = BladW.Announcement.StartTime or 0
-- lance une annonce. style/duration vides = valeurs de la config
function BladW.Announcement.Show(title, text, style, duration)
local Conf = BladW.Announcement.Conf or {}
BladW.Announcement.Title = (title and title ~= "") and title or "Annonce"
BladW.Announcement.Text = text or ""
BladW.Announcement.Style = (style and style ~= "") and style or (Conf.announcement_style or "loader")
BladW.Announcement.Duration = (duration and duration > 0) and duration or (Conf.announcement_duration or 10)
BladW.Announcement.StartTime = CurTime()
BladW.Announcement.Active = true
if Conf.announcement_sound and Conf.announcement_sound ~= "" then
surface.PlaySound(Conf.announcement_sound)
end
end
-- le serveur m'envoie une annonce à afficher
net.Receive("bladWShowAnnouncement", function()
local title = net.ReadString()
local text = net.ReadString()
local style = net.ReadString()
local duration = net.ReadUInt(16)
BladW.Announcement.Show(title, text, style, duration)
end)
-- affichage (responsive + s'adapte au message)
hook.Add("HUDPaint", "BladeWin:Announcement", function()
if not BladW.Announcement.Active then return end
local ply = LocalPlayer()
if not IsValid(ply) then return end
local duration = BladW.Announcement.Duration or 10
local elapsed = CurTime() - BladW.Announcement.StartTime
-- temps écoulé -> on cache
if elapsed >= duration then
BladW.Announcement.Active = false
return
end
local style = BladW.Announcement.Style or "loader"
local title = BladW.Announcement.Title
local text = BladW.Announcement.Text
local remaining = math.Clamp(1 - (elapsed / duration), 0, 1)
-- échelle responsive
local s = AnnScale()
local padX = 26 * s
local padY = 18 * s
local gap = 8 * s
local logoS = 62 * s
local barW = 200 * s
local barH = 18 * s
local radius = 14 * s
-- wrap du message (largeur interne responsive, la vraie limite c'est le nb de caractères)
local wrapW = ScrW() * 0.8
local lines = WrapText(text, "bladw_ann_text", wrapW)
surface.SetFont("bladw_ann_title")
local titleW, titleH = surface.GetTextSize(title)
surface.SetFont("bladw_ann_text")
local _, lineH = surface.GetTextSize("Ay")
local msgW = 0
for _, l in ipairs(lines) do
msgW = math.max(msgW, (surface.GetTextSize(l)))
end
-- taille de la box selon le contenu
local contentW = math.max(titleW, msgW, style == "loader" and barW or 0)
local boxW = math.Clamp(contentW + padX * 2, 260 * s, ScrW() * 0.92)
local msgH = #lines * lineH
local boxH = padY + logoS + gap + titleH + gap + msgH
+ (style == "loader" and (gap + barH) or 0) + padY
-- anim : fondu + glisse du haut (et l'inverse quand ça part)
local appear = math.Clamp(elapsed / INTRO_TIME, 0, 1)
local disappear = math.Clamp((duration - elapsed) / OUTRO_TIME, 0, 1)
local anim = math.min(EaseOutCubic(appear), EaseOutCubic(disappear)) -- 0 -> 1 -> 0
local slide = (1 - anim) * 26 * s
local boxX = (ScrW() - boxW) * 0.5
local boxY = ScrH() * 0.035 - slide
local cx = boxX + boxW * 0.5
surface.SetAlphaMultiplier(anim)
-- fond
rndx.Draw(radius, boxX, boxY, boxW, boxH, nil, rndx.SHAPE_FIGMA + rndx.BLUR)
rndx.Draw(radius, boxX, boxY, boxW, boxH, COL_BG, rndx.SHAPE_FIGMA)
-- le loader garde un contour fixe (couleur selon le thème config ; le simple a sa jauge sur le bord)
if style == "loader" then
rndx.DrawOutlined(radius, boxX, boxY, boxW, boxH, OuterCol(), 3 * s, rndx.SHAPE_FIGMA)
end
-- contenu empilé et centré
local y = boxY + padY
rndx.DrawMaterial(0, cx - logoS * 0.5, y, logoS, logoS, COL_WHITE, logo)
y = y + logoS + gap
draw.SimpleText(title, "bladw_ann_title", cx, y, COL_WHITE, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
y = y + titleH + gap
for _, l in ipairs(lines) do
draw.SimpleText(l, "bladw_ann_text", cx, y, COL_WHITE, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
y = y + lineH
end
-- jauge de temps
if style == "loader" then
y = y + gap
local bx = cx - barW * 0.5
rndx.Draw(barH * 0.5, bx, y, barW, barH, COL_TRACK, rndx.SHAPE_FIGMA)
rndx.Draw(barH * 0.5, bx, y, barW * remaining, barH, COL_ACCENT, rndx.SHAPE_FIGMA)
else
-- le bord bleu qui se vide en blanc
DrawBorderTimer(boxX, boxY, boxW, boxH, radius, remaining, COL_ACCENT, COL_WHITE, 3 * s)
end
surface.SetAlphaMultiplier(1)
end)