diff --git a/control.lua b/control.lua index 33562e90..164e86a0 100644 --- a/control.lua +++ b/control.lua @@ -29,13 +29,14 @@ require 'features.nuke_control' require 'features.player_colors' require 'features.reactor_meltdown' require 'features.train_station_names' +require 'features.walkabout' -- Contains various commands for users and admins alike require 'features.custom_commands' -- GUIs the order determines the order they appear from left to right. -- These can be safely disabled. Some map presets will add GUI modules themselves. -local info = require 'features.gui.info' +require 'features.gui.info' require 'features.gui.player_list' require 'features.gui.poll' require 'features.gui.tag_group' diff --git a/features/custom_commands.lua b/features/custom_commands.lua index ef9fd355..87ec167a 100644 --- a/features/custom_commands.lua +++ b/features/custom_commands.lua @@ -91,6 +91,11 @@ local function kill(cmd) end end + if global.walking[player.index] == true or global.walking[target.index] == true then + player.print("A player on walkabout cannot be killed by a mere fish, don't waste your efforts.") + return + end + if not target and player then if not do_fish_kill(player, true) then Game.player_print("Sorry, you don't have a character to kill.") @@ -121,112 +126,6 @@ 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) - local player = args.player - if not player.valid then - return - end - - global.walking[player.index] = false - - local walkabout_character = player.character - if walkabout_character and walkabout_character.valid then - walkabout_character.destroy() - end - - local character = args.character - if character ~= nil and character.valid then - player.character = character - else - player.create_character() - player.teleport(args.position) - end - - player.force = args.force - - game.print(args.player.name .. ' came back from his walkabout.') - 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) - return - end - local params = {} - if cmd.parameter == nil then - Game.player_print('Walkabout failed, check /help walkabout.') - return - end - for param in string.gmatch(cmd.parameter, '%S+') do - table.insert(params, param) - end - local player_name = params[1] - local duration = 60 - if #params > 2 then - Game.player_print('Walkabout failed, check /help walkabout.') - return - elseif #params == 2 and tonumber(params[2]) == nil then - Game.player_print(params[2] .. ' is not a number.') - return - elseif #params == 2 and tonumber(params[2]) then - duration = tonumber(params[2]) - end - if duration < 15 then - duration = 15 - end - - local player = game.players[player_name] - if player == nil or not player.valid or global.walking[player.index] then - Game.player_print(player_name .. ' could not go on a walkabout.') - return - end - local chunks = {} - for chunk in player.surface.get_chunks() do - table.insert(chunks, chunk) - end - - local surface = player.surface - local chunk = surface.get_random_chunk() - local pos = {x = chunk.x * 32, y = chunk.y * 32} - local non_colliding_pos = surface.find_non_colliding_position('player', pos, 100, 1) - - local character = player.character - if character and character.valid then - character.walking_state = {walking = false} - end - - if non_colliding_pos then - game.print(player_name .. ' went on a walkabout, to find himself.') - Task.set_timeout( - duration, - custom_commands_return_player, - { - player = player, - force = player.force, - position = {x = player.position.x, y = player.position.y}, - character = character - } - ) - player.character = nil - player.create_character() - 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) diff --git a/features/walkabout.lua b/features/walkabout.lua new file mode 100644 index 00000000..2347d660 --- /dev/null +++ b/features/walkabout.lua @@ -0,0 +1,157 @@ +local global ={} +local Task = require 'utils.Task' +local Game = require "utils.game" +local Event = require "utils.event" +local Token = require 'utils.global_token' +local Utils = require 'utils.utils' + +global.walking = {} +global.walking_storage = {} + +--- Returns a player from walkabout after the timeout. +-- If the player is no longer logged in, store their info +-- in the global table walking_storage +local custom_commands_return_player = + Token.register( + function(args) + local player = args.player + local index = player.index + if not player.valid then + return + end + -- If walking is false it means they got cleaned by clean_on_join + if global.walking[index] == false then + return + end + + -- If the player is no longer connected, store that information. + if player.connected then + global.walking[index] = false + + local walkabout_character = player.character + if walkabout_character and walkabout_character.valid then + walkabout_character.destroy() + end + + local character = args.character + if character ~= nil and character.valid then + player.character = character + else + player.create_character() + player.teleport(args.position) + end + + player.force = args.force + + game.print(args.player.name .. ' came back from his walkabout.') + else + local data = {index = index, character = args.character, force = args.force, position = args.position} + table.insert(global.walking_storage, data) + end + end +) + +--- Sends a player on a walkabout: +-- They are teleported far away, placed on a neutral force, and are given a new character. +-- They are turned after the timeout by custom_commands_return_player +local function walkabout(cmd) + if game.player and not game.player.admin then + Utils.cant_run(cmd.name) + return + end + local params = {} + if cmd.parameter == nil then + Game.player_print('Walkabout failed, check /help walkabout.') + return + end + for param in string.gmatch(cmd.parameter, '%S+') do + table.insert(params, param) + end + local player_name = params[1] + local duration = 60 + if #params > 2 then + Game.player_print('Walkabout failed, check /help walkabout.') + return + elseif #params == 2 and tonumber(params[2]) == nil then + Game.player_print(params[2] .. ' is not a number.') + return + elseif #params == 2 and tonumber(params[2]) then + duration = tonumber(params[2]) + end + if duration < 15 then + duration = 15 + end + + local player = game.players[player_name] + if player == nil or not player.valid or global.walking[player.index] then + Game.player_print(player_name .. ' could not go on a walkabout.') + return + end + local chunks = {} + for chunk in player.surface.get_chunks() do + table.insert(chunks, chunk) + end + + local surface = player.surface + local chunk = surface.get_random_chunk() + local pos = {x = chunk.x * 32, y = chunk.y * 32} + local non_colliding_pos = surface.find_non_colliding_position('player', pos, 100, 1) + + local character = player.character + if character and character.valid then + character.walking_state = {walking = false} + end + + if non_colliding_pos then + game.print(player_name .. ' went on a walkabout, to find himself.') + Task.set_timeout( + duration, + custom_commands_return_player, + { + player = player, + force = player.force, + position = {x = player.position.x, y = player.position.y}, + character = character + } + ) + player.character = nil + player.create_character() + player.teleport(non_colliding_pos) + player.force = 'neutral' + global.walking[player.index] = true + else + Game.player_print('Walkabout failed: could not find non colliding position') + end +end + +--- Cleans the walkabout status off players who disconnected during walkabout. +-- Restores their original force, character, and position. +function clean_on_join(event) + local player = Game.get_player_by_index(event.player_index) + local index = player.index + if global.walking[index] then + global.walking[index] = false + for _, s in pairs (global.walking_storage) do + if s.index == index then + + local walkabout_character = player.character + if walkabout_character and walkabout_character.valid then + walkabout_character.destroy() + end + + local character = s.character + if character ~= nil and character.valid then + player.character = character + else + player.create_character() + player.teleport(s.position) + end + + player.force = s.force + end + end + end +end + +Event.add(defines.events.on_player_joined_game, clean_on_join) +commands.add_command('walkabout', ' - Send someone on a walk. (Admins only)', walkabout)