1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-14 10:13:13 +02:00
RedMew/features/custom_commands.lua

637 lines
20 KiB
Lua
Raw Normal View History

local Task = require 'utils.Task'
local Event = require 'utils.event'
2018-11-26 03:07:03 +02:00
local Token = require 'utils.token'
2018-11-11 09:20:07 +02:00
local UserGroups = require 'features.user_groups'
2018-11-26 03:07:03 +02:00
local Utils = require 'utils.core'
2018-09-23 00:25:13 +02:00
local Game = require 'utils.game'
2018-11-11 23:18:46 +02:00
local Report = require 'features.report'
2018-11-30 17:56:26 +02:00
local Server = require 'features.server'
local Timestamp = require 'utils.timestamp'
2018-12-05 13:10:34 +02:00
local Command = require 'utils.command'
2018-12-09 01:34:25 +02:00
local format = string.format
2018-11-11 23:18:46 +02:00
2018-11-11 09:20:07 +02:00
--local Antigrief = require 'features.antigrief'
--- Takes a target and teleports them to player. (admin only)
2017-09-03 12:29:19 +02:00
local function invoke(cmd)
2018-05-23 19:29:35 +02:00
if not (game.player and game.player.admin) then
2018-11-06 13:55:52 +02:00
Utils.cant_run(cmd.name)
2017-07-06 19:37:57 +02:00
return
end
local target = cmd['parameter']
if target == nil or game.players[target] == nil then
2018-11-06 13:55:52 +02:00
Game.player_print('Unknown player.')
2017-07-08 20:58:45 +02:00
return
2017-07-06 19:37:57 +02:00
end
local pos = game.player.surface.find_non_colliding_position('player', game.player.position, 0, 1)
game.players[target].teleport({pos.x, pos.y}, game.player.surface)
game.print(target .. ', get your ass over here!')
2017-07-06 19:37:57 +02:00
end
--- Takes a target and teleports player to target. (admin only)
2017-09-03 12:29:19 +02:00
local function teleport_player(cmd)
2018-05-23 19:29:35 +02:00
if not (game.player and game.player.admin) then
2018-11-06 13:55:52 +02:00
Utils.cant_run(cmd.name)
2017-07-06 19:37:57 +02:00
return
end
local target = cmd['parameter']
if target == nil or game.players[target] == nil then
2018-11-06 13:55:52 +02:00
Game.player_print('Unknown player.')
2017-07-08 20:58:45 +02:00
return
2017-07-06 19:37:57 +02:00
end
local surface = game.players[target].surface
local pos = surface.find_non_colliding_position('player', game.players[target].position, 0, 1)
game.player.teleport(pos, surface)
2017-07-06 19:37:57 +02:00
game.print(target .. "! watcha doin'?!")
game.player.print('You have teleported to ' .. game.players[target].name)
2017-07-06 19:37:57 +02:00
end
--- Takes a selected entity and teleports player to entity. (admin only)
2017-09-03 12:29:19 +02:00
local function teleport_location(cmd)
2018-05-23 19:29:35 +02:00
if not (game.player and game.player.admin) then
2018-11-06 13:55:52 +02:00
Utils.cant_run(cmd.name)
2017-07-06 19:37:57 +02:00
return
end
if game.player.selected == nil then
2018-11-06 13:55:52 +02:00
Game.player_print('Nothing selected.')
2017-07-06 19:37:57 +02:00
return
end
local pos = game.player.surface.find_non_colliding_position('player', game.player.selected.position, 0, 1)
game.player.teleport(pos)
2017-07-06 19:37:57 +02:00
end
--- Kill a player with fish as the cause of death.
2018-07-01 15:19:19 +02:00
local function do_fish_kill(player, suicide)
2018-06-29 13:18:14 +02:00
local c = player.character
if not c then
return false
end
local e = player.surface.create_entity {name = 'fish', position = player.position}
c.die(player.force, e)
2018-07-01 15:19:19 +02:00
-- Don't want people killing themselves for free fish.
if suicide then
e.destroy()
end
2018-06-29 13:18:14 +02:00
return true
end
--- Kill a player: admins and the server can kill others, non-admins can only kill themselves
2018-06-29 13:18:14 +02:00
local function kill(cmd)
local player = game.player
local param = cmd.parameter
local target
if param then
target = game.players[param]
2018-06-29 13:18:14 +02:00
if not target then
2018-11-06 13:55:52 +02:00
Game.player_print(table.concat {"Sorry, player '", param, "' was not found."})
2018-06-29 13:18:14 +02:00
return
end
end
if global.walking then
if (player and global.walking[player.index]) or (target and global.walking[target.index]) then
Game.player_print("A player on walkabout cannot be killed by a mere fish, don't waste your efforts.")
return
end
end
2018-06-29 13:18:14 +02:00
if not target and player then
2018-07-01 15:19:19 +02:00
if not do_fish_kill(player, true) then
2018-11-06 13:55:52 +02:00
Game.player_print("Sorry, you don't have a character to kill.")
2018-06-29 13:18:14 +02:00
end
elseif player then
if target == player then
2018-07-01 15:19:19 +02:00
if not do_fish_kill(player, true) then
2018-11-06 13:55:52 +02:00
Game.player_print("Sorry, you don't have a character to kill.")
2018-06-29 13:18:14 +02:00
end
elseif target and player.admin then
2018-07-03 18:24:05 +02:00
if not do_fish_kill(target) then
2018-11-06 13:55:52 +02:00
Game.player_print(table.concat {"'Sorry, '", target.name, "' doesn't have a character to kill."})
2018-06-29 13:18:14 +02:00
end
else
2018-11-06 13:55:52 +02:00
Game.player_print("Sorry you don't have permission to use the kill command on other players.")
2018-06-29 13:18:14 +02:00
end
elseif target then
if not do_fish_kill(target) then
2018-11-06 13:55:52 +02:00
Game.player_print(table.concat {"'Sorry, '", target.name, "' doesn't have a character to kill."})
2018-06-29 13:18:14 +02:00
end
else
if param then
2018-11-06 13:55:52 +02:00
Game.player_print(table.concat {"Sorry, player '", param, "' was not found."})
2018-06-29 13:18:14 +02:00
else
2018-11-06 13:55:52 +02:00
Game.player_print('Usage: /kill <player>')
2018-06-29 13:18:14 +02:00
end
end
2017-07-08 20:58:45 +02:00
end
2017-07-06 19:37:57 +02:00
2017-07-09 15:20:01 +02:00
local function regular(cmd)
2018-06-04 17:35:18 +02:00
if game.player and not game.player.admin then
2018-11-06 13:55:52 +02:00
Utils.cant_run(cmd.name)
return
end
if cmd.parameter == nil then
2018-11-06 13:55:52 +02:00
Game.player_print('Command failed. Usage: /regular <promote, demote>, <player>')
return
end
local params = {}
for param in string.gmatch(cmd.parameter, '%S+') do
table.insert(params, param)
end
if #params == 2 then
if params[1] == 'promote' then
UserGroups.add_regular(params[2])
elseif params[1] == 'demote' then
UserGroups.remove_regular(params[2])
else
Game.player_print('Command failed. Usage: /regular <promote, demote>, <player>')
end
elseif #params == 1 and params[1] ~= 'promote' and params[1] ~= 'demote' then
UserGroups.add_regular(params[1])
else
2018-11-06 13:55:52 +02:00
Game.player_print('Command failed. Usage: /regular <promote, demote>, <player>')
end
2017-07-09 15:20:01 +02:00
end
--- Check players' afk times
2017-07-18 22:53:53 +02:00
local function afk()
2018-09-23 00:25:13 +02:00
for _, v in pairs(game.players) do
if v.afk_time > 300 then
local time = ' '
if v.afk_time > 21600 then
time = time .. math.floor(v.afk_time / 216000) .. ' hours '
end
if v.afk_time > 3600 then
time = time .. math.floor(v.afk_time / 3600) % 60 .. ' minutes and '
end
time = time .. math.floor(v.afk_time / 60) % 60 .. ' seconds.'
2018-11-06 13:55:52 +02:00
Game.player_print(v.name .. ' has been afk for' .. time)
end
end
2017-07-18 22:53:53 +02:00
end
--- Follows a player
2017-07-25 01:20:59 +02:00
local function follow(cmd)
if not game.player then
log("<Server can't do that.")
return
end
if cmd.parameter ~= nil and game.players[cmd.parameter] ~= nil then
global.follows[game.player.name] = cmd.parameter
global.follows.n_entries = global.follows.n_entries + 1
else
2018-11-30 17:56:26 +02:00
Game.player_print(
'Usage: /follow <player> makes you follow the player. Use /unfollow to stop following a player.'
)
end
2017-07-25 01:20:59 +02:00
end
--- Stops following a player
local function unfollow()
if not game.player then
log("<Server can't do that.")
return
end
if global.follows[game.player.name] ~= nil then
global.follows[game.player.name] = nil
global.follows.n_entries = global.follows.n_entries - 1
end
2017-07-25 01:20:59 +02:00
end
--- A table of players with tpmode turned on
2017-08-19 07:41:58 +02:00
global.tp_players = {}
--- If a player is in the global.tp_players list, remove ghosts they place and teleport them to that position
2017-08-18 03:04:29 +02:00
local function built_entity(event)
local index = event.player_index
2017-08-18 03:04:29 +02:00
if global.tp_players[index] then
local entity = event.created_entity
2017-08-18 03:04:29 +02:00
2018-06-04 17:35:18 +02:00
if not entity or not entity.valid or entity.type ~= 'entity-ghost' then
return
end
Game.get_player_by_index(index).teleport(entity.position)
entity.destroy()
end
2017-08-18 03:04:29 +02:00
end
2018-04-06 21:58:50 +02:00
Event.add(defines.events.on_built_entity, built_entity)
2017-08-19 07:41:58 +02:00
--- Adds/removes players from the tp_players table (admin only)
2017-08-26 13:32:49 +02:00
local function toggle_tp_mode(cmd)
2018-06-04 17:35:18 +02:00
if not (game.player and game.player.admin) then
2018-11-06 13:55:52 +02:00
Utils.cant_run(cmd.name)
return
end
local index = game.player.index
local toggled = global.tp_players[index]
if toggled then
global.tp_players[index] = nil
2018-11-06 13:55:52 +02:00
Game.player_print('tp mode is now off')
else
global.tp_players[index] = true
2018-11-06 13:55:52 +02:00
Game.player_print('tp mode is now on - place a ghost entity to teleport there.')
end
2017-08-18 03:04:29 +02:00
end
--- Checks if we have a permission group named 'banned' and if we don't, create it
2018-06-04 18:21:03 +02:00
local function get_group()
local group = game.permissions.get_group('Banned')
if not group then
game.permissions.create_group('Banned')
group = game.permissions.get_group('Banned')
if group then
for i = 2, 174 do
group.set_allows_action(i, false)
end
else
2018-11-30 17:56:26 +02:00
game.print(
'This would have nearly crashed the server, please consult the next best scenario dev (valansch or TWLtriston).'
)
end
end
2018-06-04 18:21:03 +02:00
return group
end
--- Removes player from the tempban list (by changing them back to the default permissions group)
local custom_commands_untempban =
Token.register(
function(param)
game.print(param.name .. ' is out of timeout.')
game.permissions.get_group('Default').add_player(param.name)
end
)
2017-11-12 16:49:28 +02:00
--- Gives a player a temporary ban
local function tempban(cmd)
2018-06-04 18:21:03 +02:00
if (not game.player) or not game.player.admin then
2018-11-06 13:55:52 +02:00
Utils.cant_run(cmd.name)
return
end
if cmd.parameter == nil then
2018-11-06 13:55:52 +02:00
Game.player_print('Tempban failed. Usage: /tempban <player> <minutes> Temporarily bans a player.')
return
end
local params = {}
for param in string.gmatch(cmd.parameter, '%S+') do
table.insert(params, param)
end
if #params < 2 or not tonumber(params[2]) then
2018-11-06 13:55:52 +02:00
Game.player_print('Tempban failed. Usage: /tempban <player> <minutes> Temporarily bans a player.')
return
end
if not game.players[params[1]] then
2018-11-06 13:55:52 +02:00
Game.player_print("Player doesn't exist.")
return
end
local group = get_group()
2018-06-04 18:21:03 +02:00
game.print(Utils.get_actor() .. ' put ' .. params[1] .. ' in timeout for ' .. params[2] .. ' minutes.')
if group then
group.add_player(params[1])
if not tonumber(cmd.parameter) then
Task.set_timeout(60 * tonumber(params[2]), custom_commands_untempban, {name = params[1]})
end
end
2017-11-12 16:49:28 +02:00
end
local custom_commands_replace_ghosts =
Token.register(
function(param)
for _, ghost in pairs(param.ghosts) do
local new_ghost =
game.surfaces[param.surface_index].create_entity {
name = 'entity-ghost',
position = ghost.position,
inner_name = ghost.ghost_name,
expires = false,
force = 'enemy',
direction = ghost.direction
}
new_ghost.last_user = ghost.last_user
end
end
)
--- Lets a player set their zoom level
2017-11-12 20:43:51 +02:00
local function zoom(cmd)
if game.player and cmd and cmd.parameter and tonumber(cmd.parameter) then
game.player.zoom = tonumber(cmd.parameter)
end
2017-11-12 20:43:51 +02:00
end
--- Creates a rectangle of water below an admin
local function pool(cmd)
if game.player and game.player.admin then
local t = {}
2018-06-04 18:21:03 +02:00
local p = game.player.position
for x = p.x - 3, p.x + 3 do
for y = p.y + 2, p.y + 7 do
table.insert(t, {name = 'water', position = {x, y}})
end
end
game.player.surface.set_tiles(t)
game.player.surface.create_entity {name = 'fish', position = {p.x + 0.5, p.y + 5}}
end
end
2018-06-25 13:19:50 +02:00
--[[ global.undo_warned_players = {}
local function undo(cmd)
2018-06-07 22:06:48 +02:00
if (not game.player) or not game.player.admin then
2018-11-06 13:55:52 +02:00
Utils.cant_run(cmd.name)
2018-06-07 22:06:48 +02:00
return
end
if cmd.parameter and game.players[cmd.parameter] then
2018-06-07 22:06:48 +02:00
if
not global.undo_warned_players[game.player.index] or
global.undo_warned_players[game.player.index] ~= game.players[cmd.parameter].index
2018-06-07 22:06:48 +02:00
then
global.undo_warned_players[game.player.index] = game.players[cmd.parameter].index
2018-06-07 22:06:48 +02:00
game.player.print(
string.format(
'Warning! You are about to remove %s entities and restore %s entities.',
#Utils.find_entities_by_last_user(game.players[cmd.parameter], game.surfaces.nauvis),
Antigrief.count_removed_entities(game.players[cmd.parameter])
2018-06-07 22:06:48 +02:00
)
)
game.player.print('To execute the command please run it again.')
return
end
Antigrief.undo(game.players[cmd.parameter])
2018-06-07 22:06:48 +02:00
game.print(string.format('Undoing everything %s did...', cmd.parameter))
global.undo_warned_players[game.player.index] = nil
else
2018-11-06 13:55:52 +02:00
Game.player_print('Usage: /undo <player>')
2018-06-07 22:06:48 +02:00
end
end
local function antigrief_surface_tp()
2018-06-07 22:06:48 +02:00
if (not game.player) or not game.player.admin then
2018-11-06 13:55:52 +02:00
Utils.cant_run(cmd.name)
2018-06-07 22:06:48 +02:00
return
end
Antigrief.antigrief_surface_tp()
2018-06-25 13:19:50 +02:00
end ]]
--- Creates an alert for the player at the location of their target
2018-06-08 00:50:45 +02:00
local function find_player(cmd)
local player = game.player
if not player then
return
end
local name = cmd.parameter
if not name then
player.print('Usage: /find-player <player>')
return
end
local target = game.players[name]
2018-06-08 00:50:45 +02:00
if not target then
player.print('player ' .. name .. ' not found')
return
end
target = target.character
if not target or not target.valid then
player.print('player ' .. name .. ' does not have a character')
return
end
2018-08-18 18:50:30 +02:00
player.add_custom_alert(target, {type = 'virtual', name = 'signal-F'}, name, true)
2018-06-08 00:50:45 +02:00
end
--- Places a target in jail (a permissions group which is unable to act aside from chatting)(admin only)
2018-08-07 12:14:03 +02:00
local function jail_player(cmd)
local player = game.player
-- Check if the player can run the command
if player and not player.admin then
2018-11-06 13:55:52 +02:00
Utils.cant_run(cmd.name)
2018-08-07 12:14:03 +02:00
return
end
-- Check if the target is valid
local target_name = cmd['parameter']
2018-11-18 14:21:08 +02:00
if not target_name then
2018-11-06 13:55:52 +02:00
Game.player_print('Usage: /jail <player>')
2018-08-07 12:14:03 +02:00
return
end
local target = game.players[target_name]
Report.jail(target, player)
2018-08-07 12:14:03 +02:00
end
2018-08-08 23:43:37 +02:00
2018-08-24 17:47:03 +02:00
local function all_tech()
2018-10-16 15:59:31 +02:00
if game.player then
game.player.force.research_all_technologies()
2018-11-06 13:55:52 +02:00
Game.player_print('Your force has been granted all technologies')
2018-08-09 20:13:14 +02:00
end
end
--- Traps errors if not in DEBUG.
2018-05-22 02:03:04 +02:00
if not _DEBUG then
local old_add_command = commands.add_command
commands.add_command =
function(name, desc, func)
old_add_command(
name,
desc,
function(cmd)
local success, error = pcall(func, cmd)
if not success then
log(error)
2018-11-06 13:55:52 +02:00
Game.player_print('Sorry there was an error running ' .. cmd.name)
end
end
)
end
2018-05-07 14:16:41 +02:00
end
--- Sends a message to all online admins
2018-08-09 00:14:59 +02:00
local function admin_chat(cmd)
if not game.player then -- server
Utils.print_admins(cmd.parameter, false)
elseif game.player.admin then --admin
Utils.print_admins(cmd.parameter, game.player)
else
Utils.cant_run(cmd.name)
return
2018-08-10 19:10:30 +02:00
end
end
--- Turns on rail block visualization for player
2018-09-04 14:09:14 +02:00
local function show_rail_block()
local player = game.player
if not player then
return
end
local vs = player.game_view_settings
local show = not vs.show_rail_block_visualisation
vs.show_rail_block_visualisation = show
player.print('show_rail_block_visualisation set to ' .. tostring(show))
end
2018-11-30 17:56:26 +02:00
local function server_time()
local player = game.player
local p
if not player then
p = print
elseif player.valid then
p = player.print
else
return
end
local secs = Server.get_current_time()
if secs == nil then
p('Server time is not available, is this game running on a Redmew server?')
else
p(Timestamp.to_string(secs))
end
end
--- Add all commands to command list
2018-12-02 19:04:44 +02:00
if _DEBUG or _CHEATS then
commands.add_command('all-tech', 'researches all technologies (debug only)', all_tech)
end
2018-12-05 13:10:34 +02:00
Command.add(
2018-12-01 18:20:44 +02:00
'sc',
2018-12-05 13:10:34 +02:00
{
description = 'silent-command',
arguments = {'str'},
admin_only = true,
capture_excess_arguments = true,
allowed_by_server = true,
allowed_by_player = true
},
function(args, player)
2018-12-01 18:20:44 +02:00
local p
if player then
p = player.print
else
p = print
end
2018-12-05 13:10:34 +02:00
local func, err = loadstring(args.str)
2018-12-01 18:20:44 +02:00
if not func then
p(err)
end
local _, err2 = pcall(func)
if err2 then
local i = err2:find('\n')
p(err2:sub(1, i))
end
end
)
--- Enables cheat mode (free pocket crafting) for player
2018-06-07 22:06:48 +02:00
commands.add_command(
'hax',
2018-08-24 17:47:03 +02:00
'Toggles your hax (makes recipes cost nothing)',
2018-06-07 22:06:48 +02:00
function()
if game.player and game.player.admin then
game.player.cheat_mode = not game.player.cheat_mode
end
end
)
2018-08-18 13:38:46 +02:00
--- Show reports coming from users
2018-08-18 13:38:46 +02:00
commands.add_command(
'showreports',
'Shows user reports (Admins only)',
function(event)
if game.player and game.player.admin then
Report.show_reports(Game.get_player_by_index(event.player_index))
2018-08-15 14:15:03 +02:00
end
end
)
2018-09-04 14:09:14 +02:00
commands.add_command('kill', 'Will kill you.', kill)
commands.add_command('tpplayer', '<player> - Teleports you to the player. (Admins only)', teleport_player)
commands.add_command('invoke', '<player> - Teleports the player to you. (Admins only)', invoke)
commands.add_command('tppos', 'Teleports you to a selected entity. (Admins only)', teleport_location)
commands.add_command('regulars', 'Prints a list of game regulars.', UserGroups.print_regulars)
commands.add_command('regular', '<promote, demote>, <player> Change regular status of a player. (Admins only)', regular)
commands.add_command('afk', 'Shows how long players have been afk.', afk)
2018-11-30 17:56:26 +02:00
commands.add_command(
'follow',
'<player> makes you follow the player. Use /unfollow to stop following a player.',
follow
)
commands.add_command('unfollow', 'stops following a player.', unfollow)
2018-11-30 17:56:26 +02:00
commands.add_command(
'tpmode',
'Toggles tp mode. When on place a ghost entity to teleport there (Admins only)',
toggle_tp_mode
)
commands.add_command('tempban', '<player> <minutes> Temporarily bans a player (Admins only)', tempban)
commands.add_command('zoom', '<number> Sets your zoom.', zoom)
commands.add_command('pool', 'Spawns a pool', pool)
commands.add_command('find', '<player> shows an alert on the map where the player is located', find_player)
2018-11-30 17:56:26 +02:00
commands.add_command(
'jail',
'<player> disables all actions a player can perform except chatting. (Admins only)',
jail_player
)
commands.add_command(
'unjail',
'<player> restores ability for a player to perform actions. (Admins only)',
Report.unjail_player
)
commands.add_command('a', 'Admin chat. Messages all other admins (Admins only)', admin_chat)
commands.add_command('report', '<griefer-name> <message> Reports a user to admins', Report.cmd_report)
2018-09-04 14:09:14 +02:00
commands.add_command('show-rail-block', 'Toggles rail block visualisation', show_rail_block)
2018-11-30 17:56:26 +02:00
commands.add_command('server-time', "Prints the server's time", server_time)
--[[ commands.add_command('undo', '<player> undoes everything a player has done (Admins only)', undo)
commands.add_command(
'antigrief_surface',
'moves you to the antigrief surface or back (Admins only)',
antigrief_surface_tp
) ]]
2018-12-09 01:34:25 +02:00
Command.add('search-command', {
description = 'Search for commands matching the keyword in name or description',
arguments = {'keyword'},
capture_excess_arguments = true,
}, function (arguments, player)
local keyword = arguments.keyword
local p = player.print
2018-12-09 13:44:20 +02:00
if #keyword < 2 then
2018-12-09 01:34:25 +02:00
p('Keyword should be 2 characters or more')
return
end
local matches = Command.search(arguments.keyword)
local count = #matches
if count == 0 then
p('----- Search Results -----')
p(format('No commands found matching "%s"', keyword))
return
end
local max = count > 7 and 7 or count
p('----- Search Results -----')
for i = 1, max do
p(format('/%s', matches[i]))
end
local diff = count - max
local singular = diff == 1
p('-------------------------')
if max ~= count then
p(format('%d %s hidden, please narrow your search', diff, singular and 'result was' or 'results were'))
else
p(format('%d %s matching "%s"', count, singular and 'result' or 'results', keyword))
end
end)