local modstorage = core.get_mod_storage() -- crashed on pre-5.2 -- local modpath = minetest.get_modpath("colour_chat") -- dofile(modpath .. "/colournames.lua") -- This list of colour names was extracted and converted from -- https://drafts.csswg.org/css-color/#named-colors local colournames = {} colournames["aliceblue"] = "#F0F8FF" colournames["antiquewhite"] = "#FAEBD7" colournames["aqua"] = "#00FFFF" colournames["aquamarine"] = "#7FFFD4" colournames["azure"] = "#F0FFFF" colournames["beige"] = "#F5F5DC" colournames["bisque"] = "#FFE4C4" colournames["black"] = "#000000" colournames["blanchedalmond"] = "#FFEBCD" colournames["blue"] = "#0000FF" colournames["blueviolet"] = "#8A2BE2" colournames["brown"] = "#A52A2A" colournames["burlywood"] = "#DEB887" colournames["cadetblue"] = "#5F9EA0" colournames["chartreuse"] = "#7FFF00" colournames["chocolate"] = "#D2691E" colournames["coral"] = "#FF7F50" colournames["cornflowerblue"] = "#6495ED" colournames["cornsilk"] = "#FFF8DC" colournames["crimson"] = "#DC143C" colournames["cyan"] = "#00FFFF" colournames["darkblue"] = "#00008B" colournames["darkcyan"] = "#008B8B" colournames["darkgoldenrod"] = "#B8860B" colournames["darkgray"] = "#A9A9A9" colournames["darkgreen"] = "#006400" colournames["darkgrey"] = "#A9A9A9" colournames["darkkhaki"] = "#BDB76B" colournames["darkmagenta"] = "#8B008B" colournames["darkolivegreen"] = "#556B2F" colournames["darkorange"] = "#FF8C00" colournames["darkorchid"] = "#9932CC" colournames["darkred"] = "#8B0000" colournames["darksalmon"] = "#E9967A" colournames["darkseagreen"] = "#8FBC8F" colournames["darkslateblue"] = "#483D8B" colournames["darkslategray"] = "#2F4F4F" colournames["darkslategrey"] = "#2F4F4F" colournames["darkturquoise"] = "#00CED1" colournames["darkviolet"] = "#9400D3" colournames["deeppink"] = "#FF1493" colournames["deepskyblue"] = "#00BFFF" colournames["dimgray"] = "#696969" colournames["dimgrey"] = "#696969" colournames["dodgerblue"] = "#1E90FF" colournames["firebrick"] = "#B22222" colournames["floralwhite"] = "#FFFAF0" colournames["forestgreen"] = "#228B22" colournames["fuchsia"] = "#FF00FF" colournames["gainsboro"] = "#DCDCDC" colournames["ghostwhite"] = "#F8F8FF" colournames["gold"] = "#FFD700" colournames["goldenrod"] = "#DAA520" colournames["gray"] = "#808080" colournames["green"] = "#008000" colournames["greenyellow"] = "#ADFF2F" colournames["grey"] = "#808080" colournames["honeydew"] = "#F0FFF0" colournames["hotpink"] = "#FF69B4" colournames["indianred"] = "#CD5C5C" colournames["indigo"] = "#4B0082" colournames["ivory"] = "#FFFFF0" colournames["khaki"] = "#F0E68C" colournames["lavender"] = "#E6E6FA" colournames["lavenderblush"] = "#FFF0F5" colournames["lawngreen"] = "#7CFC00" colournames["lemonchiffon"] = "#FFFACD" colournames["lightblue"] = "#ADD8E6" colournames["lightcoral"] = "#F08080" colournames["lightcyan"] = "#E0FFFF" colournames["lightgoldenrodyellow"] = "#FAFAD2" colournames["lightgray"] = "#D3D3D3" colournames["lightgreen"] = "#90EE90" colournames["lightgrey"] = "#D3D3D3" colournames["lightpink"] = "#FFB6C1" colournames["lightsalmon"] = "#FFA07A" colournames["lightseagreen"] = "#20B2AA" colournames["lightskyblue"] = "#87CEFA" colournames["lightslategray"] = "#778899" colournames["lightslategrey"] = "#778899" colournames["lightsteelblue"] = "#B0C4DE" colournames["lightyellow"] = "#FFFFE0" colournames["lime"] = "#00FF00" colournames["limegreen"] = "#32CD32" colournames["linen"] = "#FAF0E6" colournames["magenta"] = "#FF00FF" colournames["maroon"] = "#800000" colournames["mediumaquamarine"] = "#66CDAA" colournames["mediumblue"] = "#0000CD" colournames["mediumorchid"] = "#BA55D3" colournames["mediumpurple"] = "#9370DB" colournames["mediumseagreen"] = "#3CB371" colournames["mediumslateblue"] = "#7B68EE" colournames["mediumspringgreen"] = "#00FA9A" colournames["mediumturquoise"] = "#48D1CC" colournames["mediumvioletred"] = "#C71585" colournames["midnightblue"] = "#191970" colournames["mintcream"] = "#F5FFFA" colournames["mistyrose"] = "#FFE4E1" colournames["moccasin"] = "#FFE4B5" colournames["navajowhite"] = "#FFDEAD" colournames["navy"] = "#000080" colournames["oldlace"] = "#FDF5E6" colournames["olive"] = "#808000" colournames["olivedrab"] = "#6B8E23" colournames["orange"] = "#FFA500" colournames["orangered"] = "#FF4500" colournames["orchid"] = "#DA70D6" colournames["palegoldenrod"] = "#EEE8AA" colournames["palegreen"] = "#98FB98" colournames["paleturquoise"] = "#AFEEEE" colournames["palevioletred"] = "#DB7093" colournames["papayawhip"] = "#FFEFD5" colournames["peachpuff"] = "#FFDAB9" colournames["peru"] = "#CD853F" colournames["pink"] = "#FFC0CB" colournames["plum"] = "#DDA0DD" colournames["powderblue"] = "#B0E0E6" colournames["purple"] = "#800080" colournames["rebeccapurple"] = "#663399" colournames["red"] = "#FF0000" colournames["rosybrown"] = "#BC8F8F" colournames["royalblue"] = "#4169E1" colournames["saddlebrown"] = "#8B4513" colournames["salmon"] = "#FA8072" colournames["sandybrown"] = "#F4A460" colournames["seagreen"] = "#2E8B57" colournames["seashell"] = "#FFF5EE" colournames["sienna"] = "#A0522D" colournames["silver"] = "#C0C0C0" colournames["skyblue"] = "#87CEEB" colournames["slateblue"] = "#6A5ACD" colournames["slategray"] = "#708090" colournames["slategrey"] = "#708090" colournames["snow"] = "#FFFAFA" colournames["springgreen"] = "#00FF7F" colournames["steelblue"] = "#4682B4" colournames["tan"] = "#D2B48C" colournames["teal"] = "#008080" colournames["thistle"] = "#D8BFD8" colournames["tomato"] = "#FF6347" colournames["turquoise"] = "#40E0D0" colournames["violet"] = "#EE82EE" colournames["wheat"] = "#F5DEB3" colournames["white"] = "#FFFFFF" colournames["whitesmoke"] = "#F5F5F5" colournames["yellow"] = "#FFFF00" colournames["yellowgreen"] = "#9ACD32" function colourname2hex(colname) if not colname then return "" end if colname == "" then return "" end if colname:sub(1,1) == "#" then if #colname == 7 then -- let's guess it's a hexcode as colour return colname end end if colournames[colname] then return colournames[colname] end -- be safe and return nothing return "" end local cr = minetest.get_csm_restrictions() local limitationlist = { "load_client_mods", "chat_messages", "read_itemdefs", "read_nodedefs", "lookup_nodes", "read_playerinfo" } local modfunction_limited = {} if not cr then minetest.display_chat_message("cr == nil") return else for _,r in ipairs(limitationlist) do modfunction_limited[r] = true if cr[r] then modfunction_limited[r] = false end end end local function show_restrictions() for _,r in ipairs(limitationlist) do minetest.display_chat_message(string.format("%-20s: %s",r, (modfunction_limited[r] and "allowed") or "forbidden")) end end show_restrictions() if not modfunction_limited[ "chat_messages" ] then minetest.display_chat_message( "chat_messages".." are forbidden --> not loading") return end local register_on_message = core.register_on_sending_chat_message if core.register_on_sending_chat_messages then register_on_message = core.register_on_sending_chat_messages end local function safe(func) -- wrap a function w/ logic to avoid crashing the game local f = function(...) local status, out = pcall(func, ...) if status then return out else log('warning', 'Error (func): ' .. out) return nil end end return f end local function paramsplit(str) -- minetest.display_chat_message("paramsplit 1") local s = str:gsub("^%s*(.-)%s*$", "%1") local p1 = string.find(s," ",1,true) if not p1 then return nil end -- minetest.display_chat_message("paramsplit 2") local p2 = string.find(s," ",p1+1,true) local s1 = str:sub(1,p1-1) if not p2 then return {s1,s1,str:sub(p1+1,512)} end -- minetest.display_chat_message("paramsplit 3") local s2 = str:sub(p1+1,p2-1) local s3 = str:sub(p2+1,512) return {s1,s2,s3} end local function rgb_to_hex(rgb) local hexadecimal = '#' for key, value in pairs(rgb) do local hex = '' while(value > 0)do local index = math.fmod(value, 16) + 1 value = math.floor(value / 16) hex = string.sub('0123456789ABCDEF', index, index) .. hex end if(string.len(hex) == 0)then hex = '00' elseif(string.len(hex) == 1)then hex = '0' .. hex end hexadecimal = hexadecimal .. hex end return hexadecimal end local function color_from_hue(hue) local h = hue / 60 local c = 255 local x = (1 - math.abs(h%2 - 1)) * 255 local i = math.floor(h); if (i == 0) then return rgb_to_hex({c, x, 0}) elseif (i == 1) then return rgb_to_hex({x, c, 0}) elseif (i == 2) then return rgb_to_hex({0, c, x}) elseif (i == 3) then return rgb_to_hex({0, x, c}); elseif (i == 4) then return rgb_to_hex({x, 0, c}); else return rgb_to_hex({c, 0, x}); end end local function pastel_from_hue(hue) local h = hue / 60 local c = 255 local d = 192 local x = (1 - math.abs(h%2 - 1)) * 255 local i = math.floor(h); if (i == 0) then return rgb_to_hex({c, x, d}) elseif (i == 1) then return rgb_to_hex({x, c, d}) elseif (i == 2) then return rgb_to_hex({d, c, x}) elseif (i == 3) then return rgb_to_hex({d, x, c}); elseif (i == 4) then return rgb_to_hex({x, d, c}); else return rgb_to_hex({c, d, x}); end end function hex2rgb(hex) -- added - found on github hex = hex:gsub("#","") return {tonumber("0x"..hex:sub(1,2)), tonumber("0x"..hex:sub(3,4)), tonumber("0x"..hex:sub(5,6))} end local function color_step(pos, col1, col2) -- added - gets a color between colors -- if not col1 then col1 = "#888888" end -- if not col2 then col2 = "#888888" end local rgb1 = hex2rgb(col1) local rgb2 = hex2rgb(col2) local rgb = {} for i, v in pairs(rgb1) do rgb[i] = rgb1[i]+(rgb2[i]-rgb1[i])*(pos/255) end return rgb_to_hex(rgb) end local function canTalk() if core.get_privilege_list then return core.get_privilege_list().shout else return true end end local function say(message) if not canTalk() then minetest.display_chat_message("You need 'shout' in order to talk") return end minetest.send_chat_message(message) if minetest.get_server_info().protocol_version < 29 then local name = minetest.localplayer:get_name() minetest.display_chat_message("<"..name.."> " .. message) end end function fade(parameter) local p = paramsplit(parameter) if not p then return end -- local col1 = string.sub(parameter, 1, 7) -- local col2 = string.sub(parameter, 9, 15) -- local message = string.sub(parameter, 17) local col1 = colourname2hex(p[1]) -- minetest.display_chat_message("col1.a: "..col1) -- minetest.display_chat_message("col1.b: "..core.get_color_escape_sequence(col1):sub(2,-1)) -- minetest.display_chat_message("col1.c: "..minetest.colorize(col1):sub(2,-1)) local col2 = colourname2hex(p[2]) -- minetest.display_chat_message("col2.a: "..p[2]) -- minetest.display_chat_message("col2.b: "..col2) local message = p[3] -- minetest.display_chat_message("msg: "..message) -- if true then return end if not canTalk() then return false, "You need 'shout' in order to use this command" end if col1 == col2 then -- minetest.display_chat_message("col1=col2") say(minetest.get_color_escape_sequence(col1) .. message) -- minetest.display_chat_message("col1=col2 b") return true end -- minetest.display_chat_message("pos4") local step = 255 / (message:len()/2) local pos = 0 local output = "" for i = 1, message:len() do local char = message:sub(i,i) if char:match("%s") then output = output .. char else output = output .. minetest.get_color_escape_sequence(color_step(pos, col1, col2)) .. char end pos = pos + step end say(output) return true end register_on_message(function(message) if message:sub(1,1) == "/" or modstorage:get_string("colour") == "" or modstorage:get_string("colour") == "white" then return false end fade(modstorage:get_string("colour") .. " " .. message) return true end) core.register_chatcommand("set_colour", { description = core.gettext("Change chat colour"), func = function(colour) local c = paramsplit(colour) if not c then local c1 = colourname2hex(colour) if c1 and c1 ~= "" then modstorage:set_string("colour", colour.." "..colour) return true, "Chat colour changed." else return true,"'"..colour.."' is not a colour" end end c1 = colourname2hex(c[1]) c2 = colourname2hex(c[3]) if not c1 or c1 == "" then return true,"'"..c[1].."' is not a colour" end if not c2 or c2 == "" then return true,"'"..c[2].."' is not a colour" end modstorage:set_string("colour", c1.." "..c2) return true, "Chat colours changed." end, }) core.register_chatcommand("get_colour", { description = core.gettext("Display chat colour"), func = function() local cc = modstorage:get_string("colour") return true, "Current chat colour: " .. cc end, }) core.register_chatcommand("rainbow", { description = core.gettext("rainbow text"), func = function(param) if not canTalk() then return false, "You need 'shout' in order to use this command" end local step = 360 / param:len() local hue = 0 -- iterate the whole 360 degrees local output = "" for i = 1, param:len() do local char = param:sub(i,i) if char:match("%s") then output = output .. char else output = output .. core.get_color_escape_sequence(colour_from_hue(hue)) .. char end hue = hue + step end say(output) return true end, }) core.register_chatcommand("fade", { -- added - fades between any two colors description = core.gettext("fade message between two colors"), func = fade, }) core.register_chatcommand("pastel", { description = core.gettext("pastel rainbow text"), func = function(param) if not canTalk() then return false, "You need 'shout' in order to use this command" end local step = 360 / param:len() local hue = 0 -- iterate the whole 360 degrees local output = "" for i = 1, param:len() do local char = param:sub(i,i) if char:match("%s") then output = output .. char else output = output .. core.get_color_escape_sequence(pastel_from_hue(hue)) .. char end hue = hue + step end say(output) return true end, }) core.register_chatcommand("mw", { description = core.gettext("moderator warning"), func = function(param) if not canTalk() then return false, "You need 'shout' in order to use this comand" end minetest.run_server_chatcommand('mw', param) -- local output = "" -- output = core.get_color_escape_sequence("#ffdf00") .. "MODERATOR WARNING: " -- output = output .. core.get_color_escape_sequence("#ff7fff") ..param -- say(output) return true end, }) core.register_chatcommand("mi", { description = core.gettext("moderator info"), func = function(param) if not canTalk() then return false, "You need 'shout' in order to use this command" end minetest.run_server_chatcommand('mi', param) -- local output = "" -- output = core.get_color_escape_sequence("#d0ff00") .. "MODERATOR INFO: " -- output = output .. core.get_color_escape_sequence("#dfdfff") .. param -- say(output) return true end, }) core.register_chatcommand("rainbow", { description = core.gettext("rainbow text"), func = function(param) if not canTalk() then return false, "You need 'shout' in order to use this command" end local step = 360 / param:len() local hue = 0 -- iterate the whole 360 degrees local output = "" for i = 1, param:len() do local char = param:sub(i,i) if char:match("%s") then output = output .. char else output = output .. core.get_color_escape_sequence(color_from_hue(hue)) .. char end hue = hue + step end say(output) return true end, }) core.register_chatcommand("say", { description = core.gettext("Send text without applying colour to it"), func = function(text) say(text) return true end, }) minetest.display_chat_message( "[CSM colour_chat] loaded")