forked from VoxeLibre/VoxeLibre
Compare commits
36 Commits
master
...
chat-comma
Author | SHA1 | Date |
---|---|---|
AFCMS | 073707f53c | |
AFCMS | d7ac1b7cb5 | |
AFCMS | d00a5c74d2 | |
AFCMS | f9a03a3c98 | |
AFCMS | 0c96ff672d | |
AFCMS | 46677a38ae | |
AFCMS | f8804c5e56 | |
AFCMS | 3137c86f67 | |
AFCMS | 2a28bf215d | |
AFCMS | 86f01eed75 | |
AFCMS | a51bbb6974 | |
AFCMS | 11384bd73c | |
AFCMS | 669a9ff0a4 | |
AFCMS | 783146f32e | |
AFCMS | 31e256e1e2 | |
AFCMS | 5f00d47ec2 | |
AFCMS | 0d3147b13d | |
AFCMS | a22188ccf4 | |
AFCMS | f90243f6e5 | |
AFCMS | 884097a8e5 | |
AFCMS | 72ddaf33f6 | |
AFCMS | 19e83fc2fb | |
AFCMS | 43c641f84f | |
AFCMS | 155548f384 | |
AFCMS | f7b832508f | |
AFCMS | 9e7ec24c0e | |
AFCMS | 5b5b525d32 | |
AFCMS | e334665365 | |
AFCMS | 88a971fe6f | |
AFCMS | 5425a01097 | |
AFCMS | 1f5076cfd0 | |
AFCMS | 7139ca1395 | |
AFCMS | 84de4ea728 | |
AFCMS | 59ab7e6ae6 | |
AFCMS | d5874b4062 | |
AFCMS | d72fa76757 |
|
@ -0,0 +1,74 @@
|
|||
# API documentation of mcl_commands
|
||||
|
||||
The mcl_commands API allows you to register and overide complex commands.
|
||||
This mod is derivated from ChatCommandBuilder by rubenwardy
|
||||
|
||||
Some public functions are not documented here but they are for internal use only.
|
||||
|
||||
## Technical differences from ChatCommandBuilder
|
||||
|
||||
* subcommand aditional specific privs
|
||||
* new types: `json`, `color`, `nodename` an maybe more in the future
|
||||
|
||||
|
||||
## Public Functions
|
||||
|
||||
### `mcl_commands.register_command("exemple", def)`
|
||||
|
||||
This is a function which is called when an item is dispensed by the dispenser.
|
||||
These are the parameters:
|
||||
|
||||
```
|
||||
mcl_commands.register_command("exemple", {
|
||||
func = function(cmd) --function executed on registration
|
||||
cmd:sub(":name:username title :params:json", { --create a new subcommand called "title" with defined patterns
|
||||
func = function(name, target, json)
|
||||
return a_cool_function(target, json) --function executed if the params match the patterns
|
||||
end,
|
||||
privs = {settime = true}, --subcommand aditional specific privs
|
||||
})
|
||||
end,
|
||||
description = "Controls text displayed on the screen.", --the description of the command
|
||||
params = "<target> command <params>", --very basic explaination of the syntax of the command (will be semi-automatic in the future)
|
||||
privs = {server = true}, --global privs
|
||||
})
|
||||
```
|
||||
|
||||
Register a complex chatcommand. If a chat command with the same name is already registered, the program will fail.
|
||||
|
||||
### `mcl_commands.overide_command("exemple", def)`
|
||||
|
||||
Same as above but will overide existing command.
|
||||
|
||||
### `mcl_commands.register_chatcommand_alias(alias, cmd, [bypass])`
|
||||
|
||||
Register an alias called `alias` of the `cmd` command.
|
||||
If the setting `mcl_builtin_commands_overide` is set to `false`, the function will silently fail.
|
||||
If `bypass` is set to `true` the function will not take care of the above setting.
|
||||
Will warn if trying to alias to already existing command.
|
||||
|
||||
### `mcl_commands.rename_chatcommand(newname, cmd, [bypass])`
|
||||
|
||||
Rename `cmd` command to `newname`.
|
||||
If the setting `mcl_builtin_commands_overide` is set to `false`, the function will silently fail.
|
||||
If `bypass` is set to `true` the function will not take care of the above setting.
|
||||
Will warn if trying to rename to already existing command.
|
||||
|
||||
### paterns
|
||||
|
||||
mcl_commands adds many types for patterns
|
||||
If not specified, a value will be by default with the word pattern.
|
||||
|
||||
* pos value must be pos
|
||||
* text value must be text WARNING: this pattern must be the last pattern of the subcommand!!
|
||||
* number value must be number
|
||||
* int value must be integer
|
||||
* word value must be word
|
||||
* alpha value must be alphanumeric
|
||||
* modname value must be a valid modname
|
||||
* alphascore
|
||||
* alphanumeric
|
||||
* username: value must be a valid username
|
||||
* json: value must be a json string (will be parsed automaticaly)
|
||||
* color value must be a color string or a valid named color
|
||||
* nodename value must be a valid (existing) node or item name
|
|
@ -0,0 +1,365 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
local mod_death_messages = minetest.get_modpath("mcl_death_messages")
|
||||
|
||||
local parse_json = minetest.parse_json
|
||||
local get_modpath = minetest.get_modpath
|
||||
|
||||
mcl_commands.types = {
|
||||
pos = {"%(? *(%-?[%d.]+) *,? *(%-?[%d.]+) *,? *(%-?[%d.]+) *%)?",
|
||||
function(res, pointer)
|
||||
local pos = {
|
||||
x = tonumber(res[pointer]),
|
||||
y = tonumber(res[pointer + 1]),
|
||||
z = tonumber(res[pointer + 2])
|
||||
}
|
||||
if pos.x and pos.y and pos.z then
|
||||
return nil, pos, pointer+3
|
||||
else
|
||||
return S("Pos is invalid!")
|
||||
end
|
||||
end},
|
||||
text = {"(.+)",
|
||||
function(res, pointer)
|
||||
if res[pointer] == tostring(res[pointer]) then
|
||||
return nil, res[pointer], pointer+1
|
||||
else
|
||||
return S("Text is invalid!")
|
||||
end
|
||||
end},
|
||||
number = {"(%-?[%d.]+)}",
|
||||
function(res, pointer)
|
||||
if res[pointer] == tonumber(res[pointer]) then
|
||||
return nil, tonumber(res[pointer]), pointer+1
|
||||
else
|
||||
return S("Number is invalid!")
|
||||
end
|
||||
end},
|
||||
int = {"(%-?[%d]+)}",
|
||||
function(res, pointer)
|
||||
if res[pointer] == math.floor(tonumber(res[pointer])) then
|
||||
return nil, tonumber(res[pointer]), pointer+1
|
||||
else
|
||||
return S("Int is invalid!")
|
||||
end
|
||||
end},
|
||||
word = {"([^ ]+)",
|
||||
function(res, pointer)
|
||||
if res[pointer] == tostring(res[pointer]) then
|
||||
return nil, tostring(res[pointer]), pointer+1
|
||||
else
|
||||
return S("Word is invalid!")
|
||||
end
|
||||
end},
|
||||
alpha = {"([A-Za-z]+)}",
|
||||
function(res, pointer)
|
||||
if res[pointer] then
|
||||
return nil, res[pointer], pointer+1
|
||||
else
|
||||
return S("Alpha is invalid!")
|
||||
end
|
||||
end},
|
||||
modname = {"([a-z0-9_]+)}",
|
||||
function(res, pointer)
|
||||
if get_modpath(res[pointer]) then
|
||||
return nil, res[pointer], pointer+1
|
||||
else
|
||||
return S("Modname is invalid!")
|
||||
end
|
||||
end},
|
||||
alphascore = {"([A-Za-z_]+)",
|
||||
function(res, pointer)
|
||||
if res[pointer] then --What is alphascore?
|
||||
return nil, res[pointer], pointer+1
|
||||
else
|
||||
return S("Alphascore is invalid!")
|
||||
end
|
||||
end},
|
||||
alphanumeric = {"([A-Za-z0-9]+)}",
|
||||
function(res, pointer)
|
||||
if res[pointer] then --What is alphanumerical?
|
||||
return nil, res[pointer], pointer+1
|
||||
else
|
||||
return S("Alphanumerical is invalid!")
|
||||
end
|
||||
end},
|
||||
username = {"([A-Za-z0-9-_]+)",
|
||||
function(res, pointer)
|
||||
--if minetest.player_exists(res[pointer]) then
|
||||
if res[pointer] then
|
||||
return nil, res[pointer], pointer+1
|
||||
else
|
||||
return S("Player doesn't exist.")
|
||||
end
|
||||
end},
|
||||
target = {"([A-Za-z0-9-_]+)",
|
||||
function(res, pointer)
|
||||
--if minetest.player_exists(res[pointer]) then
|
||||
if res[pointer] then
|
||||
return nil, res[pointer], pointer+1
|
||||
else
|
||||
return S("Player doesn't exist.")
|
||||
end
|
||||
end},
|
||||
json = {"(.+)", --FIXME
|
||||
function(res, pointer)
|
||||
local parsed = parse_json(res[pointer])
|
||||
if parsed then
|
||||
return nil, parsed, pointer+1
|
||||
else
|
||||
return S("Json failed to parse!")
|
||||
end
|
||||
end},
|
||||
color = {"([^ ]+)", --FIXME
|
||||
function(res, pointer)
|
||||
local color = mcl_util.get_color(res[pointer])
|
||||
if color then
|
||||
return nil, color, pointer+1
|
||||
else
|
||||
return S("Color is not a valid color name or hexadecimal!")
|
||||
end
|
||||
end},
|
||||
nodename = {"(%l+[%w_]+%:?[_%l]+[%w_]*)",
|
||||
function(res, pointer)
|
||||
if minetest.registered_items[res[pointer]] then
|
||||
return nil, res[pointer], pointer+1
|
||||
else
|
||||
return S("Nodename is invalid")
|
||||
end
|
||||
end},
|
||||
}
|
||||
|
||||
function mcl_commands.register_command(name, def)
|
||||
def = def or {}
|
||||
local cmd = mcl_commands.build(name, def)
|
||||
if minetest.registered_chatcommands[name] then
|
||||
error("[mcl_commands] Failed to register command: ["..name.."] command already existing! Use mcl_commands.overide_command() if you want to overide existing command")
|
||||
end
|
||||
minetest.register_chatcommand(name, cmd)
|
||||
minetest.log("action", "[mcl_commands] ["..name.."] command registered successfully")
|
||||
return cmd
|
||||
end
|
||||
|
||||
function mcl_commands.override_command(name, def)
|
||||
def = def or {}
|
||||
local cmd = mcl_commands.build(name, def)
|
||||
if minetest.registered_chatcommands[name] then
|
||||
minetest.unregister_chatcommand(name)
|
||||
end
|
||||
minetest.register_chatcommand(name, cmd)
|
||||
minetest.log("action", "[mcl_commands] ["..name.."] command overridden successfully")
|
||||
return cmd
|
||||
end
|
||||
|
||||
local STATE_READY = 1
|
||||
local STATE_PARAM = 2
|
||||
local STATE_PARAM_TYPE = 3
|
||||
local bad_chars = {"(", ")", ".", "%", "+", "-", "*", "?", "[", "^", "$"}
|
||||
local function escape(char)
|
||||
if bad_chars[char] then
|
||||
return "%" .. char
|
||||
else
|
||||
return char
|
||||
end
|
||||
end
|
||||
|
||||
local dprint = function() end
|
||||
|
||||
function mcl_commands.build(name, chat_def)
|
||||
local cmd = {
|
||||
_subs = {}
|
||||
}
|
||||
function cmd:sub(route, def)
|
||||
dprint("Parsing " .. route)
|
||||
|
||||
if string.trim then
|
||||
route = string.trim(route)
|
||||
end
|
||||
|
||||
local sub = {
|
||||
pattern = "^",
|
||||
params = {},
|
||||
func = def.func,
|
||||
privs = def.privs or {},
|
||||
desc = def.desc,
|
||||
params_desc = def.params or "",
|
||||
}
|
||||
|
||||
-- End of param reached: add it to the pattern
|
||||
local param = ""
|
||||
local param_type = ""
|
||||
local should_be_eos = false
|
||||
local function finishParam()
|
||||
if param ~= "" and param_type ~= "" then
|
||||
dprint(" - Found param " .. param .. " type " .. param_type)
|
||||
|
||||
local pattern = mcl_commands.types[param_type][1]
|
||||
if not pattern then
|
||||
error("Unrecognised param_type=" .. param_type)
|
||||
end
|
||||
|
||||
sub.pattern = sub.pattern .. pattern
|
||||
|
||||
table.insert(sub.params, param_type)
|
||||
|
||||
param = ""
|
||||
param_type = ""
|
||||
end
|
||||
end
|
||||
|
||||
-- Iterate through the route to find params
|
||||
local state = STATE_READY
|
||||
local catching_space = false
|
||||
local match_space = " " -- change to "%s" to also catch tabs and newlines
|
||||
local catch_space = match_space.."+"
|
||||
for i = 1, #route do
|
||||
local c = route:sub(i, i)
|
||||
if should_be_eos then
|
||||
error("Should be end of string. Nothing is allowed after a param of type text.")
|
||||
end
|
||||
|
||||
if state == STATE_READY then
|
||||
if c == ":" then
|
||||
dprint(" - Found :, entering param")
|
||||
state = STATE_PARAM
|
||||
param_type = "word"
|
||||
catching_space = false
|
||||
elseif c:match(match_space) then
|
||||
print(" - Found space")
|
||||
if not catching_space then
|
||||
catching_space = true
|
||||
sub.pattern = sub.pattern .. catch_space
|
||||
end
|
||||
else
|
||||
catching_space = false
|
||||
sub.pattern = sub.pattern .. escape(c)
|
||||
end
|
||||
elseif state == STATE_PARAM then
|
||||
if c == ":" then
|
||||
dprint(" - Found :, entering param type")
|
||||
state = STATE_PARAM_TYPE
|
||||
param_type = ""
|
||||
elseif c:match(match_space) then
|
||||
print(" - Found whitespace, leaving param")
|
||||
state = STATE_READY
|
||||
finishParam()
|
||||
catching_space = true
|
||||
sub.pattern = sub.pattern .. catch_space
|
||||
elseif c:match("%W") then
|
||||
dprint(" - Found nonalphanum, leaving param")
|
||||
state = STATE_READY
|
||||
finishParam()
|
||||
sub.pattern = sub.pattern .. escape(c)
|
||||
else
|
||||
param = param .. c
|
||||
end
|
||||
elseif state == STATE_PARAM_TYPE then
|
||||
if c:match(match_space) then
|
||||
print(" - Found space, leaving param type")
|
||||
state = STATE_READY
|
||||
finishParam()
|
||||
catching_space = true
|
||||
sub.pattern = sub.pattern .. catch_space
|
||||
elseif c:match("%W") then
|
||||
dprint(" - Found nonalphanum, leaving param type")
|
||||
state = STATE_READY
|
||||
finishParam()
|
||||
sub.pattern = sub.pattern .. escape(c)
|
||||
else
|
||||
param_type = param_type .. c
|
||||
end
|
||||
end
|
||||
end
|
||||
dprint(" - End of route")
|
||||
finishParam()
|
||||
sub.pattern = sub.pattern .. "$"
|
||||
dprint("Pattern: " .. sub.pattern)
|
||||
|
||||
table.insert(self._subs, sub)
|
||||
end
|
||||
|
||||
if chat_def.func then
|
||||
chat_def.func(cmd)
|
||||
end
|
||||
|
||||
cmd.func = function(name, param)
|
||||
local msg
|
||||
for i = 1, #cmd._subs do
|
||||
local sub = cmd._subs[i]
|
||||
local res = { string.match(param, sub.pattern) }
|
||||
if #res > 0 then
|
||||
local pointer = 1
|
||||
local params = { name }
|
||||
for j = 1, #sub.params do
|
||||
local param = sub.params[j]
|
||||
local value
|
||||
if mcl_commands.types[param] then
|
||||
msg, value, pointer = mcl_commands.check_type(param, res, pointer)
|
||||
table.insert(params, value)
|
||||
else
|
||||
table.insert(params, res[pointer])
|
||||
pointer = pointer + 1
|
||||
end
|
||||
end
|
||||
local can_execute, missing_privs = minetest.check_player_privs(name, sub.privs)
|
||||
if can_execute then
|
||||
if table.unpack then
|
||||
-- lua 5.2 or later
|
||||
return sub.func(table.unpack(params))
|
||||
else
|
||||
-- lua 5.1 or earlier
|
||||
return sub.func(unpack(params))
|
||||
end
|
||||
else
|
||||
local missing_privs_str = ""
|
||||
for i = 1, #missing_privs do
|
||||
if not i == #missing_privs then
|
||||
missing_privs_str = missing_privs_str..missing_privs[i].." "
|
||||
else
|
||||
missing_privs_str = missing_privs_str..missing_privs[i]
|
||||
end
|
||||
end
|
||||
return false, "You don't have permission to run this command (missing privilege: "..missing_privs_str..")"
|
||||
end
|
||||
end
|
||||
end
|
||||
return false, msg
|
||||
end
|
||||
if chat_def.params then
|
||||
cmd.params = chat_def.params
|
||||
else
|
||||
cmd.params = ""
|
||||
end
|
||||
cmd.privs = chat_def.privs
|
||||
cmd.description = chat_def.description
|
||||
return cmd
|
||||
end
|
||||
|
||||
function mcl_commands.check_type(type, res, pointer)
|
||||
return mcl_commands.types[type][2](res, pointer)
|
||||
end
|
||||
|
||||
function mcl_commands.register_chatcommand_alias(alias, cmd, bypass)
|
||||
if not bypass then bypass = false end
|
||||
if minetest.registered_chatcommands[alias] then
|
||||
minetest.log("warning", "[mcl_commands] trying to alias ["..cmd.."] to already existing ["..alias.."] command")
|
||||
elseif minetest.settings:get_bool("mcl_builtin_commands_overide", true) or bypass then
|
||||
minetest.register_chatcommand(alias, minetest.chatcommands[cmd])
|
||||
minetest.log("action", "[mcl_commands] ["..cmd.."] command aliased successfully to ["..alias.."]")
|
||||
else
|
||||
minetest.log("action", "[mcl_commands] ["..cmd.."] command not aliased to ["..alias.."]")
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_commands.rename_chatcommand(newname, cmd, bypass)
|
||||
if not bypass then bypass = false end
|
||||
if minetest.registered_chatcommands[newname] then
|
||||
minetest.log("warning", "[mcl_commands] trying to rename ["..cmd.."] to already existing ["..alias.."] command")
|
||||
elseif minetest.settings:get_bool("mcl_builtin_commands_overide", true) or bypass then
|
||||
minetest.register_chatcommand(newname, minetest.chatcommands[cmd])
|
||||
minetest.unregister_chatcommand(cmd)
|
||||
minetest.log("action", "[mcl_commands] ["..cmd.."] command renamed successfully to ["..newname.."]")
|
||||
else
|
||||
minetest.log("action", "[mcl_commands] ["..cmd.."] command not renamed to ["..newname.."]")
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
--mcl_commands
|
||||
--derivated from ChatCommandBuilder by @rubenwardy
|
||||
|
||||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
local mod_death_messages = minetest.get_modpath("mcl_death_messages")
|
||||
|
||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
mcl_commands = {}
|
||||
|
||||
dofile(modpath.."/api.lua")
|
||||
dofile(modpath.."/utils.lua")
|
|
@ -0,0 +1,6 @@
|
|||
name = mcl_commands
|
||||
author = AFCMS
|
||||
description = MCL2 commands API
|
||||
depends = mcl_colors, mcl_util
|
||||
optional_depends =
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
function mcl_commands.get_target_selector(target, pos, name)
|
||||
if minetest.player_exists(target) then
|
||||
return nil, minetest.get_player_by_name(target)
|
||||
elseif target == "@a" then
|
||||
return nil, minetest.get_connected_players()
|
||||
elseif target == "@r" then
|
||||
local connected = minetest.get_connected_players()
|
||||
return nil, connected[math.random(1, #connected)]
|
||||
elseif target == "@s" then
|
||||
if name then
|
||||
local player = minetest.get_player_by_name(name)
|
||||
end
|
||||
if player then
|
||||
return nil, player
|
||||
else
|
||||
return S("Not a valid player")
|
||||
end
|
||||
elseif target == "@p" then
|
||||
local smallest = math.huge
|
||||
local nearest
|
||||
for _,player in pairs(minetest.get_connected_players()) do
|
||||
local distance = vector.distance(pos, player:get_pos())
|
||||
if distance < min_distance then
|
||||
min_distance = distance
|
||||
nearest = player
|
||||
end
|
||||
end
|
||||
if nearest then
|
||||
return nil, nearest
|
||||
else
|
||||
return S("No player online")
|
||||
end
|
||||
elseif target == "@e" then
|
||||
return minetest.luaentities --TODO: add filtering of not valid entities.
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
mcl_util.registered_blacklisted_entities = {}
|
||||
function mcl_util.register_blacklisted_entities(type)
|
||||
mcl_util.registered_blacklisted_entities[type] = true
|
||||
end
|
||||
function mcl_util.get_real_entities()
|
||||
for key, val in pairs(minetest.luaentities) do
|
||||
local def = minetest.registered_entities[minetest.luaentities[key].name]
|
||||
if not mcl_util.registered_blacklisted_entities[def.type] then
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,3 +1,5 @@
|
|||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
mcl_util = {}
|
||||
|
||||
-- Based on minetest.rotate_and_place
|
||||
|
@ -418,3 +420,5 @@ function mcl_util.get_color(colorstr)
|
|||
return colorstr, hex
|
||||
end
|
||||
end
|
||||
|
||||
dofile(modpath.."/entities.lua")
|
|
@ -0,0 +1,23 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
mcl_commands.register_chatcommand_alias("?", "help", false)
|
||||
mcl_commands.register_chatcommand_alias("pardon", "unban", false)
|
||||
mcl_commands.rename_chatcommand("stop", "shutdown", false)
|
||||
mcl_commands.register_chatcommand_alias("tell", "msg", false)
|
||||
mcl_commands.register_chatcommand_alias("w", "msg", false)
|
||||
mcl_commands.register_chatcommand_alias("tp", "teleport", false)
|
||||
mcl_commands.rename_chatcommand("clear", "clearinv", false)
|
||||
|
||||
mcl_commands.register_command("banlist", {
|
||||
func = function(cmd)
|
||||
cmd:sub("", {
|
||||
func = function(name)
|
||||
return true, S("Ban list: @1", minetest.get_ban_list())
|
||||
end,
|
||||
privs = {},
|
||||
})
|
||||
end,
|
||||
description = S("List bans"),
|
||||
params = "",
|
||||
privs = minetest.chatcommands["ban"].privs,
|
||||
})
|
|
@ -1,6 +1,4 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
local mod_death_messages = minetest.get_modpath("mcl_death_messages")
|
||||
--Basic commands for mcl2
|
||||
|
||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
|
@ -11,5 +9,6 @@ dofile(modpath.."/summon.lua")
|
|||
dofile(modpath.."/say.lua")
|
||||
dofile(modpath.."/list.lua")
|
||||
dofile(modpath.."/sound.lua")
|
||||
dofile(modpath.."/title.lua")
|
||||
|
||||
dofile(modpath.."/alias.lua")
|
|
@ -41,19 +41,20 @@ local function handle_kill_command(suspect, victim)
|
|||
return true
|
||||
end
|
||||
|
||||
if minetest.registered_chatcommands["kill"] then
|
||||
minetest.unregister_chatcommand("kill")
|
||||
end
|
||||
minetest.register_chatcommand("kill", {
|
||||
params = S("[<name>]"),
|
||||
description = S("Kill player or yourself"),
|
||||
privs = {server=true},
|
||||
func = function(name, param)
|
||||
if(param == "") then
|
||||
-- Selfkill
|
||||
return handle_kill_command(name, name)
|
||||
else
|
||||
return handle_kill_command(name, param)
|
||||
end
|
||||
mcl_commands.override_command("kill", {
|
||||
func = function(cmd)
|
||||
cmd:sub("", {
|
||||
func = function(name)
|
||||
return handle_kill_command(name, name)
|
||||
end,
|
||||
})
|
||||
cmd:sub(":target:username", {
|
||||
func = function(name, target)
|
||||
return handle_kill_command(name, target)
|
||||
end,
|
||||
})
|
||||
end,
|
||||
description = "Kill player or yourself.",
|
||||
params = S("[<target>]"),
|
||||
privs = {server = true},
|
||||
})
|
|
@ -0,0 +1,19 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
mcl_commands.register_command("list", {
|
||||
func = function(cmd)
|
||||
cmd:sub("", {
|
||||
func = function(name)
|
||||
local players = ""
|
||||
for _, player in ipairs(minetest.get_connected_players()) do
|
||||
players = players..player:get_player_name().."\n"
|
||||
end
|
||||
return true, players
|
||||
end,
|
||||
privs = {},
|
||||
})
|
||||
end,
|
||||
description = S("Show who is logged on"),
|
||||
params = "",
|
||||
privs = {},
|
||||
})
|
|
@ -0,0 +1,23 @@
|
|||
# textdomain: mcl_commands
|
||||
Players can't be killed right now, damage has been disabled.=Spieler können jetzt nicht getötet werden, der Schaden wurde deaktiviert.
|
||||
Player @1 does not exist.=Spieler @1 existiert nicht.
|
||||
You are already dead=Sie sind schon tot
|
||||
@1 is already dead=@1 ist schon tot
|
||||
@1 committed suicide.=@1 beging Selbstmord.
|
||||
@1 was killed by @2.=@1 wurde von @2 getötet.
|
||||
[<name>]=[<Name>]
|
||||
Kill player or yourself=Spieler oder sich selbst töten
|
||||
Can use /say=Kann „/say“ benutzen
|
||||
<message>=<Nachricht>
|
||||
Send a message to every player=Nachricht an alle Spieler senden
|
||||
Invalid usage, see /help say.=Falsche Benutzung, siehe „/help say“.
|
||||
<X>,<Y>,<Z> <NodeString>=<X>,<Y>,<Z> <Node-Bezeichner>
|
||||
Set node at given position=Node (Block) an der gegebenen Position platzieren
|
||||
Invalid node=Unültiger Node
|
||||
@1 spawned.=@1 gespawnt.
|
||||
Invalid parameters (see /help setblock)=Ungültige Parameter (siehe „/help setblock”)
|
||||
List bans=Bannliste anzeigen
|
||||
Ban list: @1=Bannliste: @1
|
||||
Show who is logged on=Anzeigen, wer eingeloggt ist
|
||||
Displays the world seed=Den Seed der Welt anzeigen
|
||||
Only peaceful mobs allowed!=Nur friedliche Mobs erlaubt!
|
|
@ -0,0 +1,23 @@
|
|||
# textdomain: mcl_commands
|
||||
Players can't be killed right now, damage has been disabled.=Los jugadores no pueden ser asesinados en este momento, el daño ha sido desactivado.
|
||||
Player @1 does not exist.=El jugador @1 no existe.
|
||||
You are already dead=Ya estas muerto
|
||||
@1 is already dead=@1 ya esta muerto
|
||||
@1 committed suicide.=@1 se suicidó.
|
||||
@1 was killed by @2.=@1 fue asesinado por @2.
|
||||
[<name>]=[<Nombre>]
|
||||
Kill player or yourself=Mata al jugador o a ti mismo
|
||||
Can use /say=Puedes usar /say
|
||||
<message>=<Mensaje>
|
||||
Send a message to every player=Envía un mensaje a todos los jugadores
|
||||
Invalid usage, see /help=Uso no válido, (Revisa el comando "/help say")
|
||||
<X>,<Y>,<Z> <NodeString>=<X>,<Y>,<Z> <ID nodo>
|
||||
Set node at given position=Establecer nodo en la posición dada
|
||||
Invalid node=Nodo no válido
|
||||
@1 spawned.=@1 generado.
|
||||
Invalid parameters (see /help setblock)=Parámetros no válidos (Revisa el comando "/help setblock")
|
||||
List bans=Lista de prohibiciones
|
||||
Ban list: @1=Lista de baneados: @1
|
||||
Show who is logged on=Mostrar quién ha iniciado sesión
|
||||
Displays the world seed=Muestra la semilla del mundo
|
||||
Only peaceful mobs allowed!=¡Solo se permiten animales pacíficos!
|
|
@ -0,0 +1,23 @@
|
|||
# textdomain: mcl_commands
|
||||
Players can't be killed right now, damage has been disabled.=Les joueurs ne peuvent pas être tués pour le moment, les dégâts ont été désactivés.
|
||||
Player @1 does not exist.=Le joueur @1 n'existe pas.
|
||||
You are already dead=Tu es déjà mort
|
||||
@1 is already dead=@1 est déjà mort
|
||||
@1 committed suicide.=@1 s'est suicidé.
|
||||
@1 was killed by @2.=@1 a été tué par @2.
|
||||
[<name>]=[<nom>]
|
||||
Kill player or yourself=Tuez un joueur ou vous-même
|
||||
Can use /say=Peut utiliser /say
|
||||
<message>=<message>
|
||||
Send a message to every player=Envoyez un message à chaque joueur
|
||||
Invalid usage, see /help say.=Utilisation non valide, voir /help say.
|
||||
<X>,<Y>,<Z> <NodeString>=<X>,<Y>,<Z> <NodeString>
|
||||
Set node at given position=Placer le noeud à une position donnée
|
||||
Invalid node=Noeud non valide
|
||||
@1 spawned.=@1 est apparu.
|
||||
Invalid parameters (see /help setblock)=Paramètres invalides (voir /help setblock)
|
||||
List bans=Liste des interdictions
|
||||
Ban list: @1=Liste d'interdiction: @1
|
||||
Show who is logged on=Afficher qui est connecté
|
||||
Displays the world seed=Affiche la graine du monde
|
||||
Only peaceful mobs allowed!=Seuls les mobs pacifiques sont autorisées!
|
|
@ -0,0 +1,23 @@
|
|||
# textdomain: mcl_commands
|
||||
Players can't be killed right now, damage has been disabled.=Игроки не могут быть убиты прямо сейчас, урон отключён.
|
||||
Player @1 does not exist.=Игрок @1 не существует.
|
||||
You are already dead=Вы уже мертвы
|
||||
@1 is already dead=@1 уже мертв(а)
|
||||
@1 committed suicide.=@1 совершил(а) роскомнадзор.
|
||||
@1 was killed by @2.=@1 был(а) убит(а) @2.
|
||||
[<name>]=[<имя>]
|
||||
Kill player or yourself=Убить игрока или себя
|
||||
Can use /say=Можно использовать /say
|
||||
<message>=<сообщение>
|
||||
Send a message to every player=Отправляет сообщение всем игрокам
|
||||
Invalid usage, see /help say.=Недопустимое использование, см. /help say.
|
||||
<X>,<Y>,<Z> <NodeString>=<X>,<Y>,<Z> <СтрокаУзла>
|
||||
Set node at given position=Устанавливает узел в заданной позиции
|
||||
Invalid node=Неправильный узел
|
||||
@1 spawned.=@1 возродился(ась).
|
||||
Invalid parameters (see /help setblock)=Недопустимые параметры (см. /help setblock)
|
||||
List bans=Список банов
|
||||
Ban list: @1=Бан-лист: @1
|
||||
Show who is logged on=Показывает, кто подключён
|
||||
Displays the world seed=Показывает значение зерна мира (seed)
|
||||
Only peaceful mobs allowed!=Включены только мирные мобы!
|
|
@ -0,0 +1,23 @@
|
|||
# textdomain: mcl_commands
|
||||
Players can't be killed right now, damage has been disabled.=
|
||||
Player @1 does not exist.=
|
||||
You are already dead=
|
||||
@1 is already dead=
|
||||
@1 committed suicide.=
|
||||
@1 was killed by @2.=
|
||||
[<name>]=
|
||||
Kill player or yourself=
|
||||
Can use /say=
|
||||
<message>=
|
||||
Send a message to every player=
|
||||
Invalid usage, see /help say.=
|
||||
<X>,<Y>,<Z> <NodeString>=
|
||||
Set node at given position=
|
||||
Invalid node=
|
||||
@1 spawned.=
|
||||
Invalid parameters (see /help setblock)=
|
||||
List bans=
|
||||
Ban list: @1=
|
||||
Show who is logged on=
|
||||
Displays the world seed=
|
||||
Only peaceful mobs allowed!=
|
|
@ -0,0 +1,3 @@
|
|||
name=mcl_basic_commands
|
||||
depends=mcl_commands
|
||||
optional_depends=mcl_death_message
|
|
@ -0,0 +1,19 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
minetest.register_privilege("announce", {
|
||||
description = S("Can use /say"),
|
||||
give_to_singleplayer = false,
|
||||
})
|
||||
|
||||
mcl_commands.register_command("say", {
|
||||
func = function(cmd)
|
||||
cmd:sub(":message:text", {
|
||||
func = function(name, message)
|
||||
minetest.chat_send_all(("["..name.."] "..message))
|
||||
return true
|
||||
end})
|
||||
end,
|
||||
description = S("Send a message to every player"),
|
||||
params = S("<message>"),
|
||||
privs = {announce = true},
|
||||
})
|
|
@ -0,0 +1,15 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
mcl_commands.register_command("seed", {
|
||||
func = function(cmd)
|
||||
cmd:sub("", {
|
||||
func = function(name)
|
||||
return true, "Seed: "..minetest.get_mapgen_setting("seed")
|
||||
end,
|
||||
privs = {},
|
||||
})
|
||||
end,
|
||||
description = S("Displays the world seed"),
|
||||
params = "",
|
||||
privs = {},
|
||||
})
|
|
@ -0,0 +1,35 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
mcl_commands.register_command("setblock", {
|
||||
func = function(cmd)
|
||||
cmd:sub(":pos:pos :node:nodename", {
|
||||
func = function(name, pos, node)
|
||||
minetest.set_node(pos, {name=node})
|
||||
return true, S("@1 spawned.", node)
|
||||
--return false, S("Invalid parameters (see /help setblock)")
|
||||
end,
|
||||
privs = {},
|
||||
})
|
||||
end,
|
||||
description = S("Set node at given position"),
|
||||
params = S("<X>,<Y>,<Z> <NodeString>"),
|
||||
privs = {give=true, interact=true},
|
||||
})
|
||||
|
||||
|
||||
--DEBUG: must be removed later
|
||||
mcl_commands.register_command("setdebug", {
|
||||
func = function(cmd)
|
||||
cmd:sub(":node:nodename", {
|
||||
func = function(name, node)
|
||||
minetest.set_node({x=0,y=0,z=0}, {name=node})
|
||||
return true, S("@1 spawned.", node)
|
||||
--return false, S("Invalid parameters (see /help setblock)")
|
||||
end,
|
||||
privs = {},
|
||||
})
|
||||
end,
|
||||
description = S("Set node at given position"),
|
||||
params = S("<X>,<Y>,<Z> <NodeString>"),
|
||||
privs = {give=true, interact=true},
|
||||
})
|
|
@ -0,0 +1,19 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
mcl_commands.register_command("playsound", {
|
||||
func = function(cmd)
|
||||
cmd:sub(":sound:word :target:username", { --TODO:replace by upcomming types
|
||||
func = function(name, sound, target)
|
||||
if minetest.player_exists(target) then
|
||||
minetest.sound_play({name = sound}, {to_player = target}, true) --TODO:add source, gain, pitch
|
||||
else
|
||||
return false, S("Target is invalid!!") --TODO: add mc chat message
|
||||
end
|
||||
end,
|
||||
privs = {},
|
||||
})
|
||||
end,
|
||||
description = S("Play a sound. Arguments: <sound>: name of the sound. <target>: Target."),
|
||||
params = S("<sound> <target>"),
|
||||
privs = {server = true},
|
||||
})
|
|
@ -0,0 +1,142 @@
|
|||
local C = minetest.colorize
|
||||
local has_mcl_colors = minetest.get_modpath("mcl_colors")
|
||||
|
||||
local huds_idx = {}
|
||||
huds_idx.title = {}
|
||||
huds_idx.subtitle = {}
|
||||
huds_idx.actionbar = {}
|
||||
|
||||
mcl_title = {}
|
||||
mcl_title.defaults = {fadein = 10, stay = 70, fadeout = 20}
|
||||
mcl_title.layout = {}
|
||||
mcl_title.layout.title = {position = {x = 0.5, y = 0.5}, alignment = {x = 0, y = -1.3}, size = 5}
|
||||
mcl_title.layout.subtitle = {position = {x = 0.5, y = 0.5}, alignment = {x = 0, y = 1.3}, size = 2}
|
||||
mcl_title.layout.actionbar = {position = {x = 0.5, y = 1}, alignment = {x = 0, y = -10}, size = 1}
|
||||
|
||||
local function gametick_to_secondes(gametick)
|
||||
return gametick / 20
|
||||
end
|
||||
|
||||
function mcl_title.set(playername, type, data)
|
||||
if not data.color then
|
||||
data.color = "white"
|
||||
end
|
||||
local _, hex_color = mcl_util.get_color(data.color)
|
||||
if not hex_color then
|
||||
return false, "Invalid color: " .. data.color
|
||||
end
|
||||
local player = minetest.get_player_by_name(playername)
|
||||
if player and data then
|
||||
if huds_idx[type][playername] then
|
||||
player:hud_remove(huds_idx[type][playername])
|
||||
end
|
||||
local stay = player:get_meta():get_int("mcl_title:stay") or 3
|
||||
huds_idx[type][playername] = player:hud_add({
|
||||
hud_elem_type = "text",
|
||||
position = mcl_title.layout[type].position,
|
||||
alignment = mcl_title.layout[type].alignment,
|
||||
text = data.text,
|
||||
size = {x = mcl_title.layout[type].size},
|
||||
number = hex_color,
|
||||
z_index = 1100
|
||||
})
|
||||
minetest.after(stay, function()
|
||||
if huds_idx[type][playername] then
|
||||
player:hud_remove(huds_idx[type][playername])
|
||||
end
|
||||
huds_idx[type][playername] = nil
|
||||
end)
|
||||
return true, "Title command executed successfuly"
|
||||
else
|
||||
return false, "Player doesn't exist or json failed to parse"
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_title.remove(playername, type)
|
||||
local player = minetest.get_player_by_name(playername)
|
||||
if player then
|
||||
if huds_idx[type][playername] then
|
||||
player:hud_remove(huds_idx[type][playername])
|
||||
end
|
||||
end
|
||||
huds_idx[type][playername] = nil
|
||||
return true
|
||||
end
|
||||
|
||||
function mcl_title.times(playername, stay)
|
||||
local player = minetest.get_player_by_name(playername)
|
||||
if player then
|
||||
local meta = player:get_meta()
|
||||
--meta:set_int("mcl_title:fadeIn", gametick_to_secondes(fadein))
|
||||
meta:set_int("mcl_title:stay", gametick_to_secondes(stay))
|
||||
--meta:set_int("mcl_title:fadeOut", gametick_to_secondes(fadeout))
|
||||
return true
|
||||
else
|
||||
return false, "Player doesn't exist"
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_newplayer(function(player)
|
||||
local meta = player:get_meta()
|
||||
--meta:set_int("mcl_title:fadeIn", gametick_to_secondes(mcl_title.defaults.fadein))
|
||||
meta:set_int("mcl_title:stay", gametick_to_secondes(mcl_title.defaults.stay))
|
||||
--meta:set_int("mcl_title:fadeOut", gametick_to_secondes(mcl_title.defaults.fadeout))
|
||||
end)
|
||||
|
||||
function mcl_title.clear(playername)
|
||||
mcl_title.remove(playername, "title")
|
||||
mcl_title.remove(playername, "subtitle")
|
||||
mcl_title.remove(playername, "actionbar")
|
||||
return true
|
||||
end
|
||||
|
||||
function mcl_title.reset(playername)
|
||||
local player = minetest.get_player_by_name(playername)
|
||||
if player then
|
||||
local meta = player:get_meta()
|
||||
--meta:set_int("mcl_title:fadeIn", gametick_to_secondes(mcl_title.defaults.fadein))
|
||||
meta:set_int("mcl_title:stay", gametick_to_secondes(mcl_title.defaults.stay))
|
||||
--meta:set_int("mcl_title:fadeOut", gametick_to_secondes(mcl_title.defaults.fadeout))
|
||||
return true
|
||||
else
|
||||
return false, "Player not found!"
|
||||
end
|
||||
end
|
||||
|
||||
mcl_commands.register_command("title", {
|
||||
func = function(cmd)
|
||||
cmd:sub(":name:username title :params:json", {
|
||||
func = function(name, target, json)
|
||||
return mcl_title.set(target, "title", json)
|
||||
end,
|
||||
})
|
||||
cmd:sub(":name:username subtitle :params:json", {
|
||||
func = function(name, target, json)
|
||||
return mcl_title.set(target, "subtitle", json)
|
||||
end,
|
||||
})
|
||||
cmd:sub(":name:username actionbar :params:json", {
|
||||
func = function(name, target, json)
|
||||
return mcl_title.set(target, "actionbar", json)
|
||||
end,
|
||||
})
|
||||
cmd:sub(":name:username times :stay:int", {
|
||||
func = function(name, target, stay)
|
||||
return mcl_title.times(target, stay)
|
||||
end,
|
||||
})
|
||||
cmd:sub(":name:username clear", {
|
||||
func = function(name, target)
|
||||
return mcl_title.clear(target)
|
||||
end,
|
||||
})
|
||||
cmd:sub(":name:username reset", {
|
||||
func = function(name, target)
|
||||
return mcl_title.reset(target)
|
||||
end,
|
||||
})
|
||||
end,
|
||||
description = "Controls text displayed on the screen.",
|
||||
params = "<target> command <params>",
|
||||
privs = {server = true},
|
||||
})
|
|
@ -1,30 +0,0 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
local function register_chatcommand_alias(alias, cmd)
|
||||
local def = minetest.chatcommands[cmd]
|
||||
minetest.register_chatcommand(alias, def)
|
||||
end
|
||||
|
||||
local function rename_chatcommand(newname, cmd)
|
||||
local def = minetest.chatcommands[cmd]
|
||||
minetest.register_chatcommand(newname, def)
|
||||
minetest.unregister_chatcommand(cmd)
|
||||
end
|
||||
|
||||
if minetest.settings:get_bool("mcl_builtin_commands_overide", true) then
|
||||
register_chatcommand_alias("?", "help")
|
||||
register_chatcommand_alias("pardon", "unban")
|
||||
rename_chatcommand("stop", "shutdown")
|
||||
register_chatcommand_alias("tell", "msg")
|
||||
register_chatcommand_alias("w", "msg")
|
||||
register_chatcommand_alias("tp", "teleport")
|
||||
rename_chatcommand("clear", "clearinv")
|
||||
|
||||
minetest.register_chatcommand("banlist", {
|
||||
description = S("List bans"),
|
||||
privs = minetest.chatcommands["ban"].privs,
|
||||
func = function(name)
|
||||
return true, S("Ban list: @1", minetest.get_ban_list())
|
||||
end,
|
||||
})
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
minetest.register_chatcommand("list", {
|
||||
description = S("Show who is logged on"),
|
||||
params = "",
|
||||
privs = {},
|
||||
func = function(name)
|
||||
local players = ""
|
||||
for _, player in ipairs(minetest.get_connected_players()) do
|
||||
players = players..player:get_player_name().."\n"
|
||||
end
|
||||
minetest.chat_send_player(name, players)
|
||||
end
|
||||
})
|
|
@ -1,4 +0,0 @@
|
|||
name = mcl_commands
|
||||
author = Wuzzy
|
||||
description = MCL2 commands
|
||||
optional_depends = mcl_death_messages
|
|
@ -1,18 +0,0 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
minetest.register_privilege("announce", {
|
||||
description = S("Can use /say"),
|
||||
give_to_singleplayer = false,
|
||||
})
|
||||
minetest.register_chatcommand("say", {
|
||||
params = S("<message>"),
|
||||
description = S("Send a message to every player"),
|
||||
privs = {announce=true},
|
||||
func = function(name, param)
|
||||
if not param then
|
||||
return false, S("Invalid usage, see /help say.")
|
||||
end
|
||||
minetest.chat_send_all(("["..name.."] "..param))
|
||||
return true
|
||||
end,
|
||||
})
|
|
@ -1,10 +0,0 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
minetest.register_chatcommand("seed", {
|
||||
description = S("Displays the world seed"),
|
||||
params = "",
|
||||
privs = {},
|
||||
func = function(name)
|
||||
minetest.chat_send_player(name, "Seed: "..minetest.get_mapgen_setting("seed"))
|
||||
end
|
||||
})
|
|
@ -1,22 +0,0 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
minetest.register_chatcommand("setblock", {
|
||||
params = S("<X>,<Y>,<Z> <NodeString>"),
|
||||
description = S("Set node at given position"),
|
||||
privs = {give=true, interact=true},
|
||||
func = function(name, param)
|
||||
local p = {}
|
||||
local nodestring = nil
|
||||
p.x, p.y, p.z, nodestring = param:match("^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+) +(.+)$")
|
||||
p.x, p.y, p.z = tonumber(p.x), tonumber(p.y), tonumber(p.z)
|
||||
if p.x and p.y and p.z and nodestring then
|
||||
local itemstack = ItemStack(nodestring)
|
||||
if itemstack:is_empty() or not minetest.registered_nodes[itemstack:get_name()] then
|
||||
return false, S("Invalid node")
|
||||
end
|
||||
minetest.set_node(p, {name=nodestring})
|
||||
return true, S("@1 spawned.", nodestring)
|
||||
end
|
||||
return false, S("Invalid parameters (see /help setblock)")
|
||||
end,
|
||||
})
|
|
@ -1,48 +0,0 @@
|
|||
local S = minetest.get_translator("mcl_commands")
|
||||
|
||||
minetest.register_chatcommand("playsound",{
|
||||
params = S("<sound> <target>"), --TODO:add source
|
||||
description = S("Play a sound. Arguments: <sound>: name of the sound. <target>: Target."),
|
||||
privs = {server = true},
|
||||
func = function(name, params)
|
||||
local P = {}
|
||||
local i = 0
|
||||
for str in string.gmatch(params, "([^ ]+)") do
|
||||
i = i + 1
|
||||
P[i] = str
|
||||
end
|
||||
|
||||
local params = {}
|
||||
if P[1] == tostring(P[1]) then
|
||||
params.name = P[1]
|
||||
else
|
||||
return false, S("Sound name is invalid!") --TODO: add mc chat message
|
||||
end
|
||||
|
||||
if P[2] == tostring(P[2]) and minetest.player_exists(P[2]) then
|
||||
params.target = P[2]
|
||||
else
|
||||
return false, S("Target is invalid!!")
|
||||
end
|
||||
|
||||
-- if P[3] then
|
||||
-- params.pos = nil --TODO:position
|
||||
-- else
|
||||
-- params.pos = nil
|
||||
-- end
|
||||
|
||||
-- if P[4] == tonumber(P[4]) then
|
||||
-- params.gain = P[4]
|
||||
-- else
|
||||
-- params.gain = 1.0
|
||||
-- end
|
||||
|
||||
-- if P[5] == tonumber(P[5]) then
|
||||
-- params.pitch = P[5]
|
||||
-- else
|
||||
-- params.pitch = 1.0
|
||||
-- end
|
||||
minetest.sound_play({name = params.name}, {to_player = params.target}, true) --TODO: /stopsound
|
||||
return true
|
||||
end,
|
||||
})
|
Loading…
Reference in New Issue