e794c49c84
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.
242 lines
8.7 KiB
Lua
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)
|