diff --git a/features/custom_commands.lua b/features/custom_commands.lua index bfb1c6dc..f701049c 100644 --- a/features/custom_commands.lua +++ b/features/custom_commands.lua @@ -8,6 +8,8 @@ local Report = require 'features.report' --local Antigrief = require 'features.antigrief' + +--- Takes a target and teleports them to player. (admin only) local function invoke(cmd) if not (game.player and game.player.admin) then Utils.cant_run(cmd.name) @@ -21,8 +23,10 @@ local function invoke(cmd) 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!') + Utils.log_command(game.player.name, cmd.name, cmd.parameter) end +--- Takes a target and teleports player to target. (admin only) local function teleport_player(cmd) if not (game.player and game.player.admin) then Utils.cant_run(cmd.name) @@ -37,8 +41,11 @@ local function teleport_player(cmd) local pos = surface.find_non_colliding_position('player', game.players[target].position, 0, 1) game.player.teleport(pos, surface) game.print(target .. "! watcha doin'?!") + game.player.print("You have teleported to" .. game.players[target].name) + Utils.log_command(game.player.name, cmd.name, cmd.parameter) end +--- Takes a selected entity and teleports player to entity. (admin only) local function teleport_location(cmd) if not (game.player and game.player.admin) then Utils.cant_run(cmd.name) @@ -50,8 +57,10 @@ local function teleport_location(cmd) end local pos = game.player.surface.find_non_colliding_position('player', game.player.selected.position, 0, 1) game.player.teleport(pos) + Utils.log_command(game.player.name, cmd.name, false) end +--- Kill a player with fish as the cause of death. local function do_fish_kill(player, suicide) local c = player.character if not c then @@ -69,6 +78,7 @@ local function do_fish_kill(player, suicide) return true end +--- Kill a player: admins and the server can kill others, non-admins can only kill themselves local function kill(cmd) local player = game.player local param = cmd.parameter @@ -94,6 +104,7 @@ local function kill(cmd) if not do_fish_kill(target) then Game.player_print(table.concat {"'Sorry, '", target.name, "' doesn't have a character to kill."}) end + Utils.log_command(game.player.name, cmd.name, param) else Game.player_print("Sorry you don't have permission to use the kill command on other players.") end @@ -110,8 +121,10 @@ local function kill(cmd) end end +--- A table of players currently on walkabout global.walking = {} +--- Return player from walkabout local custom_commands_return_player = Token.register( function(args) @@ -141,6 +154,7 @@ local custom_commands_return_player = end ) +--- Takes a target and puts them on walkabot (admin only) local function walkabout(cmd) if game.player and not game.player.admin then Utils.cant_run(cmd.name) @@ -206,11 +220,13 @@ local function walkabout(cmd) player.teleport(non_colliding_pos) player.force = 'neutral' global.walking[player.index] = true + Utils.log_command(game.player.name, cmd.name, cmd.parameter) else Game.player_print('Walkabout failed: could not find non colliding position') end end +--- Promote or demote a player between guest and regular (admin only) local function regular(cmd) if game.player and not game.player.admin then Utils.cant_run(cmd.name) @@ -230,13 +246,16 @@ local function regular(cmd) return elseif (params[1] == 'promote') then UserGroups.add_regular(params[2]) + Utils.log_command(game.player.name, cmd.name, cmd.parameter) elseif (params[1] == 'demote') then UserGroups.remove_regular(params[2]) + Utils.log_command(game.player.name, cmd.name, cmd.parameter) else Game.player_print('Command failed. Usage: /regular , ') end end +--- Check players' afk times local function afk() for _, v in pairs(game.players) do if v.afk_time > 300 then @@ -253,6 +272,7 @@ local function afk() end end +--- Follows a player local function follow(cmd) if not game.player then log(" - Teleports you to the player. (Admins only)', teleport_player) -commands.add_command('invoke', ' - 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('walkabout', ' - Send someone on a walk. (Admins only)', walkabout) -commands.add_command('regulars', 'Prints a list of game regulars.', UserGroups.print_regulars) -commands.add_command('regular', ', Change regular status of a player. (Admins only)', regular) -commands.add_command('afk', 'Shows how long players have been afk.', afk) -commands.add_command( - 'follow', - ' makes you follow the player. Use /unfollow to stop following a player.', - follow -) -commands.add_command('unfollow', 'stops following a player.', unfollow) -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', ' Temporarily bans a player (Admins only)', tempban) -commands.add_command('zoom', ' Sets your zoom.', zoom) +--- Add all commands to command list if _DEBUG then commands.add_command('all-tech', 'researches all technologies (debug only)', all_tech) end + +--- Enables cheat mode (free pocket crafting) for player commands.add_command( 'hax', 'Toggles your hax (makes recipes cost nothing)', function() if game.player and game.player.admin then game.player.cheat_mode = not game.player.cheat_mode + Utils.log_command(game.player, 'hax', false) end end ) -commands.add_command('pool', 'Spawns a pool', pool) ---[[ commands.add_command('undo', ' 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 -) ]] -commands.add_command('find-player', ' shows an alert on the map where the player is located', find_player) -commands.add_command( - 'jail', - ' disables all actions a player can perform except chatting. (Admins only)', - jail_player -) -commands.add_command( - 'unjail', - ' 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', ' Reports a user to admins', Report.cmd_report) +--- Show reports coming from users commands.add_command( 'showreports', 'Shows user reports (Admins only)', @@ -609,4 +607,32 @@ commands.add_command( end ) + +commands.add_command('kill', 'Will kill you.', kill) +commands.add_command('tpplayer', ' - Teleports you to the player. (Admins only)', teleport_player) +commands.add_command('invoke', ' - 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('walkabout', ' - Send someone on a walk. (Admins only)', walkabout) +commands.add_command('regulars', 'Prints a list of game regulars.', UserGroups.print_regulars) +commands.add_command('regular', ', Change regular status of a player. (Admins only)', regular) +commands.add_command('afk', 'Shows how long players have been afk.', afk) +commands.add_command('follow', ' makes you follow the player. Use /unfollow to stop following a player.', follow) +commands.add_command('unfollow', 'stops following a player.', unfollow) +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', ' Temporarily bans a player (Admins only)', tempban) +commands.add_command('zoom', ' 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) +commands.add_command('jail', ' disables all actions a player can perform except chatting. (Admins only)', jail_player) +commands.add_command('unjail', ' 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', ' Reports a user to admins', Report.cmd_report) commands.add_command('show-rail-block', 'Toggles rail block visualisation', show_rail_block) + + +--[[ commands.add_command('undo', ' 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 +) ]] diff --git a/features/gui/popup.lua b/features/gui/popup.lua index 91bbc412..47daafe9 100644 --- a/features/gui/popup.lua +++ b/features/gui/popup.lua @@ -67,6 +67,7 @@ Gui.on_click( end ) +-- Creates a popup dialog for all players local function popup(cmd) local player = game.player if player and not player.admin then @@ -85,8 +86,13 @@ local function popup(cmd) for _, p in ipairs(game.connected_players) do show_popup(p, message) end + + player.print('Popup sent') + Utils.print_admins(player.name .. ' sent a popup to all players', false) + Utils.log_command(game.player.name, cmd.name, cmd.parameter) end +-- Creates a popup dialog for all players, specifically for the server upgrading factorio versions local function popup_update(cmd) local player = game.player if player and not player.admin then @@ -99,8 +105,13 @@ local function popup_update(cmd) for _, p in ipairs(game.connected_players) do show_popup(p, message) end + + player.print('Popup sent') + Utils.print_admins(player.name .. ' sent a popup to all players', false) + Utils.log_command(game.player.name, cmd.name, message) end +-- Creates a popup dialog for the specifically targetted player local function popup_player(cmd) local player = game.player if player and not player.admin then @@ -130,6 +141,9 @@ local function popup_player(cmd) message = message:sub(end_index, #message):gsub('\\n', '\n') show_popup(target, message) + + player.print('Popup sent') + Utils.log_command(game.player.name, cmd.name, cmd.parameter) end commands.add_command('popup', ' - Shows a popup to all connected players (Admins only)', popup) diff --git a/features/nuke_control.lua b/features/nuke_control.lua index 262648e5..19c58e86 100644 --- a/features/nuke_control.lua +++ b/features/nuke_control.lua @@ -1,39 +1,43 @@ local Event = require "utils.event" local UserGroups = require "features.user_groups" local Utils = require "utils.utils" -local Game = require 'utils.game' +local Game = require "utils.game" local function allowed_to_nuke(player) - if type(player) == "table" then - return player.admin or UserGroups.is_regular(player.name) or ((player.online_time / 216000) > global.scenario.config.nuke_control.nuke_min_time_hours) - elseif type(player) == "number" then - return allowed_to_nuke(Game.get_player_by_index(player)) - end + if type(player) == "table" then + return player.admin or UserGroups.is_regular(player.name) or ((player.online_time / 216000) > global.scenario.config.nuke_control.nuke_min_time_hours) + elseif type(player) == "number" then + return allowed_to_nuke(Game.get_player_by_index(player)) + end end local function ammo_changed(event) - local player = Game.get_player_by_index(event.player_index) - if allowed_to_nuke(player) then return end - local nukes = player.remove_item({name="atomic-bomb", count=1000}) - if nukes > 0 then - game.print(player.name .. " tried to use a nuke, but instead dropped it on his foot.") - - local character = player.character - if character and character.valid then - for _,p in ipairs(game.connected_players) do - if p ~= player then - p.add_custom_alert(character, {type = 'item', name = 'atomic-bomb'}, player.name, true) - end - end + local player = Game.get_player_by_index(event.player_index) + if allowed_to_nuke(player) then + return + end + local nukes = player.remove_item({name = "atomic-bomb", count = 1000}) + if nukes > 0 then + game.print(player.name .. " tried to use a nuke, but instead dropped it on his foot.") + + local character = player.character + if character and character.valid then + for _, p in ipairs(game.connected_players) do + if p ~= player then + p.add_custom_alert(character, {type = "item", name = "atomic-bomb"}, player.name, true) + end + end + end + player.character.health = 0 end - player.character.health = 0 - end end local function on_player_deconstructed_area(event) - local player = Game.get_player_by_index(event.player_index) - if allowed_to_nuke(player) then return end - player.remove_item({name="deconstruction-planner", count=1000}) + local player = Game.get_player_by_index(event.player_index) + if allowed_to_nuke(player) then + return + end + player.remove_item({name = "deconstruction-planner", count = 1000}) --Make them think they arent noticed Utils.print_except(player.name .. " tried to deconstruct something, but instead deconstructed themself.", player) @@ -41,113 +45,111 @@ local function on_player_deconstructed_area(event) local character = player.character if character and character.valid then - for _,p in ipairs(game.connected_players) do - if p ~= player then - p.add_custom_alert(character, {type = 'item', name = 'deconstruction-planner'}, player.name, true) + for _, p in ipairs(game.connected_players) do + if p ~= player then + p.add_custom_alert(character, {type = "item", name = "deconstruction-planner"}, player.name, true) + end end - end end character.health = 0 local area = event.area local left_top, right_bottom = area.left_top, area.right_bottom if left_top.x == right_bottom.x and left_top.y == right_bottom.y then - return + return end - local entities = player.surface.find_entities_filtered{area = area, force = player.force} + local entities = player.surface.find_entities_filtered {area = area, force = player.force} if #entities > 1000 then - Utils.print_admins("Warning! " .. player.name .. " just tried to deconstruct " .. tostring(#entities) .. " entities!") + Utils.print_admins("Warning! " .. player.name .. " just tried to deconstruct " .. tostring(#entities) .. " entities!", false) end - for _,entity in pairs(entities) do - if entity.valid and entity.to_be_deconstructed(Game.get_player_by_index(event.player_index).force) then - entity.cancel_deconstruction(Game.get_player_by_index(event.player_index).force) - end + for _, entity in pairs(entities) do + if entity.valid and entity.to_be_deconstructed(Game.get_player_by_index(event.player_index).force) then + entity.cancel_deconstruction(Game.get_player_by_index(event.player_index).force) + end end end local function item_not_sanctioned(item) - local name = item.name - return ( - name:find("capsule") or - name == "cliff-explosives" or - name == "raw-fish" or - name == "discharge-defense-remote" - ) + local name = item.name + return (name:find("capsule") or name == "cliff-explosives" or name == "raw-fish" or name == "discharge-defense-remote") end global.entities_allowed_to_bomb = { - ["stone-wall"] = true, - ["transport-belt"] = true, - ["fast-transport-belt"] = true, - ["express-transport-belt"] = true, - ["construction-robot"] = true, - ["player"] = true, - ["gun-turret"] = true, - ["laser-turret"] = true, - ["flamethrower-turret"] = true, - ["rail"] = true, - ["rail-chain-signal"] = true, - ["rail-signal"] = true, - ["tile-ghost"] = true, - ["entity-ghost"] = true, - ["gate"] = true, - ["electric-pole"] = true, - ["small-electric-pole"] = true, - ["medium-electric-pole"] = true, - ["big-electric-pole"] = true, - ["logistic-robot"] = true, - ["defender"] = true, - ["destroyer"] = true, - ["distractor"] = true + ["stone-wall"] = true, + ["transport-belt"] = true, + ["fast-transport-belt"] = true, + ["express-transport-belt"] = true, + ["construction-robot"] = true, + ["player"] = true, + ["gun-turret"] = true, + ["laser-turret"] = true, + ["flamethrower-turret"] = true, + ["rail"] = true, + ["rail-chain-signal"] = true, + ["rail-signal"] = true, + ["tile-ghost"] = true, + ["entity-ghost"] = true, + ["gate"] = true, + ["electric-pole"] = true, + ["small-electric-pole"] = true, + ["medium-electric-pole"] = true, + ["big-electric-pole"] = true, + ["logistic-robot"] = true, + ["defender"] = true, + ["destroyer"] = true, + ["distractor"] = true } local function entity_allowed_to_bomb(entity) - return global.entities_allowed_to_bomb[entity.name] + return global.entities_allowed_to_bomb[entity.name] end global.players_warned = {} local function on_capsule_used(event) - local item = event.item - local player = Game.get_player_by_index(event.player_index) + local item = event.item + local player = Game.get_player_by_index(event.player_index) - if not player or not player.valid or - (global.scenario.config.nuke_control.enable_autokick and global.scenario.config.nuke_control.enable_autoban) then - return - end - - if item.name == 'artillery-targeting-remote' then - player.surface.create_entity{name = 'flying-text', text = player.name, color = player.color, position = event.position} - end - - if item_not_sanctioned(item) then return end - - if (not allowed_to_nuke(player)) then - local area = {{event.position.x-5, event.position.y-5}, {event.position.x+5, event.position.y+5}} - local count = 0 - local entities = player.surface.find_entities_filtered{force=player.force, area=area} - for _,e in pairs(entities) do - if not entity_allowed_to_bomb(e) then count = count + 1 end + if not player or not player.valid or (global.scenario.config.nuke_control.enable_autokick and global.scenario.config.nuke_control.enable_autoban) then + return end - if count > 8 then - if global.players_warned[event.player_index] then - if global.scenario.config.nuke_control.enable_autokick then - game.ban_player(player, string.format("Damaged %i entities with %s. This action was performed automatically. If you want to contest this ban please visit redmew.com/discord.", count, event.item.name)) - end - else - global.players_warned[event.player_index] = true - if global.scenario.config.nuke_control.enable_autoban then - game.print(player, string.format("Damaged %i entities with %s -Antigrief", count, event.item.name)) - end - end + + if item.name == "artillery-targeting-remote" then + player.surface.create_entity {name = "flying-text", text = player.name, color = player.color, position = event.position} + end + + if item_not_sanctioned(item) then + return + end + + if (not allowed_to_nuke(player)) then + local area = {{event.position.x - 5, event.position.y - 5}, {event.position.x + 5, event.position.y + 5}} + local count = 0 + local entities = player.surface.find_entities_filtered {force = player.force, area = area} + for _, e in pairs(entities) do + if not entity_allowed_to_bomb(e) then + count = count + 1 + end + end + if count > 8 then + if global.players_warned[event.player_index] then + if global.scenario.config.nuke_control.enable_autokick then + game.ban_player(player, string.format("Damaged %i entities with %s. This action was performed automatically. If you want to contest this ban please visit redmew.com/discord.", count, event.item.name)) + end + else + global.players_warned[event.player_index] = true + if global.scenario.config.nuke_control.enable_autoban then + game.print(player, string.format("Damaged %i entities with %s -Antigrief", count, event.item.name)) + end + end + end end - end end local function on_player_joined(event) - local player = game.players[event.player_index] - if string.match(player.name,"^[Ili1|]+$") then - game.ban_player(player) --No reason given, to not give them any hints to change their name - end + local player = game.players[event.player_index] + if string.match(player.name, "^[Ili1|]+$") then + game.ban_player(player) --No reason given, to not give them any hints to change their name + end end Event.add(defines.events.on_player_ammo_inventory_changed, ammo_changed) diff --git a/features/report.lua b/features/report.lua index 14fd6fe9..45edc52a 100644 --- a/features/report.lua +++ b/features/report.lua @@ -57,10 +57,10 @@ Module.show_reports = function(player) local center = player.gui.center local report_frame = center[report_frame_name] - if report_frame and report_frame.valid then + if report_frame and report_frame.valid then Gui.destroy(report_frame) end - + report_frame = center.add { type = 'frame', name = report_frame_name, @@ -135,6 +135,7 @@ function Module.cmd_report(cmd) end end +-- Places a target in jail as long as player is admin or server function Module.jail(target_player, player) -- Set the name of the jail permission group local jail_name = 'Jail' @@ -179,16 +180,9 @@ function Module.jail(target_player, player) target_player.driving=false -- Add player to jail group permission_group.add_player(target_player) - -- Check if a player is shooting while jailed, if they are, remove the weapon in their active gun slot. + -- If a player is shooting when they're jailed they can't stop shooting, so we change their shooting state if target_player.shooting_state.state ~= 0 then - -- Use a while loop because if a player has guns in inventory they will auto-refill the slot. - while target_player.get_inventory(defines.inventory.player_guns)[target_player.character.selected_gun_index].valid_for_read do - target_player.remove_item(target_player.get_inventory(defines.inventory.player_guns)[target_player.character.selected_gun_index]) - end - target_player.print(prefix) - target_player.print('Your active weapon has been removed because you were shooting while jailed.') - target_player.print('Your gun will *not* be returned to you.') - target_player.print(prefix_e) + target_player.shooting_state.state = {state = defines.shooting.not_shooting, position = {0,0}} end -- Check that it worked @@ -198,6 +192,8 @@ function Module.jail(target_player, player) target_player.print(prefix) target_player.print('You have been placed in jail by ' .. jailed_by .. '. The only action avaliable to you is chatting.') target_player.print('Please respond to inquiries from the admins.', {r = 1, g = 1, b = 0, a = 1}) + Utils.print_admins(target_player.name .. 'has been jailed by' .. player.name) + Utils.log_command(player, 'jail', target_player.name) else -- Let admin know it didn't work. print('Something went wrong in the jailing of ' .. target_player.name .. '. You can still change their group via /permissions.') @@ -303,9 +299,9 @@ local reporting_input_name = Gui.uid_name() Module.spawn_reporting_popup = function(player, reported_player) local center = player.gui.center - + local reporting_popup = center[reporting_popup_name] - if reporting_popup and reporting_popup.valid then + if reporting_popup and reporting_popup.valid then Gui.destroy(reporting_popup) end reporting_popup = center.add { @@ -323,7 +319,7 @@ Module.spawn_reporting_popup = function(player, reported_player) caption = 'Report message:' } local input = reporting_popup.add {type = 'text-box', name=reporting_input_name} - input.style.width = 400 + input.style.width = 400 input.style.height = 85 local button_flow = reporting_popup.add {type = "flow"} button_flow.add {type = "button", name = reporting_submit_button_name, caption="Submit"} @@ -332,7 +328,7 @@ end Gui.on_custom_close( reporting_popup_name, - function(event) + function(event) Gui.destroy(event.element) end ) diff --git a/utils/utils.lua b/utils/utils.lua index ddb3d2b1..cbc81df8 100644 --- a/utils/utils.lua +++ b/utils/utils.lua @@ -1,5 +1,6 @@ local Module = {} local Game = require 'utils.game' +local prefix = '## - ' Module.distance = function(pos1, pos2) local dx = pos2.x - pos1.x @@ -15,10 +16,25 @@ Module.print_except = function(msg, player) end end -Module.print_admins = function(msg) - for _, p in pairs(game.players) do - if p.connected and p.admin then - p.print(msg) +-- Takes a LuaPlayer or string as source +Module.print_admins = function(msg, source) + local source_name + local chat_color + if source then + if type(source) == 'string' then + source_name = source + chat_colot = game.players[source].chat_color + else + source_name = source.name + chat_color = source.chat_color + end + else + source_name = "Server" + chat_color = {r=255, g=255, b=255} + end + for _, p in pairs(game.connected_players) do + if p.admin then + p.print(string.format('%s(ADMIN) %s: %s', prefix, source_name, msg), chat_color) end end end @@ -117,6 +133,22 @@ Module.cant_run = function(name) Game.player_print("Can't run command (" .. name .. ') - insufficient permission.') end +Module.log_command = function(user, command, parameters) + local name + + -- We can use a LuaPlayer or a string (ex. "Server"). + if type(user) == 'string' then + name = user + else + name = user.name + end + local action = table.concat {'[Admin-Command] ', name, ' used: ', command} + if parameters then + action = table.concat {'[Admin-Command] ', name, ' used: ', command, ' ', parameters} + end + log(action) +end + Module.comma_value = function(n) -- credit http://richard.warburton.it local left,num,right = string.match(n, '^([^%d]*%d)(%d*)(.-)$') return left .. (num:reverse():gsub('(%d%d%d)', '%1,'):reverse()) .. right