BladW = BladW or {} BladW.Announcement = BladW.Announcement or {} -- pour que les clients téléchargent le son resource.AddFile("sound/announce.mp3") -- coupe une chaîne à maxChars caractères (propre avec les accents) local function LimitChars(str, maxChars) str = tostring(str or "") local n = utf8.len(str) if not n or n <= maxChars then return str end local endByte = utf8.offset(str, maxChars + 1) return endByte and string.sub(str, 1, endByte - 1) or str end -- ouvre le menu pour le joueur (faut avoir le droit) concommand.Add("bladw_amenu", function(ply, cmd) if not IsValid(ply) or not BladW.Announcement.HasAccess(ply) then return end net.Start("bladWOpenAnnouncementMenu") net.Send(ply) end) -- /bannonce (ou !bannonce) dans le chat = ouvre le menu hook.Add("PlayerSay", "BladW:AnnouncementChatCmd", function(ply, text) local cmd = string.lower(string.Trim(text)) if cmd ~= "/bannonce" and cmd ~= "!bannonce" then return end -- que ceux qui ont le droit ouvrent le menu, mais on cache la commande pour tout le monde if IsValid(ply) and BladW.Announcement.HasAccess(ply) then net.Start("bladWOpenAnnouncementMenu") net.Send(ply) end return "" -- commande reconnue -> on la retire du chat end) -- reconstruit l'annonce finale : le preset sert de base, title/text passent devant function BladW.Announcement.Resolve(entry) local presets = BladW.Announcement.Presets or {} local base = (entry.preset and presets[entry.preset]) or {} return { title = (entry.title and entry.title ~= "" and entry.title) or base.title or "Annonce", text = (entry.text and entry.text ~= "" and entry.text ) or base.text or "", style = entry.style or base.style or "", duration = tonumber(entry.duration) or tonumber(base.duration) or 0, target = entry.target or base.target, -- usergroup ciblé (nil = tout le monde) } end -- envoie l'annonce à tout le monde. false si rien à envoyer ou si une annonce est déjà en cours function BladW.Announcement.Broadcast(entry) -- déjà une annonce à l'écran ? on n'en empile pas une autre if CurTime() < (BladW.Announcement.activeUntil or 0) then return false end local a = BladW.Announcement.Resolve(entry) if a.text == "" then return false end -- destinataires (nil = tout le monde) : -- liste de joueurs (menu) > liste de groupes (menu) + target unique (preset/schedule) local recipients if istable(entry.players) and #entry.players > 0 then recipients = {} for _, p in ipairs(entry.players) do if IsValid(p) and p:IsPlayer() then recipients[#recipients + 1] = p end end elseif (istable(entry.groups) and #entry.groups > 0) or (a.target and a.target ~= "" and a.target ~= "all") then local set = {} if istable(entry.groups) then for _, g in ipairs(entry.groups) do set[g] = true end end if a.target and a.target ~= "" and a.target ~= "all" then set[a.target] = true end recipients = {} for _, p in ipairs(player.GetAll()) do if set[p:GetUserGroup()] then recipients[#recipients + 1] = p end end end if recipients and #recipients == 0 then return false end -- personne à qui envoyer local Conf = BladW.Announcement.Conf or {} local maxLen = tonumber(Conf.announcement_max_length) or 120 local dur = a.duration > 0 and a.duration or (tonumber(Conf.announcement_duration) or 10) -- on bloque les suivantes le temps que celle-ci s'affiche BladW.Announcement.activeUntil = CurTime() + dur net.Start("bladWShowAnnouncement") net.WriteString(LimitChars(a.title, 64)) net.WriteString(LimitChars(a.text, maxLen)) net.WriteString(a.style or "") net.WriteUInt(math.Clamp(a.duration, 0, 65535), 16) if recipients then net.Send(recipients) else net.Broadcast() end return true end -- un admin veut poster une annonce -> je la diffuse net.Receive("bladWSendAnnouncement", function(len, ply) if not IsValid(ply) or not BladW.Announcement.HasAccess(ply) then return end local preset = net.ReadString() local title = net.ReadString() local text = net.ReadString() -- destinataires : "all" / "group" (liste de groupes) / "players" (liste de joueurs) -- le choix du menu est explicite -> il prime sur le target du preset local scope = net.ReadString() local target, groups, players = "all", nil, nil if scope == "group" then target = "" -- vide = on ignore le target du preset, on prend la liste groups = {} for _ = 1, net.ReadUInt(8) do groups[#groups + 1] = net.ReadString() end elseif scope == "players" then target = "" players = {} for _ = 1, net.ReadUInt(8) do local p = net.ReadEntity() if IsValid(p) and p:IsPlayer() then players[#players + 1] = p end end end local ok = BladW.Announcement.Broadcast({ preset = preset ~= "" and preset or nil, title = title, text = text, target = target, groups = groups, players = players, }) -- je réponds à l'admin : publié -> il ferme le menu, refusé -> il garde son texte local left = math.Clamp(math.ceil((BladW.Announcement.activeUntil or 0) - CurTime()), 0, 255) net.Start("bladWAnnouncementResult") net.WriteBool(ok) net.WriteUInt(left, 8) net.Send(ply) end)