-- Necessary Eversion of Konstant Obscenity (NEKO) v1.0 -- Author: mango-ki (https://nekoa.me) -- Date: 23/01/2026 ----------------------------------------------------------------------------- -- This script watches for words in external word blacklists, as well as chat abuse, and blocks them in chat. It also bans players who use a blacklisted word in their username. ----------------------------------------------------------------------------- -- VARIABLES -- local version = "v1.0" local names = {} local badWords = {} local badNameWords = {} local strangeChars = {"<", ">", "{", "}"} local savedNames = {} local attempts = 0 local attemptThreshold = 5 ----------------------------------------------------------------------------- -- FUNCTIONS -- local function N_FormatLog(p, level) local color local soundID if level == 2 then color = "\x85" soundID = 175 elseif level == 1 then color = "\x87" soundID = 174 else color = "\x81" soundID = 181 end S_StartSound(nil, soundID, p) return color, soundID end local function N_ChatLog(p, text, level) local color, soundID = N_FormatLog(p, level) chatprintf(p, color .. "[NEKO] " .. text .. "\x80") end local function N_ConsoleLog(p, text, level) local color, soundID = N_FormatLog(p, level) CONS_Printf(p, color .. "[NEKO] " .. text .. "\x80") end ----------------------------------------------------------------------------- local function loadTxtIntoTable(p, filepath, list) local f = io.openlocal(filepath, "r") if f == nil then N_ConsoleLog(p, filepath .. " was not found in your luafiles folder. Please add it, otherwise NEKO will not work!", 2) return else local contents = f:read() for str in string.gmatch(contents, "([^,]+)") do table.insert(list, str) end f:close() N_ConsoleLog(p, filepath .. " word list loaded successfully.", 0) end end local function checkPlayerName(p, badWord) local playerLower = string.lower(p.name) local match = string.match(playerLower, badWord) if match == badWord then if p ~= server then table.insert(savedNames, p.name) COM_BufInsertText(server, "ban " .. #p) return end end end local function checkPlayerMessage(p, message, badWord) local msgLower = string.lower(message) local match = string.match(msgLower, badWord) if attempts > attemptThreshold then COM_BufInsertText(server, "muteplayer " .. #p) N_ChatLog(p, "You've reached the maximum amount of attempts, so you have been muted.", 2) return true elseif match == badWord then N_ChatLog(p, "Your message has been blocked, because it contained the following phrase: '" .. badWord .. "'.", 1) return true elseif string.len(msgLower) > 150 then N_ChatLog(p, "Your message has been blocked, because it was longer than 150 characters.", 1) return true else return false end end local function iterateThroughNameLists(p) for _, name in ipairs(savedNames) do if p.name == name then COM_BufInsertText(server, "ban " .. #p) return end end for _, name in ipairs(names) do checkPlayerName(p, name) end for _, word in ipairs(badWords) do checkPlayerName(p, word) end for _, word in ipairs(badNameWords) do checkPlayerName(p, word) end end ----------------------------------------------------------------------------- -- COMMANDS -- COM_AddCommand("nekoban", function(p, playerName) if playerName == nil then N_ConsoleLog(p, "Usage: nekoban 'playername'\nThis IP bans a player and also adds their name to the list of banned names.", 0) return else for player in players.iterate do if player.name == playerName then table.insert(savedNames, playerName) COM_BufInsertText(server, "ban " .. playerName) N_ConsoleLog(p, playerName .. " has been banned and their name has been added to the banned name list.", 2) return end end N_ConsoleLog(p, playerName .. " doesn't seem to be here.", 1) end end) ----------------------------------------------------------------------------- -- HOOKS -- addHook("PlayerSpawn", function(p) loadTxtIntoTable(p, "client/NEKO-Moderator/badWords.txt", badWords) loadTxtIntoTable(p, "client/NEKO-Moderator/badNameWords.txt", badNameWords) loadTxtIntoTable(p, "client/NEKO-Moderator/customNameWords.txt", names) iterateThroughNameLists(p) N_ChatLog(p, "Welcome, " .. p.name .. "! This server is using NEKO " .. version .. " for user moderation.", 0) end) addHook("PlayerThink", iterateThroughNameLists) addHook("PlayerMsg", function(p, type, target, msg) for _, word in ipairs(badWords) do if checkPlayerMessage(p, msg, word) then attempts = $ + 1 return true end end for _, char in ipairs(strangeChars) do if checkPlayerMessage(p, msg, char) then attempts = $ + 1 return true end end attempts = 0 return false end)