local S = classroom.S classroom.register_action("classroom:bring", { title = S"Bring", description = S"Teleport players to your location", online_required = true, func = function(runner, players) local pos = runner:get_pos() for _, name in pairs(players) do local player = minetest.get_player_by_name(name) player:set_pos(pos) end end, }) local function look_at(player, target) local pos = player:get_pos() local delta = vector.subtract(target, pos) player:set_look_horizontal(math.atan2(delta.z, delta.x) - math.pi / 2) end classroom.register_action("classroom:look", { title = S"Look", description = S"Make players look at you", online_required = true, func = function(runner, players) local pos = runner:get_pos() for _, name in pairs(players) do local player = minetest.get_player_by_name(name) look_at(player, pos) end end, }) classroom.register_action("classroom:mute", { title = S"Mute", description = S"Revoke shout from players", online_required = false, func = function(runner, players) for _, name in pairs(players) do local privs = minetest.get_player_privs(name) privs.shout = nil minetest.set_player_privs(name, privs) end end, }) classroom.register_action("classroom:unmute", { title = S"Unmute", description = S"Grant shout to players", online_required = false, func = function(runner, players) for _, name in pairs(players) do local privs = minetest.get_player_privs(name) privs.shout = true minetest.set_player_privs(name, privs) end end, }) classroom.register_action("classroom:fly", { title = S"Fly", description = S"Grant fly to players", online_required = false, func = function(runner, players) for _, name in pairs(players) do local privs = minetest.get_player_privs(name) privs.fly = true minetest.set_player_privs(name, privs) end end, }) classroom.register_action("classroom:nofly", { title = S"NoFly", description = S"Revoke fly from players", online_required = false, func = function(runner, players) for _, name in pairs(players) do local privs = minetest.get_player_privs(name) privs.fly = nil minetest.set_player_privs(name, privs) end end, }) classroom.register_action("classroom:kick", { title = S"Kick", description = S"Remove from the server", online_required = false, params = { message = "Kick Message", }, func = function(runner, players, message) message = message or S("Kicked by @1", runner:get_player_name()) for _, name in pairs(players) do minetest.kick_player(name, message) end end, }) classroom.register_action("classroom:ban", { title = S"Ban", description = S"Permanently from the server", online_required = false, params = { message = "Ban Message", }, func = function(runner, players, message) message = message or S("Banned by @1", runner:get_player_name()) for _, name in pairs(players) do minetest.ban_player(name, message) end end, }) local function find_center_position(start, direction) local endp = vector.add(start, vector.multiply(direction, 10)) local rc = minetest.raycast(start, endp, false, true) local first = rc:next() if first then return vector.subtract(first.under, direction) else return endp end end local function place_player_if_ok(player, pos, teacher_pos) -- Move down to ground local rc = minetest.raycast(pos, vector.add(pos, { x = 0, y = -20, z = 0 }), false, true) local first = rc:next() if first then pos = vector.add(first.under, { x = 0, y = 1, z = 0 }) end -- TODO: handle players already being in that location -- Check teacher is visible if not minetest.line_of_sight(pos, teacher_pos) then return false end player:set_pos(pos) look_at(player, teacher_pos) return true end local function place_all_players(players, teacher_pos, direction) local center = find_center_position(teacher_pos, direction) local direction_perp = vector.normalize(vector.new(direction.z, direction.y, -direction.x)) for unmapped_column=0, 100 do for row=0, 1 do local next_player = players[#players] assert(next_player) local column = math.floor(unmapped_column / 2) * ((unmapped_column % 2) * 2 - 1) + unmapped_column % 2 local delta = vector.add(vector.multiply(direction, row), vector.multiply(direction_perp, column)) local pos = vector.add(center, delta) if place_player_if_ok(next_player, pos, teacher_pos) then table.remove(players, #players) end if #players == 0 then return end end end end classroom.register_action("classroom:audience", { title = S"Audience", description = S"Move to the crosshair location, spread out and facing you", online_required = true, func = function(runner, players, message) local playerrefs = {} for i=1, #players do playerrefs[i] = minetest.get_player_by_name(players[i]) end local eye_height = runner:get_properties().eye_height local teacher_pos = vector.add(runner:get_pos(), { x = 0, y = eye_height, z = 0}) place_all_players(playerrefs, teacher_pos, runner:get_look_dir()) end, }) classroom.register_action("classroom:freeze", { title = S"Freeze", description = S"Prevent movement", online_required = true, func = function(runner, players, message) for i=1, #players do local player = minetest.get_player_by_name(players[i]) classroom.freeze(player) end end, }) classroom.register_action("classroom:thaw", { title = S"Unfreeze", description = S"Allow movement", online_required = true, func = function(runner, players, message) for i=1, #players do local player = minetest.get_player_by_name(players[i]) classroom.unfreeze(player) end end, })