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 = "[]", 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 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 = "", 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 = "", 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 = "", 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 = "", 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 = "", 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 = "[]", 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 = "[]", 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 = " ", 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 = " ", 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 = "( )|()", 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 = " [name] [args]", description = "Commands for working with the people module. '/people help ' for help.", func = people.do_command }) minetest.register_chatcommand("tell", { params = " ", description = "Send a message to a 'person' from the people module", func = function(name, param) subcmd.tell.exec(name, param) end })