people/commands.lua

454 lines
15 KiB
Lua

local dbg
if moddebug then dbg=moddebug.dbg("people") else dbg={v1=function() end,v2=function() end,v3=function() end} end
--- Get a person name from the next argument
-- @return The person name, the actual person, and the rest of the
-- arguments. If the person name is nil, the arguments are invalid.
-- If person is nil, the name is valid, but it's not a person that
-- actually exists.
local get_person = function(args)
if not args then return nil, nil, nil end
local person_name
person_name, args = string.match(args, "^([^ ]+)(.*)")
if person_name and not people.is_valid_name(person_name) then
return nil, nil, nil
end
local person
if person_name then person = people.people[person_name] end
if args then args = string.sub(args, 2) end
return person_name, person, args
end
-- All chat commands are defined by simply adding the handler function to
-- this table. The handler receives the name of the player and the command
-- arguments, and it should return:
-- 1. success status (true or false)
-- 2. reply message (or nil)
-- 3. optionally, true to queue the command and wake the entity, which
-- it should only do if the enitity is inactive. In this case, the
-- other two return values are ignored. The command will execute
-- again when the entitiy is reactivated.
local subcmd = {}
subcmd.help = {
params = "[<subcmd>]",
desc = "You're being silly, aren't you?",
exec = function(playername, args)
if args and args ~= "" then
if not subcmd[args] then
return false, "No such subcommand"
end
return true, "/people "..args.." "..subcmd[args].params.." - "..
subcmd[args].desc
end
local msg = "Subcommands (use /people help <subcmd> for more):"
for c, _ in pairs(subcmd) do
msg = msg.." "..c
end
return true, msg
end
}
subcmd.reload_presets = {
params = "none",
desc = "Reload the presets from disk",
exec = function(playername, args)
if not minetest.check_player_privs(playername, {server=true}) then
return false, "Only admins can reload presets"
end
people.load_presets()
return true, "Reloaded presets"
end
}
subcmd.create = {
params = "<name>",
desc = "Create a person with the given name at your current location",
exec = function(playername, args)
if not minetest.check_player_privs(playername, {server=true}) then
return false, "Only admins can create people"
end
local person, person_name
person_name, person, args = get_person(args)
if not person_name then
return false, "Name needs to be specified"
end
if person then
return false, "Person "..person_name.." already exists"
end
local player = minetest.get_player_by_name(playername)
if not player then
return false, "people create can only be used by a player"
end
local pos = player:getpos()
local err = people.create(pos, person_name, playername)
if err then return false, err end
return true, "Created "..person_name
end
}
subcmd.forget = {
params = "<name>",
desc = "Completely forget the person with the given name. If activated, they will be deleted.",
exec = function(playername, args)
local person, person_name
person_name, person, args = get_person(args)
if not person then
return false, "Specify a valid person"
end
if not minetest.check_player_privs(playername, {server=true}) then
if playername ~= ent.owner then
return false, person_name.." isn't yours, so so can't do that"
end
end
local ent = people.people[person_name].entity
if ent then
ent.object:remove()
end
people.people[person_name] = nil
return true, "Forgot "..person_name
end
}
subcmd.delete = {
params = "<name>",
desc = "Delete the person with the given name",
exec = function(playername, args)
local person, person_name
person_name, person, args = get_person(args)
if not person then
return false, "Specify a valid person"
end
local ent = people.people[person_name].entity
if not ent then
return false, nil, true
end
if not minetest.check_player_privs(playername, {server=true}) then
if playername ~= ent.owner then
return false, person_name.." isn't yours, so so can't do that"
end
end
ent.object:remove()
people.people[person_name] = nil
return true, "Deleted "..person_name
end
}
subcmd.summon = {
params = "<name>",
desc = "Move the person with the given name to your current location",
exec = function(playername, args)
local person, person_name
person_name, person, args = get_person(args)
if not person then
return false, "Specify a valid person"
end
local player = minetest.get_player_by_name(playername)
if not player then
return false, "people summon can only be used by a player"
end
local pos = player:getpos()
local ent = people.people[person_name].entity
if not ent then
return false, nil, true
end
ent.object:setpos(pos)
return true, "Summoned "..person_name
end
}
subcmd.where = {
params = "<name>",
desc = "Report the location and status of the person with the given name",
exec = function(playername, args)
local person, person_name
person_name, person, args = get_person(args)
if not person then
return false, "Specify a valid person"
end
local ent = people.people[person_name].entity
if not ent then
return true, person_name.." is inactive at "..minetest.pos_to_string(people.people[person_name].pos)
end
return true, person_name.." is at "..minetest.pos_to_string(ent.object:getpos())
end
}
subcmd.attach = {
params = "[<name>]",
desc = "Attach to a person (or remove, with no parameter)",
exec = function(playername, args)
if not minetest.check_player_privs(playername, {server=true}) then
return false, "Only admins can attach to people"
end
local function removecur(playername)
if not people.attach_by_player[playername] then return end
local player = minetest.get_player_by_name(playername)
player:set_detach()
end
local person, person_name
person_name, person, args = get_person(args)
if not person then
if args then
return false, "No such person as "..person_name
end
if not people.attach_by_player[playername] then
return false, "Not attached to a person"
end
removecur(playername)
local n = people.attach_by_player[playername].name
people.attach_by_player[playername] = nil
return true, "Detached from "..n
end
removecur(playername)
people.attach_by_player[playername] = {name=person_name}
local player = minetest.get_player_by_name(playername)
local ent = person.entity
if not ent then
return false, nil, true
end
player:set_attach(ent.object, "", {x=0,y=1,z=0}, {x=0,y=0,z=0})
return true, "Attached to "..person_name
end
}
subcmd.track = {
params = "[<name>]",
desc = "Track a person on the HUD (or remove, with no parameter)",
exec = function(playername, args)
local function removecur(playername)
if not people.hud_show_by_player[playername] then return end
local hudid = people.hud_show_by_player[playername].hudid
if hudid then
local player = minetest.get_player_by_name(playername)
player:hud_remove(hudid)
end
end
local person, person_name
person_name, person, args = get_person(args)
if not person then
if args then
return false, "No such person as "..person_name
end
if not people.hud_show_by_player[playername] then
return false, "No person was being tracked"
end
removecur(playername)
local n = people.hud_show_by_player[playername].name
people.hud_show_by_player[playername] = nil
return true, "Stopped tracking "..n
end
removecur(playername)
people.hud_show_by_player[playername] = {name=person_name}
return true, "Now tracking "..person_name
end
}
subcmd.setowner = {
params = "<name> <owner>",
desc = "Set the owner of the given person to the given player",
exec = function(playername, args)
local person, person_name
person_name, person, args = get_person(args)
if not person then
return false, "Specify a valid person"
end
local ent = people.people[person_name].entity
if not ent then
return false, nil, true
end
if not minetest.check_player_privs(playername, {server=true}) then
if playername ~= ent.owner then
return false, person_name.." isn't yours, so so can't do that"
end
end
if not minetest.auth_table[args] then
return false, "No such new owner '"..args.."'"
end
ent.owner = args
return true, "Set owner of "..person_name.. " to "..args
end
}
subcmd.list = {
params = "",
desc = "List all people in the world",
exec = function(playername, args)
if not minetest.check_player_privs(playername, {server=true}) then
return false, "Only admins can list people"
end
local count = 0
for k, v in pairs(people.people) do
local msg = k.." : "
if v.entity then
msg = msg.."active at "..minetest.pos_to_string(v.entity.object:getpos())
else
if not v.waketime then
msg = msg.."inactive (for unknown time!?)"
else
msg = msg.."inactive for another "..v.waketime - minetest.get_gametime().."s at "..minetest.pos_to_string(v.pos)
end
end
minetest.chat_send_player(playername, msg)
count = count + 1
end
return true, count.." people"
end
}
subcmd.tell = {
params = "<name> <message>",
desc = "Send a message to the given person",
exec = function(playername, args)
local person, person_name
person_name, person, args = get_person(args)
if not person then
return false, "Specify a valid person"
end
local ent = people.people[person_name].entity
if not ent then
return false, nil, true
end
if not minetest.check_player_privs(playername, {server=true}) then
if playername ~= ent.owner then
return false, person_name.." doesn't listen to you"
end
end
local sender = minetest.get_player_by_name(playername)
if not sender then return false, "No such sender" end
ent.on_tell(ent, sender, args)
return true, nil
end
}
subcmd.skin = {
params = "(<name> <skin>)|(<list>)",
desc = "Set a person's skin, or list available skins",
exec = function(playername, args)
local person, person_name
person_name, person, args = get_person(args)
if not args then
return false, "More arguments needed"
end
if not minetest.get_modpath("skins") then
return false, "Skins mod is not installed"
end
if person_name == "list" then
local texlist = ""
for _, skin in ipairs(skins.list) do
if string.match(skin, "^character_") then
if texlist ~= "" then texlist = texlist.." " end
texlist = texlist..string.sub(skin, 11)
end
end
return true, "Available skins: "..texlist
end
if not person then
return false, "Specify a valid person, or 'list'"
end
if not args then
return false, "Specify skin"
end
local ent = person.entity
if not ent then
return false, nil, true
end
if not minetest.check_player_privs(playername, {server=true}) then
if playername ~= ent.owner then
return false, person_name.." isn't yours, so so can't do that"
end
end
local req = "character_"..args
for _, skin in ipairs(skins.list) do
if skin == req then
ent.props.textures = {req..".png"}
ent:update_props()
return true, "Skin updated"
end
end
return false, "No such skin as '"..args.."'"
end
}
--- Handle a chat command.
-- This gets called in the usual way, as a registered chat command handler.
-- It can also get called if a person was inactive when a command was sent
-- and was subsequently activated.
-- @return success, reply
people.do_command = function(name, param)
local cmd, args
cmd, args = string.match(param, "^([^ ]+)(.*)")
if not cmd then return subcmd.help.exec() end
if subcmd[cmd] then
if args then args = string.sub(args, 2) end
success, reply, queue_and_activate = subcmd[cmd].exec(name, args)
if queue_and_activate then
-- Queue a command to happen when the entity wakes up,
-- and make it wake up!
local person
_, person, _ = get_person(args)
person.waketime = minetest.get_gametime()
local add = {name, param}
if person.wakecmds then
table.insert(person.wakecmds, add)
else
person.wakecmds = {add}
end
return true, "Person is inactivate - activating..."
end
return success, reply
end
return false, "No such people command '"..cmd.."' - see '/people help'"
end
minetest.register_chatcommand("people", {
params = "<cmd> [name] [args]",
description = "Commands for working with the people module. '/people help <cmd>' for help.",
func = people.do_command
})
minetest.register_chatcommand("tell", {
params = "<name> <message>",
description = "Send a message to a 'person' from the people module",
func = function(name, param)
subcmd.tell.exec(name, param)
end
})