From 4b6872c14cf4b1ab474e80d2cddec05b5c21a887 Mon Sep 17 00:00:00 2001 From: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:59:46 +0000 Subject: [PATCH] Migrate all commands to new lib --- exp_legacy/module/config/_file_loader.lua | 41 - exp_legacy/module/config/chat_reply.lua | 4 +- .../config/expcore/command_auth_admin.lua | 19 - .../config/expcore/command_auth_roles.lua | 14 - .../config/expcore/command_color_parse.lua | 15 - .../config/expcore/command_general_parse.lua | 143 --- .../config/expcore/command_role_parse.lua | 56 -- .../expcore/command_runtime_disable.lua | 32 - exp_legacy/module/expcore/commands.lua | 895 ------------------ exp_legacy/module/expcore/gui/top_flow.lua | 2 +- exp_legacy/module/expcore/player_data.lua | 26 +- exp_legacy/module/expcore/roles.lua | 9 + exp_legacy/module/locale/en/commands.cfg | 245 ----- exp_legacy/module/locale/en/config.cfg | 3 - exp_legacy/module/locale/en/data.cfg | 4 + exp_legacy/module/locale/en/expcore.cfg | 28 +- exp_legacy/module/locale/en/gui.cfg | 19 + .../module/modules/addons/lawnmower.lua | 60 -- .../module/modules/commands/admin-chat.lua | 28 - .../module/modules/commands/admin-markers.lua | 88 -- .../module/modules/commands/artillery.lua | 81 -- .../module/modules/commands/bot-queue.lua | 25 - .../module/modules/commands/cheat-mode.lua | 46 - .../modules/commands/clear-inventory.lua | 28 - .../module/modules/commands/connect.lua | 107 --- exp_legacy/module/modules/commands/debug.lua | 14 - exp_legacy/module/modules/commands/enemy.lua | 30 - exp_legacy/module/modules/commands/find.lua | 19 - .../module/modules/commands/friendly-fire.lua | 19 - exp_legacy/module/modules/commands/help.lua | 95 -- exp_legacy/module/modules/commands/home.lua | 83 -- .../module/modules/commands/interface.lua | 117 --- exp_legacy/module/modules/commands/jail.lua | 48 - exp_legacy/module/modules/commands/kill.lua | 34 - .../module/modules/commands/last-location.lua | 20 - exp_legacy/module/modules/commands/me.lua | 17 - .../module/modules/commands/pollution.lua | 35 - exp_legacy/module/modules/commands/ratio.lua | 83 -- exp_legacy/module/modules/commands/repair.lua | 54 -- .../module/modules/commands/reports.lua | 99 -- .../module/modules/commands/research.lua | 45 - exp_legacy/module/modules/commands/roles.lua | 80 -- exp_legacy/module/modules/commands/search.lua | 170 ---- exp_legacy/module/modules/commands/spawn.lua | 66 -- .../module/modules/commands/spectate.lua | 33 - exp_legacy/module/modules/commands/speed.lua | 16 - .../modules/commands/surface-clearing.lua | 41 - .../module/modules/commands/teleport.lua | 93 -- exp_legacy/module/modules/commands/train.lua | 23 - exp_legacy/module/modules/commands/vlayer.lua | 15 - .../module/modules/commands/warnings.lua | 77 -- .../module/modules/commands/waterfill.lua | 80 -- .../module/modules/control/selection.lua | 4 +- exp_legacy/module/modules/control/warps.lua | 7 +- exp_legacy/module/modules/data/bonus.lua | 22 +- exp_legacy/module/modules/data/greetings.lua | 28 +- .../module/modules/data/personal-logistic.lua | 13 +- exp_legacy/module/modules/data/quickbar.lua | 13 +- exp_legacy/module/modules/data/tag.lua | 52 +- .../module/modules/factorio-control.lua | 2 + .../module/modules/graftorio/require.lua | 9 +- .../module/modules/gui/debug/main_view.lua | 2 +- .../modules/gui/debug/redmew_global_view.lua | 3 +- exp_legacy/module/modules/gui/module.lua | 9 +- exp_legacy/module/modules/gui/production.lua | 3 +- exp_legacy/module/modules/gui/research.lua | 16 +- exp_legacy/module/modules/gui/server-ups.lua | 10 +- exp_scenario/index.ts | 3 - .../{authorities.lua => _authorities.lua} | 6 +- exp_scenario/module/commands/_rcon.lua | 12 + .../module/commands/{types.lua => _types.lua} | 17 +- exp_scenario/module/commands/admin_chat.lua | 22 + exp_scenario/module/commands/artillery.lua | 96 ++ exp_scenario/module/commands/bot_queue.lua | 28 + exp_scenario/module/commands/cheat.lua | 132 +++ .../module/commands/clear_inventory.lua | 26 + exp_scenario/module/commands/connect.lua | 111 +++ exp_scenario/module/commands/debug.lua | 10 + exp_scenario/module/commands/enemy.lua | 30 + exp_scenario/module/commands/home.lua | 116 +++ exp_scenario/module/commands/jail.lua | 43 + exp_scenario/module/commands/kill.lua | 32 + exp_scenario/module/commands/lawnmower.lua | 52 + exp_scenario/module/commands/locate.lua | 40 + exp_scenario/module/commands/me.lua | 14 + .../module/commands/protected_entities.lua | 175 ++-- .../module/commands/protected_tags.lua | 112 +++ .../module}/commands/rainbow.lua | 49 +- exp_scenario/module/commands/ratio.lua | 54 ++ exp_scenario/module/commands/repair.lua | 60 ++ exp_scenario/module/commands/reports.lua | 107 +++ exp_scenario/module/commands/research.lua | 71 ++ exp_scenario/module/commands/roles.lua | 63 ++ exp_scenario/module/commands/search.lua | 181 ++++ exp_scenario/module/commands/spectate.lua | 29 + exp_scenario/module/commands/surface.lua | 89 ++ exp_scenario/module/commands/teleport.lua | 84 ++ exp_scenario/module/commands/trains.lua | 29 + exp_scenario/module/commands/vlayer.lua | 18 + exp_scenario/module/commands/warnings.lua | 96 ++ exp_scenario/module/commands/waterfill.lua | 69 ++ exp_scenario/module/control.lua | 38 +- exp_scenario/module/locale/en.cfg | 278 +++++- 103 files changed, 2415 insertions(+), 3694 deletions(-) delete mode 100644 exp_legacy/module/config/expcore/command_auth_admin.lua delete mode 100644 exp_legacy/module/config/expcore/command_auth_roles.lua delete mode 100644 exp_legacy/module/config/expcore/command_color_parse.lua delete mode 100644 exp_legacy/module/config/expcore/command_general_parse.lua delete mode 100644 exp_legacy/module/config/expcore/command_role_parse.lua delete mode 100644 exp_legacy/module/config/expcore/command_runtime_disable.lua delete mode 100644 exp_legacy/module/expcore/commands.lua delete mode 100644 exp_legacy/module/locale/en/commands.cfg delete mode 100644 exp_legacy/module/locale/en/config.cfg delete mode 100644 exp_legacy/module/modules/addons/lawnmower.lua delete mode 100644 exp_legacy/module/modules/commands/admin-chat.lua delete mode 100644 exp_legacy/module/modules/commands/admin-markers.lua delete mode 100644 exp_legacy/module/modules/commands/artillery.lua delete mode 100644 exp_legacy/module/modules/commands/bot-queue.lua delete mode 100644 exp_legacy/module/modules/commands/cheat-mode.lua delete mode 100644 exp_legacy/module/modules/commands/clear-inventory.lua delete mode 100644 exp_legacy/module/modules/commands/connect.lua delete mode 100644 exp_legacy/module/modules/commands/debug.lua delete mode 100644 exp_legacy/module/modules/commands/enemy.lua delete mode 100644 exp_legacy/module/modules/commands/find.lua delete mode 100644 exp_legacy/module/modules/commands/friendly-fire.lua delete mode 100644 exp_legacy/module/modules/commands/help.lua delete mode 100644 exp_legacy/module/modules/commands/home.lua delete mode 100644 exp_legacy/module/modules/commands/interface.lua delete mode 100644 exp_legacy/module/modules/commands/jail.lua delete mode 100644 exp_legacy/module/modules/commands/kill.lua delete mode 100644 exp_legacy/module/modules/commands/last-location.lua delete mode 100644 exp_legacy/module/modules/commands/me.lua delete mode 100644 exp_legacy/module/modules/commands/pollution.lua delete mode 100644 exp_legacy/module/modules/commands/ratio.lua delete mode 100644 exp_legacy/module/modules/commands/repair.lua delete mode 100644 exp_legacy/module/modules/commands/reports.lua delete mode 100644 exp_legacy/module/modules/commands/research.lua delete mode 100644 exp_legacy/module/modules/commands/roles.lua delete mode 100644 exp_legacy/module/modules/commands/search.lua delete mode 100644 exp_legacy/module/modules/commands/spawn.lua delete mode 100644 exp_legacy/module/modules/commands/spectate.lua delete mode 100644 exp_legacy/module/modules/commands/speed.lua delete mode 100644 exp_legacy/module/modules/commands/surface-clearing.lua delete mode 100644 exp_legacy/module/modules/commands/teleport.lua delete mode 100644 exp_legacy/module/modules/commands/train.lua delete mode 100644 exp_legacy/module/modules/commands/vlayer.lua delete mode 100644 exp_legacy/module/modules/commands/warnings.lua delete mode 100644 exp_legacy/module/modules/commands/waterfill.lua rename exp_scenario/module/commands/{authorities.lua => _authorities.lua} (69%) create mode 100644 exp_scenario/module/commands/_rcon.lua rename exp_scenario/module/commands/{types.lua => _types.lua} (83%) create mode 100644 exp_scenario/module/commands/admin_chat.lua create mode 100644 exp_scenario/module/commands/artillery.lua create mode 100644 exp_scenario/module/commands/bot_queue.lua create mode 100644 exp_scenario/module/commands/cheat.lua create mode 100644 exp_scenario/module/commands/clear_inventory.lua create mode 100644 exp_scenario/module/commands/connect.lua create mode 100644 exp_scenario/module/commands/debug.lua create mode 100644 exp_scenario/module/commands/enemy.lua create mode 100644 exp_scenario/module/commands/home.lua create mode 100644 exp_scenario/module/commands/jail.lua create mode 100644 exp_scenario/module/commands/kill.lua create mode 100644 exp_scenario/module/commands/lawnmower.lua create mode 100644 exp_scenario/module/commands/locate.lua create mode 100644 exp_scenario/module/commands/me.lua rename exp_legacy/module/modules/commands/protection.lua => exp_scenario/module/commands/protected_entities.lua (50%) create mode 100644 exp_scenario/module/commands/protected_tags.lua rename {exp_legacy/module/modules => exp_scenario/module}/commands/rainbow.lua (52%) create mode 100644 exp_scenario/module/commands/ratio.lua create mode 100644 exp_scenario/module/commands/repair.lua create mode 100644 exp_scenario/module/commands/reports.lua create mode 100644 exp_scenario/module/commands/research.lua create mode 100644 exp_scenario/module/commands/roles.lua create mode 100644 exp_scenario/module/commands/search.lua create mode 100644 exp_scenario/module/commands/spectate.lua create mode 100644 exp_scenario/module/commands/surface.lua create mode 100644 exp_scenario/module/commands/teleport.lua create mode 100644 exp_scenario/module/commands/trains.lua create mode 100644 exp_scenario/module/commands/vlayer.lua create mode 100644 exp_scenario/module/commands/warnings.lua create mode 100644 exp_scenario/module/commands/waterfill.lua diff --git a/exp_legacy/module/config/_file_loader.lua b/exp_legacy/module/config/_file_loader.lua index 8e7bf22a..452ba95a 100644 --- a/exp_legacy/module/config/_file_loader.lua +++ b/exp_legacy/module/config/_file_loader.lua @@ -8,44 +8,6 @@ return { "modules.factorio-control", -- base factorio free play scenario "expcore.player_data", -- must be loaded first to register event handlers - --- Game Commands - "modules.commands.debug", - "modules.commands.me", - "modules.commands.kill", - "modules.commands.admin-chat", - "modules.commands.admin-markers", - "modules.commands.teleport", - "modules.commands.cheat-mode", - "modules.commands.ratio", - "modules.commands.interface", - "modules.commands.help", - "modules.commands.roles", - "modules.commands.rainbow", - "modules.commands.clear-inventory", - "modules.commands.jail", - "modules.commands.repair", - "modules.commands.reports", - "modules.commands.spawn", - "modules.commands.warnings", - "modules.commands.find", - "modules.commands.home", - "modules.commands.connect", - "modules.commands.last-location", - "modules.commands.protection", - "modules.commands.spectate", - "modules.commands.search", - "modules.commands.bot-queue", - "modules.commands.speed", - "modules.commands.pollution", - "modules.commands.train", - "modules.commands.friendly-fire", - "modules.commands.research", - "modules.commands.vlayer", - "modules.commands.enemy", - "modules.commands.waterfill", - "modules.commands.artillery", - "modules.commands.surface-clearing", - --- Addons "modules.addons.chat-popups", "modules.addons.damage-popups", @@ -104,9 +66,6 @@ return { "modules.gui.toolbar", -- must be loaded last to register toolbar handlers --- Config Files - "config.expcore.command_auth_admin", -- commands tagged with admin_only are blocked for non admins - "config.expcore.command_auth_roles", -- commands must be allowed via the role config - "config.expcore.command_runtime_disable", -- allows commands to be enabled and disabled during runtime "config.expcore.permission_groups", -- loads some predefined permission groups "config.expcore.roles", -- loads some predefined roles } diff --git a/exp_legacy/module/config/chat_reply.lua b/exp_legacy/module/config/chat_reply.lua index 36ba39fc..4a1cd6e8 100644 --- a/exp_legacy/module/config/chat_reply.lua +++ b/exp_legacy/module/config/chat_reply.lua @@ -80,8 +80,8 @@ return { local options = { "?", ".", "!", "!!!" } return { "chat-bot.hodor", table.get_random(options) } end, - ["evolution"] = function(_player, _is_command) - return { "chat-bot.current-evolution", string.format("%.2f", game.forces["enemy"].evolution_factor) } + ["evolution"] = function(player, _is_command) + return { "chat-bot.current-evolution", string.format("%.2f", game.forces["enemy"].get_evolution_factor(player.surface)) } end, ["makepopcorn"] = function(player, _is_command) local timeout = math.floor(180 * (math.random() + 0.5)) diff --git a/exp_legacy/module/config/expcore/command_auth_admin.lua b/exp_legacy/module/config/expcore/command_auth_admin.lua deleted file mode 100644 index be582f44..00000000 --- a/exp_legacy/module/config/expcore/command_auth_admin.lua +++ /dev/null @@ -1,19 +0,0 @@ ---- This is a very simple config file which adds a admin only auth function; --- not much to change here its more so it can be enabled and disabled from ./config/file_loader.lua; --- either way you can change the requirements to be "admin" if you wanted to --- @config Commands-Auth-Admin - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands - --- luacheck:ignore 212/command -Commands.add_authenticator(function(player, command, tags, reject) - if tags.admin_only then - if player.admin then - return true - else - return reject{ "command-auth.admin-only" } - end - else - return true - end -end) diff --git a/exp_legacy/module/config/expcore/command_auth_roles.lua b/exp_legacy/module/config/expcore/command_auth_roles.lua deleted file mode 100644 index 388c6e18..00000000 --- a/exp_legacy/module/config/expcore/command_auth_roles.lua +++ /dev/null @@ -1,14 +0,0 @@ ---- This will make commands only work if the role has been allowed it in the role config --- @config Commands-Auth-Roles - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles - --- luacheck:ignore 212/tags -Commands.add_authenticator(function(player, command, tags, reject) - if Roles.player_allowed(player, "command/" .. command) then - return true - else - return reject() - end -end) diff --git a/exp_legacy/module/config/expcore/command_color_parse.lua b/exp_legacy/module/config/expcore/command_color_parse.lua deleted file mode 100644 index 0066c3d6..00000000 --- a/exp_legacy/module/config/expcore/command_color_parse.lua +++ /dev/null @@ -1,15 +0,0 @@ ---- This will make commands only work when a valid color from the presets has been selected --- @config Commands-Color-Parse - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Colours = require("modules/exp_util/include/color") - -Commands.add_parse("color", function(input, _, reject) - if not input then return end - local color = Colours[input] - if not color then - return reject{ "expcore-commands.reject-color" } - else - return input - end -end) diff --git a/exp_legacy/module/config/expcore/command_general_parse.lua b/exp_legacy/module/config/expcore/command_general_parse.lua deleted file mode 100644 index 7502cec7..00000000 --- a/exp_legacy/module/config/expcore/command_general_parse.lua +++ /dev/null @@ -1,143 +0,0 @@ ---[[-- This file contains some common command param parse functions; -this file is less of a config and more of a requirement but you may wish to change how some behave; -as such you need to be confident with lua but you edit this config file; -use Commands.add_parse('name',function(input, player, reject) end) to add a parse; -see ./expcore/commands.lua for more details -@config Commands-Parse -@usage Adds Parses: - boolean - string-options - options: array - string-max-length - max_length: number - number - integer - number-range - range_min: number, range_max: number - integer-range - range_min: number, range_max: number - player - player-online - player-alive - force - surface -]] - -local ExpUtil = require("modules/exp_util") -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands - --- luacheck:ignore 212/player -Commands.add_parse("boolean", function(input, player) - if not input then return end -- nil check - input = input:lower() - if input == "yes" - or input == "y" - or input == "true" - or input == "1" then - return true - else - return false - end -end) - -Commands.add_parse("string-options", function(input, player, reject, options) - if not input then return end -- nil check - local option = ExpUtil.auto_complete(options, input) - return option or reject{ "expcore-commands.reject-string-options", table.concat(options, ", ") } -end) - -Commands.add_parse("string-max-length", function(input, player, reject, max_length) - if not input then return end -- nil check - local length = input:len() - if length > max_length then - return reject{ "expcore-commands.reject-string-max-length", max_length } - else - return input - end -end) - -Commands.add_parse("number", function(input, player, reject) - if not input then return end -- nil check - local number = tonumber(input) - if not number then - return reject{ "expcore-commands.reject-number" } - else - return number - end -end) - -Commands.add_parse("integer", function(input, player, reject) - if not input then return end -- nil check - local number = tonumber(input) - if not number then - return reject{ "expcore-commands.reject-number" } - else - return math.floor(number) - end -end) - -Commands.add_parse("number-range", function(input, player, reject, range_min, range_max) - local number = Commands.parse("number", input, player, reject) - if not number then return end -- nil check - if number < range_min or number > range_max then - return reject{ "expcore-commands.reject-number-range", range_min, range_max } - else - return number - end -end) - -Commands.add_parse("integer-range", function(input, player, reject, range_min, range_max) - local number = Commands.parse("integer", input, player, reject) - if not number then return end -- nil check - if number < range_min or number > range_max then - return reject{ "expcore-commands.reject-number-range", range_min, range_max } - else - return number - end -end) - -Commands.add_parse("player", function(input, player, reject) - if not input then return end -- nil check - local input_player = game.players[input] - if not input_player then - return reject{ "expcore-commands.reject-player", input } - else - return input_player - end -end) - -Commands.add_parse("player-online", function(input, player, reject) - local input_player = Commands.parse("player", input, player, reject) - if not input_player then return end -- nil check - if not input_player.connected then - return reject{ "expcore-commands.reject-player-online" } - else - return input_player - end -end) - -Commands.add_parse("player-alive", function(input, player, reject) - local input_player = Commands.parse("player-online", input, player, reject) - if not input_player then return end -- nil check - if not input_player.character or not input_player.character.health or input_player.character.health <= 0 then - return reject{ "expcore-commands.reject-player-alive" } - else - return input_player - end -end) - -Commands.add_parse("force", function(input, player, reject) - if not input then return end -- nil check - local force = game.forces[input] - if not force then - return reject{ "expcore-commands.reject-force" } - else - return force - end -end) - -Commands.add_parse("surface", function(input, player, reject) - if not input then return end - local surface = game.surfaces[input] - if not surface then - return reject{ "expcore-commands.reject-surface" } - else - return surface - end -end) diff --git a/exp_legacy/module/config/expcore/command_role_parse.lua b/exp_legacy/module/config/expcore/command_role_parse.lua deleted file mode 100644 index 6dedd8de..00000000 --- a/exp_legacy/module/config/expcore/command_role_parse.lua +++ /dev/null @@ -1,56 +0,0 @@ ---[[-- Adds some parse functions that can be used with the role system -@config Commands-Parse-Roles -@usage Adds Parses: - role - player-role - player-role-online - player-role-alive -]] - -local ExpUtil = require("modules/exp_util") -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles -local auto_complete = ExpUtil.auto_complete --- @dep expcore.common -require("modules.exp_legacy.config.expcore.command_general_parse") - --- luacheck:ignore 212/player -Commands.add_parse("role", function(input, player, reject) - if not input then return end - local roles = Roles.config.order - local rev_roles = {} - for i = #roles, 1, -1 do - table.insert(rev_roles, roles[i]) - end - - local role = auto_complete(rev_roles, input) - role = Roles.get_role_by_name(role) - if not role then - return reject{ "expcore-role.reject-role" } - else - return role - end -end) - -Commands.add_parse("player-role", function(input, player, reject) - local input_player = Commands.parse("player", input, player, reject) - if not input_player then return end -- nil check - local player_highest = Roles.get_player_highest_role(player) - local input_player_highest = Roles.get_player_highest_role(input_player) - if player_highest.index < input_player_highest.index then - return input_player - else - return reject{ "expcore-roles.reject-player-role" } - end -end) - -Commands.add_parse("player-role-online", function(input, player, reject) - local input_player = Commands.parse("player-role", input, player, reject) - if not input_player then return end -- nil check - return Commands.parse("player-online", input_player.name, player, reject) -end) - -Commands.add_parse("player-role-alive", function(input, player, reject) - local input_player = Commands.parse("player-role", input, player, reject) - if not input_player then return end -- nil check - return Commands.parse("player-alive", input_player.name, player, reject) -end) diff --git a/exp_legacy/module/config/expcore/command_runtime_disable.lua b/exp_legacy/module/config/expcore/command_runtime_disable.lua deleted file mode 100644 index 65cec329..00000000 --- a/exp_legacy/module/config/expcore/command_runtime_disable.lua +++ /dev/null @@ -1,32 +0,0 @@ ---- This config for command auth allows commands to be globally enabled and disabled during runtime; --- this config adds Commands.disable and Commands.enable to enable and disable commands for all users --- @config Commands-Auth-Runtime-Disable - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Storage = require("modules/exp_util/storage") - -local disabled_commands = {} -Storage.register(disabled_commands, function(tbl) - disabled_commands = tbl -end) - ---- Stops a command from be used by any one --- @tparam string command_name the name of the command to disable -function Commands.disable(command_name) - disabled_commands[command_name] = true -end - ---- Allows a command to be used again after disable was used --- @tparam string command_name the name of the command to enable -function Commands.enable(command_name) - disabled_commands[command_name] = nil -end - --- luacheck:ignore 212/player 212/tags -Commands.add_authenticator(function(player, command, tags, reject) - if disabled_commands[command] then - return reject{ "command-auth.command-disabled" } - else - return true - end -end) diff --git a/exp_legacy/module/expcore/commands.lua b/exp_legacy/module/expcore/commands.lua deleted file mode 100644 index 252f9240..00000000 --- a/exp_legacy/module/expcore/commands.lua +++ /dev/null @@ -1,895 +0,0 @@ ---[[-- Core Module - Commands -- Factorio command making module that makes commands with better parse and more modularity -@core Commands -@alias Commands - -@usage--- Full code example, see below for explanation -Commands.new_command('repeat-name', 'Will repeat you name a number of times in chat.') -:add_param('repeat-count', 'number-range-int', 1, 5) -- required int in range 1 to 5 inclusive -:add_param('smiley', true, function(input, player, reject) -- optional boolean default false - if not input then return end - input = input:lower() - if input == 'true' or input == 'yes' then return true end - return false -end) -:set_defaults{ smiley = false } -:set_flag('admin_only') -- command is admin only -:add_alias('name', 'rname') -- allow alias: name and rname -:register(function(player, repeat_count, smiley, raw) - game.print(player.name..' used a command with input: '..raw) - - local msg = ') '..player.name - if smiley then - msg = ':'..msg - end - - for 1 = 1, repeat_count do - Command.print(1..msg) - end -end) - -@usage--- Example Command Explanation: --- Making commands basics, the commands can be set up with any number of params and flags that you want, --- you can add aliases for the commands and set default values for optional params and of course register your command callback. --- In our example we will have a command that will repeat the users name in chat X amount of times and only allow admins to use it. - --- First we create the new command, note this will not register the command to the game this is done at the end. --- We will call the command "repeat-name" and set the help message as follows: -Commands.new_command('repeat-name', 'Will repeat you name a number of times in chat.') - --- Now for our first param, we have named it "repeat-count" and it will be a required value, between 1 and 5 inclusive: --- By using "number-range-int" we are saying to use this parser to convert our input text, common ones exist in config.expcore.command_general_parse -:add_param('repeat-count', 'number-range-int', 1, 5) - --- Our second param needs a custom parser, meaning it isnt defined with add_parser, this is an option for when it is unlikely for --- any other command to use the same input type. In the example it is a boolean type and we are just showing it here as part of the example. --- As for the param its self it will be called "smiley" and will be optional with a default value of false: -:add_param('smiley', true, function(input, player, reject) - -- Since it is optional the input can be nil, in which case we just return - if not input then return end - -- If it is not nil then we check for a truthy value - if input == 'true' or input == 'yes' then return true end - -- Note that because we did not return nil or reject then false will be passed to command callback, see example parse - return false -end) - --- Once all params are defined you can add some default values for your optional params, the default value will be used only --- when no value is given as input, if an invalid value is given then the command will fail and the default will not be used, the --- default can also be a function which is passed the player as an argument and should return a value to be the default. --- Here we set the default for "smiley" to false: -:set_defaults{smiley=false} - --- Another example of defaults if we have: item, amount[opt], player[opt] -:set_defaults{ - amount = 50, -- More than one value can be set at a time - player = function(player) return player end -- Default is the player using the command -} - --- Now the params are set up we can alter how the command works, we can set auth flags, add aliases, or enable "auto concat": -:set_flag('admin_only') -- In our case we want "admin_only" to be set to true so only admins can use the command -:add_alias('name', 'rname') -- We also add two aliases here: "name" and "rname" which point to this command --- :enable_auto_concat() -- We do not use this in our case but this can also be used to enable the "auto concat" feature - --- And finally we want to register a callback to this command, the callback is what defines what the command does, can be as complex as you --- want it to be, or as simple as our example; the command receives two params plus all param you have defined: --- 1) the player who used the command --- 2) in our case repeat_count which will be a number --- 3) in our case smiley which will be a boolean --- 4) the raw input; this param is always last as is always present as a catch all -:register(function(player, repeat_count, smiley, raw) - -- This is to show the value for raw as this is an example command, the log file will also show this - game.print(player.name..' used a command with input: '..raw) - local msg = ') '..player.name - - if smiley then - msg = ':'..msg - end - - for 1 = 1, repeat_count do - -- this print function will return ANY value to the user in a desync safe manor, this includes if the command was used through rcon - Command.print(1..msg) - end - -- See below for what can be used here -end) - --- Values that can be returned from register callback -Commands.print(any, colour[opt]) -- This will return any value value to the user including if it is ran through rcon console -Commands.error(message[opt]) -- This returns a warning to the user, aka an error that does not prevent execution of the command -return Commands.error(message[opt]) -- This returns an error to the user, and will halt the command execution, ie no success message is returned -Commands.success(message[opt]) -- Used to return a success message however don't use this method, see below -return Commands.success(message[opt]) -- Will return the success message to the user and your given message, halts execution -return -- If any value is returned then it will be returned to the player via a Commands.success call - -@usage--- Example Authenticator: --- The command system is best used when you can control who uses commands; --- to do this you need to define an authenticator which is ran every time a command is run; --- in this example I will show a simple one that requires certain commands to require the user to be a game admin. - --- For our admin only example we will set a flag to true when we want it to be admin only; --- when we define the command will will use :set_flag('admin_only'); --- then inside the authenticator we will test if the flag is present using: if flags.admin_only then - --- When the authenticator is called by the command handler it will be passed 4 arguments: --- 1) player - the player who used the command --- 2) command - the name of the command that is being used --- 3) flags - the flags which have been set for this command, flags are set with :set_flag(name, value) --- 4) reject - the reject function which is the preferred method to prevent execution of the command - --- No return is required to allow the command to execute but it is best practice to return true; --- we do this in two cases in our authenticator: --- 1) when the "admin_only" flag is not set, which we take assume that any one can use it --- 2) when the "admin_only" flag is set, and the player is admin - --- When want to prevent execution of the command we must reject it, listed is how that can be done: --- 1) return false -- this is the most basic rejection and should only be used while testing --- 2) return reject -- returning the reject function is as a fail safe in case you forget to call it, same as returning false --- 3) reject() -- this will block execution while allowing further code to be ran in your authenticator --- 4) reject('This command is for admins only!') -- using reject as a function allows a error message to be returned --- 5) return reject() -- using return on either case above is best practice as you should execute all your code before rejecting - --- Example Code: -Commands.add_authenticator(function(player, command, flags, reject) - -- Check if the command is admin only - if flags.admin_only then - -- Return true if player is admin, or reject and return error message - return player.admin or reject('This command is for admins only!') - else - -- Return true if command was not admin only - return true - end -end) - -@usage--- Example Parser: --- Before you make a command it is important to understand the most powerful feature of this command handler; --- when you define a command you are able to type the params and have then be parsed and validated before your command is executed; --- This module should be paired with a general command parse but you may want to create your own. - --- For our example we will create a parse to accept only integer numbers in a given range: --- 1) we will give it the name "number-range-int" this is the "type" that the input is expected to be --- 2) when we define the type we will also define the min and max of the range so we can use the function more than once -:add_param('repeat_count', 'number-range-int', 5, 10) -- "repeat_count" is a required "number-range-int" in a range 5 to 10 inclusive - --- The command parse will be passed 3 arguments plus any other which you define, in our case: --- 1) input - the input that has been given by the user for this param, the role of this function is to transform this value --- nb: the input is a string but can be nil if the param is marked as optional --- 2) player - the player who is using the command, this is always present --- 3) reject - the reject function to throw an error to the user, this is always present --- 4) range_min - the range min, this is user defined and has the value given when the param is defined --- 5) range_max - the range max, this is user defined and has the value given when the param is defined - --- When returning from the param parse you have a few options with how to do this: --- 1) you return the new value for the param (any non nil value) this value is then passed to the command callback --- 2) not returning will cause a generic invalid error and the command is rejected, not recommenced --- 3) return reject -- this is just a failsafe in case the function is not called, same as no return --- 4) return reject() -- will give a shorter error message as you pass a nil custom error --- 5) return reject('Number entered is not in range: '..range_min..', '..range_max) -- returns a custom error to the user --- nb: if you do not return reject after you call it then you will still be returning nil so there will be a duplicate error message - --- It should be noted that if you want to expand on an existing parse you can use Commands.parse(type, input, player, reject) --- this function will either return a new value for the input or nil, if it is nil you should return nil to prevent duplicate --- error messages to the user: -input = Commands.parse('number-int', input, player, reject) -if not input then return end -- nil check - --- Example Code: -Commands.add_parse('number-range-int', function(input, player, reject, range_min, range_max) - local rtn = tonumber(input) and math.floor(tonumber(input)) or nil -- converts input to number - if not rtn or rtn < range_min or rtn > range_max then - -- the input is either not a number or is outside the range - return reject('Number entered is not in range: '..range_min..', '..range_max) - else - -- returns the input as a number value rather than a string, thus the param is now the correct type - return rtn - end -end) - -]] - -local ExpUtil = require("modules/exp_util") -local write_json = ExpUtil.write_json --- @dep expcore.common -local trace = debug.traceback - -local Commands = { - --- Constant values used by the command system - defines = { - error = "CommandError", - unauthorized = "CommandErrorUnauthorized", - success = "CommandSuccess", - }, - --- An array of all custom commands that are registered - commands = {}, - --- When true any authenticator error will result in authorization failure, more secure - authorization_failure_on_error = false, - --- An array of all custom authenticators that are registered - authenticators = {}, - --- Used to store default functions which are common parse function such as player or number in range - parsers = {}, - --- The command prototype which stores all command defining functions - _prototype = {}, -} - -local Colours = ExpUtil.color ---- This is copied in so that _C.player_return can be removed ---- Returns a value to the player, different to success as this does not signal the end of your command -function Commands.print(value, colour, player) - colour = type(colour) == "table" and colour or Colours[colour] ~= Colours.white and Colours[colour] or Colours.white - player = player or game.player - local output = ExpUtil.format_any(value) - if player then - player = type(player) == "userdata" and player or game.get_player(player) - if not player then error("Invalid Player given to Commands.print", 2) end - player.print(output, { - color = colour, - sound_path = "utility/scenario_message", - }) - else - rcon.print(output) - end -end - ---- Authentication. --- Functions that control who can use commands --- @section auth - ---[[-- Adds an authorization function, function used to check if a player if allowed to use a command -@tparam function authenticator The function you want to register as an authenticator -@treturn number The index it was inserted at, used to remove the authenticator - -@usage-- If the admin_only flag is set, then make sure the player is an admin -local admin_authenticator = -Commands.add_authenticator(function(player, command, flags, reject) - if flags.admin_only and not player.admin then - return reject('This command is for admins only!') - else - return true - end -end) - -]] -function Commands.add_authenticator(authenticator) - local next_index = #Commands.authenticators + 1 - Commands.authenticators[next_index] = authenticator - return next_index -end - ---[[-- Removes an authorization function, can use the index or the function value -@tparam function|number authenticator The authenticator to remove, either the index return from add_authenticator or the function used -@treturn boolean If the authenticator was found and removed successfully - -@usage-- Removing the admin authenticator, can not be done during runtime -Commands.remove_authenticator(admin_authenticator) - -]] -function Commands.remove_authenticator(authenticator) - if type(authenticator) == "number" then - -- If a number is passed then it is assumed to be the index - if Commands.authenticators[authenticator] then - Commands.authenticators[authenticator] = nil - return true - end - else - -- will search the array and remove the key - for index, value in pairs(Commands.authenticators) do - if value == authenticator then - Commands.authenticators[index] = nil - return true - end - end - end - return false -end - ---[[-- Mostly used internally, calls all authenticators, returns if the player is authorized -@tparam LuaPlayer player The player who is using the command, passed to authenticators -@tparam string command_name The name of the command being used, passed to authenticators -@treturn[1] boolean true Player is authorized -@treturn[1] string commands Define value for success -@treturn[2] boolean false Player is unauthorized -@treturn[2] string|locale_string The reason given by the failed authenticator - -@usage-- Test if a player can use "repeat-name" -local authorized, status = Commands.authorize(game.player, 'repeat-name') - -]] -function Commands.authorize(player, command_name) - local command_data = Commands.commands[command_name] - if not command_data then return false end - if not player then return true end - - -- This is the reject function given to authenticators - local failure_message - local function reject(message) - failure_message = message or { "expcore-commands.unauthorized" } - return Commands.defines.unauthorized - end - - -- This is the internal error function used when an authenticator errors - local function authenticator_error(err) - log("[ERROR] Authorization failed: " .. trace(err)) - if Commands.authorization_failure_on_error then - return reject("Internal Error") - end - end - - -- Loops over each authenticator, if any return false then then command will not be ran - for _, authenticator in pairs(Commands.authenticators) do - -- player: LuaPlayer, command: string, flags: table, reject: function(error_message: string) - local _, rtn = xpcall(authenticator, authenticator_error, player, command_name, command_data.flags, reject) - if rtn == false or rtn == Commands.defines.unauthorized or rtn == reject or failure_message ~= nil then - if failure_message == nil then failure_message = { "expcore-commands.unauthorized" } end - return false, failure_message - end - end - - return true, Commands.defines.success -end - ---- Parse. --- Functions that help with parsing --- @section parse - ---[[-- Adds a parse function which can be called by name (used in add_param) -nb: this is not required as you can use the callback directly this just allows it to be called by name -@tparam string name The name of the parse, should describe a type of input such as number or player, must be unique -@tparam function parser The function that is ran to parse the input string -@treturn boolean Was the parse added, will be false if the name is already used - -@usage-- Adding a parse to validate integers in a given range -Commands.add_parse('number-range-int', function(input, player, reject, range_min, range_max) - local rtn = tonumber(input) and math.floor(tonumber(input)) or nil -- converts input to number - if not rtn or rtn < range_min or rtn > range_max then - -- The input is either not a number or is outside the range - return reject('Number entered is not in range: '..range_min..', '..range_max) - else - -- Returns the input as a number rather than a string, thus the param is now the correct type - return rtn - end -end) - -]] -function Commands.add_parse(name, parser) - if Commands.parsers[name] then return false end - Commands.parsers[name] = parser - return true -end - ---[[-- Removes a parse function, see add_parse for adding them, cant be done during runtime -@tparam string name The name of the parse to remove - -@usage-- Removing a parse -Commands.remove_parse('number-range-int') - -]] -function Commands.remove_parse(name) - Commands.parsers[name] = nil -end - ---[[-- Intended to be used within other parse functions, runs a parse and returns success and new value -@tparam string name The name of the parse to call, must be a registered parser -@tparam string input The input to pass to the parse, must be a string but not necessarily the original input -@tparam LuaPlayer player The player that is using the command, pass directly from your arguments -@tparam function reject The reject function, pass directly from your arguments -@treturn any The new value for the input, if nil is return then either there was an error or the input was nil - -@usage-- Parsing an int after first checking it is a number -Commands.add_parse('number', function(input, player, reject) - local number = tonumber(input) - if number then return number end - return reject('Input must be a number value') -end) - -Commands.add_parse('number-int', function(input, player, reject) - local number = Commands.parse('number', input, player, reject) - if not number then return end - return math.floor(number) -end) - -]] -function Commands.parse(name, input, player, reject, ...) - if not Commands.parsers[name] then return end - local success, rtn = pcall(Commands.parsers[name], input, player, reject, ...) - if not success then - error(rtn, 2) - return - end - if not rtn or rtn == Commands.defines.error then return end - return rtn -end - ---- Getters. --- Functions that get commands --- @section getters - ---[[-- Gets all commands that a player is allowed to use, game commands are not included -@tparam[opt] LuaPlayer player The player that you want to get commands of, nil will return all commands -@treturn table All commands that that player is allowed to use, or all commands - -@usage-- Get the commands you are allowed to use -local commands = Commands.get(game.player) - -@usage-- Get all commands that are registered -local commands = Commands.get() - -]] -function Commands.get(player) - if not player then return Commands.commands end - local allowed = {} - for name, command_data in pairs(Commands.commands) do - if Commands.authorize(player, name) then - allowed[name] = command_data - end - end - - return allowed -end - ---[[-- Searches command names and help messages to find possible commands, game commands are included -@tparam string keyword The word which you are trying to find in your search -@tparam[opt] LuaPlayer player The player to get allowed commands of, if nil all commands are searched -@treturn table All commands that contain the key word, and allowed by the player if a player was given - -@usage-- Get all commands which "repeat" -local commands = Commands.search('repeat') - -@usage-- Get all commands which "repeat" and you are allowed to use -local commands = Commands.search('repeat', game.player) - -]] -function Commands.search(keyword, player) - local custom_commands = Commands.get(player) - local matches = {} - keyword = keyword:lower() - -- Loops over custom commands - for name, command_data in pairs(custom_commands) do - -- combines name help and aliases into one message to be searched - local search = string.format("%s %s %s %s", name, command_data.help, command_data.searchable_description, table.concat(command_data.aliases, " ")) - - if search:lower():match(keyword) then - matches[name] = command_data - end - end - - -- Loops over the names of game commands - for name, description in pairs(commands.game_commands) do - if name:lower():match(keyword) then - -- because game commands lack some stuff that the custom ones have they are formatted - matches[name] = { - name = name, - help = description, - description = "", - aliases = {}, - } - end - end - - return matches -end - ---- Creation. --- Functions that create a new command --- @section creation - ---[[-- Creates a new command object to added details to, this does not register the command to the game api -@tparam string name The name of the command to be created -@tparam string help The help message for the command -@treturn table This will be used with other functions to define the new command - -@usage-- Define a new command -Commands.new_command('repeat-name', 'Will repeat you name a number of times in chat.') - -]] -function Commands.new_command(name, help, descr) - local command = setmetatable({ - name = name, - help = help, - searchable_description = descr or "", - callback = function() Commands.internal_error(false, name, "No callback registered") end, - auto_concat = false, - min_param_count = 0, - max_param_count = 0, - flags = {}, -- stores flags that can be used by auth - aliases = {}, -- stores aliases to this command - params = {}, -- [param_name] = {optional: boolean, default: any, parse: function, parse_args: table} - }, { - __index = Commands._prototype, - }) - Commands.commands[name] = command - return command -end - ---[[-- Adds a new param to the command this will be displayed in the help and used to parse the input -@tparam string name The name of the new param that is being added to the command -@tparam[opt=false] boolean optional Is this param optional, these must be added after all required params -@tparam[opt] ?string|function parse This function will take the input and return a new value, if not given no parse is done -@tparam[opt] any ... Extra args you want to pass to the parse function; for example if the parse is general use -@treturn table Pass through to allow more functions to be called - -@usage-- Adding a required param which has a parser pre-defined -command:add_param('repeat-count', 'number-range-int', 1, 5) - -@usage-- Adding an optional param which has a custom parse, see Commands.add_parse for details -command:add_param('smiley', true, function(input, player, reject) - if not input then return end - return input:lower() == 'true' or input:lower() == 'yes' or false -end) - -]] -function Commands._prototype:add_param(name, optional, parse, ...) - local parse_args = { ... } - if type(optional) ~= "boolean" then - parse_args = { parse, ... } - parse = optional - optional = false - end - - self.params[name] = { - optional = optional, - parse = parse or function(string) return string end, - parse_args = parse_args, - } - - self.max_param_count = self.max_param_count + 1 - if not optional then - self.min_param_count = self.min_param_count + 1 - end - - return self -end - ---[[-- Add default values to params, only as an effect if the param is optional, if default value is a function it is called with the acting player -@tparam table defaults A table which is keyed by the name of the param and the value is the default value for that param -@treturn table Pass through to allow more functions to be called - -@usage-- Adding default values -command:set_defaults{ - smiley = false, - -- not in example just used to show arguments given - player_name = function(player) - return player.name - end -} - -]] -function Commands._prototype:set_defaults(defaults) - for name, value in pairs(defaults) do - if self.params[name] then - self.params[name].default = value - end - end - - return self -end - ---[[-- Adds a flag to the command which is passed via the flags param to the authenticators, can be used to assign command roles or usage type -@tparam string name The name of the flag to be added, set to true if no value is given -@tparam[opt=true] any value The value for the flag, can be anything that the authenticators are expecting -@treturn table Pass through to allow more functions to be called - -@usage-- Setting a custom flag -command:set_flag('admin_only', true) - -@usage-- When value is true it does not need to be given -command:set_flag('admin_only') - -]] -function Commands._prototype:set_flag(name, value) - self.flags[name] = value or true - return self -end - ---[[-- Adds an alias, or multiple, that will be registered to this command, eg /teleport can be used as /tp -@tparam string ... Any amount of aliases that you want this command to be callable with -@treturn table Pass through to allow more functions to be called - -@usage-- Added multiple aliases to a command -command:add_alias('name', 'rname') - -]] -function Commands._prototype:add_alias(...) - local start_index = #self.aliases - for index, alias in ipairs{ ... } do - self.aliases[start_index + index] = alias - end - - return self -end - ---[[-- Enables auto concatenation for this command, all params after the last are added to the last param, useful for reasons or other long text input -nb: this will disable max param checking as they will be concatenated onto the end of that last param -@treturn table Pass through to allow more functions to be called - -@usage-- Enable auto concat for a command -command:enable_auto_concat() - -]] -function Commands._prototype:enable_auto_concat() - self.auto_concat = true - return self -end - ---[[-- Adds the callback to the command and registers: aliases, params and help message with the base game api -nb: this must be the last function ran on the command and must be done for the command to work -@tparam function callback The callback for the command, will receive the player running command, and any params added with add_param - -@usage-- Registering your command to the base game api -command:register(function(player, repeat_count, smiley, raw) - local msg = ') '..player.name - if smiley then msg = ':'..msg end - - for 1 = 1, repeat_count do - Command.print(1..msg) - end -end) - -]] -function Commands._prototype:register(callback) - self.callback = callback - - -- Generates a description to be used - local description = "" - for param_name, param_details in pairs(self.params) do - if param_details.optional then - description = string.format("%s [%s]", description, param_name) - else - description = string.format("%s <%s>", description, param_name) - end - end - - self.description = description - - -- Last resort error handler for commands - local function command_error(err) - Commands.internal_error(false, self.name, trace(err)) - end - - -- Callback that the game will call - local function command_callback(event) - event.name = self.name - xpcall(Commands.run_command, command_error, event) - end - - -- Registers the command under its own name - local help = { "expcore-commands.command-help", description, self.help } - commands.add_command(self.name, help, command_callback) - - -- Adds any aliases that it has - for _, alias in pairs(self.aliases) do - if not commands.commands[alias] and not commands.game_commands[alias] then - commands.add_command(alias, help, command_callback) - end - end -end - ---- Status. --- Functions that indicate status --- @section status - ---[[-- Sends a value to the player, followed by a command complete message, returning a value will trigger this automatically -@tparam[opt] any value The value to return to the player, if nil then only the success message is returned -@treturn Commands.defines.success Return this to the command handler to prevent two success messages - -@usage-- Print a custom success message -return Commands.success('Your message has been printed') - -@usage-- Returning the value has the same result -return 'Your message has been printed' - -]] -function Commands.success(value) - if value ~= nil then Commands.print(value) end - Commands.print({ "expcore-commands.command-ran" }, "cyan") - return Commands.defines.success -end - ---[[-- Sends a value to the player, different to success as this does not signal the end of your command -@function print -@tparam any value The value that you want to return to the player -@tparam table colour The colour of the message that the player sees - -@usage-- Output a message to the player -Commands.print('Your command is in progress') - -]] - ---[[-- Sends an error message to the player and when returned will stop execution of the command -nb: this is for non fatal errors meaning there is no log of this event, use during register callback -@tparam[opt=''] string error_message An optional error message that can be sent to the user -@tparam[opt=utility/wire_pickup] string play_sound The sound to play for the error -@treturn Commands.defines.error Return this to command handler to terminate execution - -@usage-- Send an error message to the player, and stops further code running -return Commands.error('The player you selected is offline') - -]] -function Commands.error(error_message, play_sound) - error_message = error_message or "" - Commands.print({ "expcore-commands.command-fail", error_message }, "orange_red") - if play_sound ~= false then - play_sound = play_sound or "utility/wire_pickup" - if game.player then game.player.play_sound{ path = play_sound } end - end - return Commands.defines.error -end - ---[[-- Sends an error to the player and logs the error, used internally please avoid direct use -nb: use error(error_message) within your callback to trigger do not trigger directly as code execution may still continue -@tparam boolean success The success value returned from pcall, or just false to trigger error -@tparam string command_name The name of the command this is used within the log -@tparam string error_message The error returned by pcall or some other error, this is logged and not returned to player -@treturn boolean The opposite of success so true means to cancel execution, used internally - -@usage-- Used in the command system to log handler errors -local success, err = pcall(command_data.callback, player, table.unpack(params)) -if Commands.internal_error(success, command_data.name, err) then - return command_log(player, command_data, 'Internal Error: Command Callback Fail', raw_params, command_event.parameter, err) -end - -]] -function Commands.internal_error(success, command_name, error_message) - if not success then - Commands.error("Internal Error, Please contact an admin", "utility/cannot_build") - log{ "expcore-commands.command-error-log-format", command_name, error_message } - end - return not success -end - ---- Logs command usage to file -local function command_log(player, command, comment, params, raw, details) - local player_name = player and player.name or "" - write_json("log/commands.log", { - player_name = player_name, - command_name = command.name, - comment = comment, - details = details, - params = params, - raw = raw, - }) -end - ---- Main event function that is ran for all commands, used internally please avoid direct use --- @tparam table command_event Passed directly from the add_command function --- @usage Commands.run_command(event) -function Commands.run_command(command_event) - local command_data = Commands.commands[command_event.name] - -- Player can be nil when it is the server - local player - if command_event.player_index and command_event.player_index > 0 then - player = game.players[command_event.player_index] - end - - -- Check if the player is allowed to use the command - local authorized, auth_fail = Commands.authorize(player, command_data.name) - if not authorized then - command_log(player, command_data, "Failed Auth", {}, command_event.parameter) - Commands.error(auth_fail, "utility/cannot_build") - return - end - - -- Check for parameter being nil - if command_data.min_param_count > 0 and not command_event.parameter then - command_log(player, command_data, "No Params Given", {}, command_event.parameter) - Commands.error{ "expcore-commands.invalid-inputs", command_data.name, command_data.description } - return - end - - -- Extract quoted arguments - local raw_input = command_event.parameter or "" - local quote_params = {} - local input_string = raw_input:gsub('"[^"]-"', function(word) - local no_spaces = word:gsub("%s", "%%s") - quote_params[no_spaces] = word:sub(2, -2) - return " " .. no_spaces .. " " - end) - - -- Extract unquoted arguments - local raw_params = {} - local last_index = 0 - local param_number = 0 - for word in input_string:gmatch("%S+") do - param_number = param_number + 1 - if param_number > command_data.max_param_count then - -- there are too many params given to the command - if not command_data.auto_concat then - -- error as they should not be more - command_log(player, command_data, "Invalid Input: Too Many Params", raw_params, raw_input) - Commands.error{ "expcore-commands.invalid-inputs", command_data.name, command_data.description } - return - else - -- concat to the last param - if quote_params[word] then - raw_params[last_index] = raw_params[last_index] .. ' "' .. quote_params[word] .. '"' - else - raw_params[last_index] = raw_params[last_index] .. " " .. word - end - end - else - -- new param that needs to be added - if quote_params[word] then - last_index = last_index + 1 - raw_params[last_index] = quote_params[word] - else - last_index = last_index + 1 - raw_params[last_index] = word - end - end - end - - -- Check the param count - local param_count = #raw_params - if param_count < command_data.min_param_count then - command_log(player, command_data, "Invalid Input: Not Enough Params", raw_params, raw_input) - Commands.error{ "expcore-commands.invalid-inputs", command_data.name, command_data.description } - return - end - - -- Parse the arguments - local index = 1 - local params = {} - for param_name, param_data in pairs(command_data.params) do - local parse_callback = param_data.parse - -- If its a string this get it from the parser table - if type(parse_callback) == "string" then - parse_callback = Commands.parsers[parse_callback] - end - - -- If its not a function throw and error - if type(parse_callback) ~= "function" then - Commands.internal_error(false, command_data.name, "Invalid param parse " .. tostring(param_data.parse)) - command_log(player, command_data, "Internal Error: Invalid Param Parse", params, raw_input, tostring(param_data.parse)) - return - end - - -- This is the reject function given to parse callbacks - local function reject(error_message) - error_message = error_message or "" - command_log(player, command_data, "Invalid Param Given", raw_params, input_string) - return Commands.error{ "expcore-commands.invalid-param", param_name, error_message } - end - - -- input: string, player: LuaPlayer, reject: function, ... extra args - local success, param_parsed = pcall(parse_callback, raw_params[index], player, reject, table.unpack(param_data.parse_args)) - if Commands.internal_error(success, command_data.name, param_parsed) then - return command_log(player, command_data, "Internal Error: Param Parse Fail", params, raw_input, param_parsed) - end - - if param_data.optional == true and raw_params[index] == nil then - -- If the param is optional and nil then it is set to default - param_parsed = param_data.default - if type(param_parsed) == "function" then - success, param_parsed = pcall(param_parsed, player) - if Commands.internal_error(success, command_data.name, param_parsed) then - return command_log(player, command_data, "Internal Error: Default Value Fail", params, raw_input, param_parsed) - end - end - elseif param_parsed == nil or param_parsed == Commands.defines.error or param_parsed == reject then - -- No value was returned or error was returned, if nil then give generic error - if param_parsed ~= Commands.defines.error then - command_log(player, command_data, "Invalid Param Given", raw_params, raw_input, param_name) - Commands.error{ "expcore-commands.command-error-param-format", param_name, "please make sure it is the correct type" } - end - return - end - - -- Add the param to the table to be passed to the command callback - params[index] = param_parsed - index = index + 1 - end - - -- Run the command - -- player: LuaPlayer, ... command params, raw: string - params[command_data.max_param_count + 1] = raw_input - local success, rtn = pcall(command_data.callback, player, table.unpack(params)) - if Commands.internal_error(success, command_data.name, rtn) then - return command_log(player, command_data, "Internal Error: Command Callback Fail", raw_params, command_event.parameter, rtn) - end - - -- Give output to the player - if rtn == Commands.defines.error or rtn == Commands.error then - return command_log(player, command_data, "Custom Error", raw_params, raw_input) - elseif rtn ~= Commands.defines.success and rtn ~= Commands.success then - Commands.success(rtn) - end - command_log(player, command_data, "Success", raw_params, raw_input) -end - -return Commands diff --git a/exp_legacy/module/expcore/gui/top_flow.lua b/exp_legacy/module/expcore/gui/top_flow.lua index 04109616..a955692e 100644 --- a/exp_legacy/module/expcore/gui/top_flow.lua +++ b/exp_legacy/module/expcore/gui/top_flow.lua @@ -195,7 +195,7 @@ Gui.toggle_top_flow(game.player, true) ]] function Gui.toggle_top_flow(player, state) -- Get the top flow, we need the parent as we want to toggle the outer frame - local top_flow = Gui.get_top_flow(player).parent + local top_flow = Gui.get_top_flow(player).parent --- @cast top_flow -nil if state == nil then state = not top_flow.visible end -- Get the show button for the top flow diff --git a/exp_legacy/module/expcore/player_data.lua b/exp_legacy/module/expcore/player_data.lua index 8f05ebfa..ecf617b2 100644 --- a/exp_legacy/module/expcore/player_data.lua +++ b/exp_legacy/module/expcore/player_data.lua @@ -44,8 +44,7 @@ end) local Async = require("modules/exp_util/async") local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event local Datastore = require("modules.exp_legacy.expcore.datastore") --- @dep expcore.datastore -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") --- @dep config.expcore.command_general_parse +local Commands = require("modules/exp_commands") local table_to_json = helpers.table_to_json local write_file = helpers.write_file @@ -67,23 +66,20 @@ DataSavingPreference:set_metadata{ } --- Sets your data saving preference --- @command set-data-preference -Commands.new_command("set-preference", "Allows you to set your data saving preference") - :add_param("option", false, "string-options", PreferenceEnum) +Commands.new("data-preference", { "expcore-data.description-preference" }) + :optional("option", { "expcore-data.arg-option" }, Commands.types.enum(PreferenceEnum)) :register(function(player, option) - DataSavingPreference:set(player, option) - return { "expcore-data.set-preference", option } - end) - ---- Gets your data saving preference --- @command data-preference -Commands.new_command("preference", "Shows you what your current data saving preference is") - :register(function(player) - return { "expcore-data.get-preference", DataSavingPreference:get(player) } + --- @cast option "All" | "Statistics" | "Settings" | "Required" | nil + if option then + DataSavingPreference:set(player, option) + return Commands.status.success{ "expcore-data.set-preference", option } + else + return Commands.status.success{ "expcore-data.get-preference", DataSavingPreference:get(player) } + end end) --- Gets your data and writes it to a file -Commands.new_command("save-data", "Writes all your player data to a file on your computer") +Commands.new("save-data", { "expcore-data.description-data" }) :register(function(player) player.print{ "expcore-data.get-data" } write_file("expgaming_player_data.json", table_to_json(PlayerData:get(player, {})), false, player.index) diff --git a/exp_legacy/module/expcore/roles.lua b/exp_legacy/module/expcore/roles.lua index a0e235a7..880eca75 100644 --- a/exp_legacy/module/expcore/roles.lua +++ b/exp_legacy/module/expcore/roles.lua @@ -311,6 +311,15 @@ function Roles.get_role_from_any(any) end end +--- Returns all roles in order of index +function Roles.get_roles_ordered() + local rtn = {} + for index, role_name in ipairs(Roles.config.order) do + rtn[index] = Roles.config.roles[role_name] + end + return rtn +end + --[[-- Gets all the roles of the given player, this will always contain the default role @tparam LuaPlayer player the player to get the roles of @treturn table a table where the values are the roles which the player has diff --git a/exp_legacy/module/locale/en/commands.cfg b/exp_legacy/module/locale/en/commands.cfg deleted file mode 100644 index 372c5394..00000000 --- a/exp_legacy/module/locale/en/commands.cfg +++ /dev/null @@ -1,245 +0,0 @@ -[expcom-admin-chat] -description=Sends a message in chat that only admins can see. -format=[Admin Chat] __1__: __2__ - -[expcom-admin-marker] -description=Toggles admin marker mode, new markers can only be edited by admins -exit=You have left admin marker mode, all new markers will not be protected. -enter=You have entered admin marker mode, all new markers will be protected. -place=You have placed an admin marker. -edit=You have edited an admin marker. -revert=You cannot edit admin markers. - -[expcom-artillery] -description=Artillery Target Remote - -[expcom-bonus] -description=Changes the amount of bonus you receive -set=Your bonus has been set to __1__. -perm=You dont have enough permission to set more than __1__. - -[expcom-bot-queue] -description-get=Get bot queue -description-set=Set bot queue -result=__1__ set the bot queue to __2__ successful attempts and __3__ failed attempts - -[expcom-cheat] -description-cheat=Toggles cheat mode for your player, or another player. -description-res=Set all research for your force. -description-day=Toggles always day in surface. -res=__1__ has enabled all technologies -day=__1__ set always day to __2__ - -[expcom-chelp] -description=Searches for a keyword in all commands you are allowed to use. -title=Help results for "__1__": -footer=[__1__ results found: page __2__ of __3__] -format=/__1__ __2__ - __3__ __4__ -alias=Alias: __1__ -out-of-range=__1__ is an invalid page number. - -[expcom-clr-inv] -description=Clears a players inventory - -[expcom-connect] -description=Connect to another server -description-player=Send a player to a different server -description-all=Connect all players to another server -too-many-matching=Multiple server were found with the given name: __1__ -wrong-version=Servers were found but are on a different version: __1__ -same-server=You are already connected to the server: __1__ -offline=You cannot connect as the server is currently offline: __1__ -none-matching=No servers were found with that name, if you used an address please append true to the end of your command. - -[expcom-debug] -description=Opens the debug pannel for viewing tables. - -[expcom-enemy] -description-kill=Kill all biters only -description-remove=Remove biters and prevent generation - -[expcom-ff] -description=Toggle friendly fire -ff=__1__ set friendly fire to __2__ - -[expcom-find] -description=Find a player on your map. - -[expcom-home] -description-home=Teleports you to your home location -description-home-set=Sets your home location to your current position -description-home-get=Returns your current home location -description-return=Teleports you to previous location -no-home=You have no home set. -no-return=You can't return when home has not yet been used. -home-set=Your home point has been set to x: __1__ y: __2__ -return-set=Your return point has been set to x: __1__ y: __2__ -home-get=Your home point is at x: __1__ y: __2__ - -[expcom-interface] -description=Sends an invocation to be ran and returns the result. - -[expcom-inv-search] -description-ia=Display players sorted by the quantity of an item held -description-ir=Display players who hold an item sorted by join time -description-i=Display players sorted by the quantity of an item held and playtime -description-io=Display online players sorted by the quantity of an item held and playtime -reject-item=No item was found with internal name __1__; try using rich text selection. -results-heading=Players found with [item=__1__]: -results-item=__1__) __2__ has __3__ items. (__4__) -results-none=No players have [item=__1__] - -[expcom-jail] -description-jail=Puts a player into jail and removes all other roles. -description-unjail=Removes a player from jail. -give=__1__ was jailed by __2__. Reason: __3__ -remove=__1__ was unjailed by __2__. -already-jailed=__1__ is already in jail. -not-jailed=__1__ is not currently in jail. - -[expcom-join-message] -description-msg=Sets your custom join message -description-clr=Clear your join message - -[expcom-kill] -description=Kills yourself or another player. -already-dead=You are already dead. - -[expcom-lawnmower] -description=Clean up biter corpse, decoratives and nuclear hole - -[expcom-lastlocation] -description=Sends you the last location of a player -response=Last location of __1__ was [gps=__2__,__3__] - -[expcom-me] -description=Sends an action message in the chat - -[expcom-personal-logistics] -description=Set Personal Logistic (-1 to cancel all) (Select spidertron to edit spidertron) - -[expcom-pol] -description-clr=Clear pollution -description-off=Disable pollution -clr=__1__ cleared the pollution. -off=__1__ disabled the pollution. - -[expcom-protection] -description-pe=Toggles entity protection selection, hold shift to remove protection -description-pa=Toggles area protection selection, hold shift to remove protection -entered-entity-selection=Entered entity selection, select entites to protect, hold shift to remove protection. -entered-area-selection=Entered area selection, select areas to protect, hold shift to remove protection. -protected-entities=__1__ entities have been protected. -unprotected-entities=__1__ entities have been unprotected. -already-protected=This area is already protected. -protected-area=This area is now protected. -unprotected-area=This area is now unprotected. -repeat-offence=__1__ has removed __2__ at [gps=__3__,__4__] - -[expcom-quickbar] -description=Saves your quickbar preset items to file - -[expcom-rainbow] -description=Sends an rainbow message in the chat - -[expcom-ratio] -description=This command will give the input and output ratios of the selected machine. Use the parameter for calculating the machines needed for that amount of items per second. -notSelecting=Please select an entity with a recipe. -item-in=You need __1__ per second of [item=__2__]. -fluid-in=You need __1__ per second of [fluid=__2__]. -item-out=This will result in: __1__ [item=__2__] per second. -fluid-out=This will result in: __1__ [fluid=__2__] per second. -machines=And you will need __1__ machines (with the same speed as this one) for this. - -[expcom-repair] -description=Repairs entities on your force around you -result=__1__ entites were revived and __2__ were healed to max health. - -[expcom-report] -description-report=Reports a player and notifies moderators -description-get-reports=Gets a list of all reports that a player has on them. If no player then lists all players and the number of reports on them. -description-clear-reports=Clears all reports from a player or just the report from one player. -player-immune=This player can not be reported. -self-report=You cannot report yourself. -non-admin=__1__ was reported for __2__. -admin=__1__ was reported by __2__ for __3__. -already-reported=You can only report a player once, you can ask a moderator to clear this report. -not-reported=The player had no reports on them. -player-count-title=The following players have reports against them: -player-report-title=__1__ has the following reports against them: -list=__1__: __2__ -removed=__1__ has one or more reports removed by __2__. - -[expcom-res] -description-ares=Automatically queue up research -res=__1__ set auto research to __2__ -msg=[color=255, 255, 255] Research completed at __1__ - [technology=__2__][/color] -inf=[color=255, 255, 255] Research completed at __1__ - [technology=__2__] - __3__[/color] -inf-q=[color=255, 255, 255] Research added to queue - [technology=__1__] - __2__[/color] -res-name=[technology=__1__] __2__ -name=Name -target=Target -attempt=Attempt -difference=Diff -main-tooltip=Research GUI - -[expcom-roles] -description-assign-role=Assigns a role to a player -description-unassign-role=Unassigns a role from a player -description-list-roles=Lists all roles in they correct order -higher-role=The role you tried to assign is higher than your highest. -list=All roles are: __1__ -list-player=__1__ has: __2__ -list-element=__1__, __2__ - -[expcom-server-ups] -no-ext=No external source was found, cannot display server ups. - -[expcom-spawn] -description=Teleport to spawn -unavailable=They was a problem getting you to spawn, please try again later. - -[expcom-spectate] -description-spectate=Toggles spectator mode -description-follow=Start following a player in spectator -follow-self=You can not follow yourself - -[expcom-speed] -description=Set game speed -result=__1__ set the game speed to __2__ - -[expcom-surface-clearing] -description-ci=Clear Item On Ground -description-cb=Clear Blueprint - -[expcom-tag] -description=Sets your player tag. -description-clear=Clears your tag. Or another player if you are admin. - -[expcom-tp] -description-tp=Teleports a player to another player. -description-bring=Teleports a player to you. -description-goto=Teleports you to a player. -no-position-found=No position to teleport to was found, please try again later. -to-self=Player can not be teleported to themselves. - -[expcom-train] -description=Set All Trains to Automatic -manual-result=__1__ put __2__ trains into automatic mode - -[expcom-warnings] -description-give=Gives a warning to a player; may lead to automatic script action. -description-get=Gets the number of warnings a player has. If no player then lists all players and the number of warnings they have. -description-clear=Clears all warnings (and script warnings) from a player -received=__1__ received a warning from __2__ for __3__. -player=__1__ has __2__ warnings and __3__/__4__ script warnings. -player-detail=__1__ gave warning for: __2__ -list-title=The following players have this many warnings (and this many script warnings): -list=__1__: __2__ (__3__/__4__) -cleared=__1__ had all their warnings cleared by __2__. - -[expcom-waterfill] -description=Change tile to water -waterfill-distance=Too close to designated location -waterfill-cliff=Not enough cliff explosive to create water -entered-area-selection=Entered area selection, select areas to convert. diff --git a/exp_legacy/module/locale/en/config.cfg b/exp_legacy/module/locale/en/config.cfg deleted file mode 100644 index b12b17cf..00000000 --- a/exp_legacy/module/locale/en/config.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[command-auth] -admin-only=This command is for (game) admins only! -command-disabled=This command has been disabled by management! \ No newline at end of file diff --git a/exp_legacy/module/locale/en/data.cfg b/exp_legacy/module/locale/en/data.cfg index 9d673acc..b29656a3 100644 --- a/exp_legacy/module/locale/en/data.cfg +++ b/exp_legacy/module/locale/en/data.cfg @@ -1,6 +1,10 @@ [join-message] +description-add=Sets / Gets your custom join message. +description-remove=Removes you custom join message. +arg-message=Your custom join message. greet=[color=0,1,0] Welcome to explosive gaming community server! If you like the server join our discord: __1__ [/color] message-set=Your join message has been updated. +message-get=Your join message is: __1__ message-cleared=Your join message has been cleared. [quickbar] diff --git a/exp_legacy/module/locale/en/expcore.cfg b/exp_legacy/module/locale/en/expcore.cfg index bdc4907d..0f9f18c3 100644 --- a/exp_legacy/module/locale/en/expcore.cfg +++ b/exp_legacy/module/locale/en/expcore.cfg @@ -1,29 +1,3 @@ -time-symbol-days-short=__1__d -color-tag=[color=__1__]__2__[/color] - -[time-format] -simple-format-tagged=__1__ __2__ -simple-format-div=__1__:__2__ - -[expcore-commands] -unauthorized=Unauthorized, Access is denied due to invalid credentials -reject-string-options=Invalid Option, Must be one of: __1__ -reject-string-max-length=Invalid Length, Max: __1__ -reject-number=Invalid Number. -reject-number-range=Invalid Range, Min (inclusive): __1__, Max (inclusive): __2__ -reject-player=Invalid Player Name, __1__ ,try using tab key to auto-complete the name -reject-player-online=Player is offline. -reject-player-alive=Player is dead. -reject-force=Invalid Force Name. -reject-surface=Invalid Surface Name. -reject-color=Invalid Color Name. -invalid-inputs=Invalid Input, /__1__ __2__ -invalid-param=Invalid Param "__1__"; __2__ -command-help=__1__ - __2__ -command-ran=Command Complete -command-fail=Command failed to run: __1__ -command-error-log-format=[ERROR] command/__1__ :: __2__ - [expcore-roles] error-log-format-flag=[ERROR] roleFlag/__1__ :: __2__ error-log-format-assign=[ERROR] rolePromote/__1__ :: __2__ @@ -39,6 +13,8 @@ button_tooltip=Shows/hides the toolbar. left-button-tooltip=Hide all open windows. [expcore-data] +description-preference=Allows you to set/get your data saving preference. +description-data=Writes all your player data to a file on your computer. set-preference=You data saving preference has been set to __1__. Existing data will not be effected until you rejoin. get-preference=You data saving preference is __1__. Use /set-preference to change this. Use /save-data to get a local copy of your data. get-data=Your player data has been writen to file, location: factorio/script_output/expgaming_player_data.json diff --git a/exp_legacy/module/locale/en/gui.cfg b/exp_legacy/module/locale/en/gui.cfg index 4a32da2a..a7bdb278 100644 --- a/exp_legacy/module/locale/en/gui.cfg +++ b/exp_legacy/module/locale/en/gui.cfg @@ -210,6 +210,11 @@ disabled=disabled toggle-msg=Fast decon has been __1__ [bonus] +description=Get / Set the amount of bonus you receive. +arg-amount=Amount to set your bonus to, 0 will disable bonus. +set=Your bonus has been set to __1__. +get=Your bonus is __1__. +perm=You dont have enough permission to set more than __1__. main-tooltip=Bonus control-pts-a=Points available control-pts-n=Points needed @@ -319,3 +324,17 @@ reset=Reset All toggle=Toggle Favourites move-up=Move Up move-down=Move Down + +[research] +msg=[color=255, 255, 255] Research completed at __1__ - [technology=__2__][/color] +inf=[color=255, 255, 255] Research completed at __1__ - [technology=__2__] - __3__[/color] +res-name=[technology=__1__] __2__ +name=Name +target=Target +attempt=Attempt +difference=Diff +main-tooltip=Research GUI + +[server-ups] +description=Toggle the server UPS display. +no-ext=No external source was found, cannot display server ups. \ No newline at end of file diff --git a/exp_legacy/module/modules/addons/lawnmower.lua b/exp_legacy/module/modules/addons/lawnmower.lua deleted file mode 100644 index cadb324a..00000000 --- a/exp_legacy/module/modules/addons/lawnmower.lua +++ /dev/null @@ -1,60 +0,0 @@ ---[[-- Addon Lawnmower - - Adds a command that clean up biter corpse and nuclear hole - @addon Lawnmower -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event -local config = require("modules.exp_legacy.config.lawnmower") --- @dep config.lawnmower -require("modules.exp_legacy.config.expcore.command_general_parse") - -Commands.new_command("lawnmower", "Clean up biter corpse, decoratives and nuclear hole") - :add_param("range", false, "integer-range", 1, 200) - :register(function(player, range) - local tile_to_do = {} - - -- Intentionally left as player.position to allow use in remote view - player.surface.destroy_decoratives{ position = player.position, radius = range } - - local entities = player.surface.find_entities_filtered{ position = player.position, radius = range, type = "corpse" } - - for _, entity in pairs(entities) do - if (entity.name ~= "transport-caution-corpse" and entity.name ~= "invisible-transport-caution-corpse") then - entity.destroy() - end - end - - local tiles = player.surface.find_tiles_filtered{ position = player.position, radius = range, name = { "nuclear-ground" } } - - for _, tile in pairs(tiles) do - table.insert(tile_to_do, { name = "grass-1", position = tile.position }) - end - - player.surface.set_tiles(tile_to_do) - - return Commands.success - end) - -local function destroy_decoratives(entity) - if entity.type ~= "entity-ghost" and entity.type ~= "tile-ghost" and entity.prototype.selectable_in_game then - entity.surface.destroy_decoratives{ area = entity.selection_box } - end -end - -if config.destroy_decoratives then - Event.add(defines.events.on_built_entity, function(event) - destroy_decoratives(event.created_entity) - end) - - Event.add(defines.events.on_robot_built_entity, function(event) - destroy_decoratives(event.created_entity) - end) - - Event.add(defines.events.script_raised_built, function(event) - destroy_decoratives(event.entity) - end) - - Event.add(defines.events.script_raised_revive, function(event) - destroy_decoratives(event.entity) - end) -end diff --git a/exp_legacy/module/modules/commands/admin-chat.lua b/exp_legacy/module/modules/commands/admin-chat.lua deleted file mode 100644 index fa866aaa..00000000 --- a/exp_legacy/module/modules/commands/admin-chat.lua +++ /dev/null @@ -1,28 +0,0 @@ ---[[-- Commands Module - Admin Chat - - Adds a command that allows admins to talk in a private chat - @commands Admin-Chat -]] - -local ExpUtil = require("modules/exp_util") -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local format_player_name = ExpUtil.format_player_name_locale --- @dep expcore.common -require("modules.exp_legacy.config.expcore.command_general_parse") - ---- Sends a message in chat that only admins can see --- @command admin-chat --- @tparam string message the message to send in the admin chat -Commands.new_command("admin-chat", { "expcom-admin-chat.description" }, "Sends a message in chat that only admins can see.") - :add_param("message", false) - :enable_auto_concat() - :set_flag("admin_only") - :add_alias("ac") - :register(function(player, message) - local player_name_colour = format_player_name(player) - for _, return_player in pairs(game.connected_players) do - if return_player.admin then - return_player.print{ "expcom-admin-chat.format", player_name_colour, message } - end - end - - return Commands.success -- prevents command complete message from showing - end) diff --git a/exp_legacy/module/modules/commands/admin-markers.lua b/exp_legacy/module/modules/commands/admin-markers.lua deleted file mode 100644 index 34232aac..00000000 --- a/exp_legacy/module/modules/commands/admin-markers.lua +++ /dev/null @@ -1,88 +0,0 @@ ---[[-- Commands Module - Admin Markers - - Adds a command that creates map markers which can only be edited by admins - @commands Admin-Markers -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Storage = require("modules/exp_util/storage") -local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event - -local admins = {} -- Stores all players in admin marker mode -local markers = {} -- Stores all admin markers - ---- Storage variables -Storage.register({ - admins = admins, - markers = markers, -}, function(tbl) - admins = tbl.admins - markers = tbl.markers -end) - ---- Toggle admin marker mode, can only be applied to yourself --- @command admin-marker -Commands.new_command("admin-marker", { "expcom-admin-marker.description" }, "Toggles admin marker mode, new markers can only be edited by admins") - :set_flag("admin_only") - :add_alias("am", "admin-markers") - :register(function(player) - if admins[player.name] then - -- Exit admin mode - admins[player.name] = nil - return Commands.success{ "expcom-admin-marker.exit" } - else - -- Enter admin mode - admins[player.name] = true - return Commands.success{ "expcom-admin-marker.enter" } - end - end) - ---- Listen for new map markers being added, add admin marker if done by player in admin mode -Event.add(defines.events.on_chart_tag_added, function(event) - if not event.player_index then return end - local player = game.players[event.player_index] - if not admins[player.name] then return end - local tag = event.tag - markers[tag.force.name .. tag.tag_number] = true - Commands.print({ "expcom-admin-marker.place" }, nil, player) -end) - ---- Listen for players leaving the game, leave admin mode to avoid unexpected admin markers -Event.add(defines.events.on_player_left_game, function(event) - if not event.player_index then return end - local player = game.players[event.player_index] - admins[player.name] = nil -end) - ---- Listen for tags being removed or edited, maintain tags edited by non admins -local function maintain_tag(event) - local tag = event.tag - if not event.player_index then return end - if not markers[tag.force.name .. tag.tag_number] then return end - local player = game.players[event.player_index] - if player.admin then - -- Player is admin, tell them it was an admin marker - Commands.print({ "expcom-admin-marker.edit" }, nil, player) - elseif event.name == defines.events.on_chart_tag_modified then - -- Tag was modified, revert the changes - tag.text = event.old_text - tag.last_user = event.old_player - if event.old_icon then tag.icon = event.old_icon end - player.play_sound{ path = "utility/wire_pickup" } - Commands.print({ "expcom-admin-marker.revert" }, nil, player) - else - -- Tag was removed, remake the tag - player.play_sound{ path = "utility/wire_pickup" } - Commands.print({ "expcom-admin-marker.revert" }, "orange_red", player) - local new_tag = tag.force.add_chart_tag(tag.surface, { - last_user = tag.last_user, - position = tag.position, - icon = tag.icon, - text = tag.text, - }) - markers[tag.force.name .. tag.tag_number] = nil - markers[new_tag.force.name .. new_tag.tag_number] = true - end -end - -Event.add(defines.events.on_chart_tag_modified, maintain_tag) -Event.add(defines.events.on_chart_tag_removed, maintain_tag) diff --git a/exp_legacy/module/modules/commands/artillery.lua b/exp_legacy/module/modules/commands/artillery.lua deleted file mode 100644 index fe6484d6..00000000 --- a/exp_legacy/module/modules/commands/artillery.lua +++ /dev/null @@ -1,81 +0,0 @@ ---[[-- Commands Module - Artillery - - Adds a command that help shot artillery - @commands Artillery -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") -local Selection = require("modules.exp_legacy.modules.control.selection") --- @dep modules.control.selection -local SelectionArtyArea = "ArtyArea" - -local function location_break(player, pos) - -- Intentionally left as player.surface to allow use in remote view - if player.force.is_chunk_charted(player.surface, { x = math.floor(pos.left_top.x / 32), y = math.floor(pos.left_top.y / 32) }) then - return true - elseif player.force.is_chunk_charted(player.surface, { x = math.floor(pos.left_top.x / 32), y = math.floor(pos.right_bottom.y / 32) }) then - return true - elseif player.force.is_chunk_charted(player.surface, { x = math.floor(pos.right_bottom.x / 32), y = math.floor(pos.left_top.y / 32) }) then - return true - elseif player.force.is_chunk_charted(player.surface, { x = math.floor(pos.right_bottom.x / 32), y = math.floor(pos.right_bottom.y / 32) }) then - return true - else - return false - end -end - ---- align an aabb to the grid by expanding it -local function aabb_align_expand(aabb) - return { - left_top = { x = math.floor(aabb.left_top.x), y = math.floor(aabb.left_top.y) }, - right_bottom = { x = math.ceil(aabb.right_bottom.x), y = math.ceil(aabb.right_bottom.y) }, - } -end - ---- when an area is selected to add protection to the area -Selection.on_selection(SelectionArtyArea, function(event) - local area = aabb_align_expand(event.area) - local player = game.players[event.player_index] - - if player == nil then - return - end - - if not (game.players[event.player_index].cheat_mode or location_break(player, event.area)) then - return Commands.error - end - - local count = 0 - local hit = {} - - for _, e in pairs(player.surface.find_entities_filtered{ area = area, type = { "unit-spawner", "turret" }, force = "enemy" }) do - local skip = false - - for _, pos in ipairs(hit) do - if math.sqrt(math.abs(e.position.x - pos.x) ^ 2 + math.abs(e.position.y - pos.y) ^ 2) < 6 then - skip = true - break - end - end - - if not skip then - player.surface.create_entity{ name = "artillery-flare", position = e.position, force = player.force, life_time = 240, movement = { 0, 0 }, height = 0, vertical_speed = 0, frame_speed = 0 } - table.insert(hit, e.position) - count = count + 1 - - if count > 400 then - break - end - end - end -end) - -Commands.new_command("artillery-target-remote", { "expcom-artillery.description" }, "Artillery Target Remote") - :register(function(player) - if Selection.is_selecting(player, SelectionArtyArea) then - Selection.stop(player) - else - Selection.start(player, SelectionArtyArea) - end - - return Commands.success - end) diff --git a/exp_legacy/module/modules/commands/bot-queue.lua b/exp_legacy/module/modules/commands/bot-queue.lua deleted file mode 100644 index 2da11bc2..00000000 --- a/exp_legacy/module/modules/commands/bot-queue.lua +++ /dev/null @@ -1,25 +0,0 @@ ---[[-- Commands Module - Bot queue - - Adds a command that allows changing bot queue - @commands Bot Queue -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") - -Commands.new_command("bot-queue-get", { "expcom-bot-queue.description-get" }, "Get bot queue") - :set_flag("admin_only") - :register(function(player) - local s = player.force.max_successful_attempts_per_tick_per_construction_queue - local f = player.force.max_failed_attempts_per_tick_per_construction_queue - return Commands.success{ "expcom-bot-queue.result", player.name, s, f } - end) - -Commands.new_command("bot-queue-set", { "expcom-bot-queue.description-set" }, "Set bot queue") - :add_param("amount", "integer-range", 1, 20) - :set_flag("admin_only") - :register(function(player, amount) - player.force.max_successful_attempts_per_tick_per_construction_queue = 3 * amount - player.force.max_failed_attempts_per_tick_per_construction_queue = 1 * amount - game.print{ "expcom-bot-queue.result", player.name, 3 * amount, 1 * amount } - return Commands.success - end) diff --git a/exp_legacy/module/modules/commands/cheat-mode.lua b/exp_legacy/module/modules/commands/cheat-mode.lua deleted file mode 100644 index 4aacd0c7..00000000 --- a/exp_legacy/module/modules/commands/cheat-mode.lua +++ /dev/null @@ -1,46 +0,0 @@ ---[[-- Commands Module - Cheat Mode - - Adds a command that allows players to enter cheat mode - @commands Cheat-Mode -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") - ---- Toggles cheat mode for your player, or another player. --- @command toggle-cheat-mode --- @tparam[opt=self] LuaPlayer player player to toggle chest mode of, can be nil for self -Commands.new_command("toggle-cheat-mode", { "expcom-cheat.description-cheat" }, "Toggles cheat mode for your player, or another player.") - :add_param("player", true, "player") - :set_defaults{ player = function(player) - return player -- default is the user using the command - end } - :set_flag("admin_only") - :register(function(_, player) - player.cheat_mode = not player.cheat_mode - return Commands.success - end) - -Commands.new_command("research-all", { "expcom-cheat.description-res" }, "Set all research for your force.") - :set_flag("admin_only") - :add_param("force", true, "force") - :set_defaults{ force = function(player) - return player.force - end } - :register(function(player, force) - force.research_all_technologies() - game.print{ "expcom-cheat.res", player.name } - return Commands.success - end) - -Commands.new_command("toggle-always-day", { "expcom-cheat.description-day" }, "Toggles always day in surface.") - :set_flag("admin_only") - :add_param("surface", true, "surface") - :set_defaults{ surface = function(player) - -- Intentionally left as player.surface to allow use in remote view - return player.surface - end } - :register(function(player, surface) - surface.always_day = not surface.always_day - game.print{ "expcom-cheat.day", player.name, surface.always_day } - return Commands.success - end) diff --git a/exp_legacy/module/modules/commands/clear-inventory.lua b/exp_legacy/module/modules/commands/clear-inventory.lua deleted file mode 100644 index 9b0f6977..00000000 --- a/exp_legacy/module/modules/commands/clear-inventory.lua +++ /dev/null @@ -1,28 +0,0 @@ ---[[-- Commands Module - Clear Inventory - - Adds a command that allows admins to clear people's inventorys - @commands Clear-Inventory -]] - -local ExpUtil = require("modules/exp_util") -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_role_parse") - ---- Clears a players inventory --- @command clear-inventory --- @tparam LuaPlayer player the player to clear the inventory of -Commands.new_command("clear-inventory", { "expcom-clr-inv.description" }, "Clears a players inventory") - :add_param("player", false, "player-role") - :add_alias("clear-inv", "move-inventory", "move-inv") - :register(function(_, player) - local inventory = player.get_main_inventory() - if not inventory then - return Commands.error{ "expcore-commands.reject-player-alive" } - end - - ExpUtil.transfer_inventory_to_surface{ - inventory = inventory, - surface = game.planets.nauvis.surface, - name = "iron-chest", - allow_creation = true, - } - end) diff --git a/exp_legacy/module/modules/commands/connect.lua b/exp_legacy/module/modules/commands/connect.lua deleted file mode 100644 index a23f444c..00000000 --- a/exp_legacy/module/modules/commands/connect.lua +++ /dev/null @@ -1,107 +0,0 @@ ---[[-- Commands Module - Connect - - Adds a commands that allows you to request a player move to another server - @commands Connect -]] - -local Async = require("modules/exp_util/async") -local External = require("modules.exp_legacy.expcore.external") --- @dep expcore.external -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_role_parse") -local concat = table.concat - -local request_connection_async = Async.register(External.request_connection) - -local function get_server_id(server) - local current_server = External.get_current_server() - local current_version = current_server.version - local servers = External.get_servers_filtered(server) - - local server_names_before, server_names = {}, {} - local server_count_before, server_count = 0, 0 - for next_server_id, server_details in pairs(servers) do - server_count_before = server_count_before + 1 - server_names_before[server_count_before] = server_details.name - if server_details.version == current_version then - server_count = server_count + 1 - server_names[server_count] = server_details.name - else - servers[next_server_id] = nil - end - end - - if server_count > 1 then - return false, Commands.error{ "expcom-connect.too-many-matching", concat(server_names, ", ") } - elseif server_count == 1 then - local server_id, server_details = next(servers) - local status = External.get_server_status(server_id) - if server_id == current_server.id then - return false, Commands.error{ "expcom-connect.same-server", server_details.name } - elseif status == "Offline" then - return false, Commands.error{ "expcom-connect.offline", server_details.name } - end - return true, server_id - elseif server_count_before > 0 then - return false, Commands.error{ "expcom-connect.wrong-version", concat(server_names_before, ", ") } - else - return false, Commands.error{ "expcom-connect.none-matching" } - end -end - ---- Connect to a different server --- @command connect --- @tparam string server The address or name of the server to connect to --- @tparam[opt=false] boolean is_address If an address was given for the server param -Commands.new_command("connect", { "expcom-connect.description" }, "Connect to another server") - :add_param("server") - :add_param("is_address", true, "boolean") - :add_alias("join", "server") - :register(function(player, server, is_address) - local server_id = server - if not is_address and External.valid() then - local success, new_server_id = get_server_id(server) - if not success then return new_server_id end - server_id = new_server_id - end - - request_connection_async(player, server_id, true) - end) - ---- Connect a player to a different server --- @command connect-player --- @tparam string address The address or name of the server to connect to --- @tparam LuaPlayer player The player to connect to a different server --- @tparam[opt=false] boolean is_address If an address was given for the server param -Commands.new_command("connect-player", { "expcom-connect.description-player" }, "Send a player to a different server") - :add_param("player", "player-role") - :add_param("server") - :add_param("is_address", true, "boolean") - :register(function(_, player, server, is_address) - local server_id = server - if not is_address and External.valid() then - local success, new_server_id = get_server_id(server) - if not success then return new_server_id end - server_id = new_server_id - end - - External.request_connection(player, server_id) - end) - ---- Connect all players to a different server --- @command connect-all --- @tparam string address The address or name of the server to connect to --- @tparam[opt=false] boolean is_address If an address was given for the server param -Commands.new_command("connect-all", { "expcom-connect.description-all" }, "Connect all players to another server") - :add_param("server") - :add_param("is_address", true, "boolean") - :register(function(_, server, is_address) - local server_id = server - if not is_address and External.valid() then - local success, new_server_id = get_server_id(server) - if not success then return new_server_id end - server_id = new_server_id - end - - for _, player in pairs(game.connected_players) do - External.request_connection(player, server_id) - end - end) diff --git a/exp_legacy/module/modules/commands/debug.lua b/exp_legacy/module/modules/commands/debug.lua deleted file mode 100644 index ef7c2106..00000000 --- a/exp_legacy/module/modules/commands/debug.lua +++ /dev/null @@ -1,14 +0,0 @@ ---[[-- Commands Module - Debug - - Adds a command that opens the debug frame - @commands Debug -]] - -local DebugView = require("modules.exp_legacy.modules.gui.debug.main_view") --- @dep modules.gui.debug.main_view -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands - ---- Opens the debug pannel for viewing tables. --- @command debug -Commands.new_command("debug", { "expcom-debug.description" }, "Opens the debug pannel for viewing tables.") - :register(function(player) - DebugView.open_dubug(player) - end) diff --git a/exp_legacy/module/modules/commands/enemy.lua b/exp_legacy/module/modules/commands/enemy.lua deleted file mode 100644 index 7af03f2d..00000000 --- a/exp_legacy/module/modules/commands/enemy.lua +++ /dev/null @@ -1,30 +0,0 @@ ---[[-- Commands Module - Enemy - - Adds a command of handling enemy - @commands Enemy -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") - -Commands.new_command("kill-biters", { "expcom-enemy.description-kill" }, "Kill all biters only") - :set_flag("admin_only") - :register(function(_, _) - game.forces["enemy"].kill_all_units() - return Commands.success - end) - -Commands.new_command("remove-biters", { "expcom-enemy.description-remove" }, "Remove biters and prevent generation") - :set_flag("admin_only") - :add_param("surface", true, "surface") - :set_defaults{ surface = function(player) - -- Intentionally left as player.surface to allow use in remote view - return player.surface - end } - :register(function(_, surface) - for _, entity in pairs(surface.find_entities_filtered{ force = "enemy" }) do - entity.destroy() - end - - surface.map_gen_settings.autoplace_controls["enemy-base"].size = "none" - return Commands.success - end) diff --git a/exp_legacy/module/modules/commands/find.lua b/exp_legacy/module/modules/commands/find.lua deleted file mode 100644 index 54c27b90..00000000 --- a/exp_legacy/module/modules/commands/find.lua +++ /dev/null @@ -1,19 +0,0 @@ ---[[-- Commands Module - Find - - Adds a command that zooms in on the given player - @commands Find -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") - ---- Find a player on your map. --- @command find-on-map --- @tparam LuaPlayer the player to find on the map -Commands.new_command("find-on-map", { "expcom-find.description" }, "Find a player on your map.") - :add_param("player", false, "player-online") - :add_alias("find", "zoom-to") - :register(function(player, action_player) - local position = action_player.physical_position - player.zoom_to_world(position, 1.75) - return Commands.success -- prevents command complete message from showing - end) diff --git a/exp_legacy/module/modules/commands/friendly-fire.lua b/exp_legacy/module/modules/commands/friendly-fire.lua deleted file mode 100644 index 18421cf9..00000000 --- a/exp_legacy/module/modules/commands/friendly-fire.lua +++ /dev/null @@ -1,19 +0,0 @@ ---[[-- Commands Module - Toggle Friendly Fire - - Adds a command that toggle all friendly fire - @commands Toggle Friendly Fire -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") - --- For Modded Server Use -Commands.new_command("toggle-friendly-fire", { "expcom-ff.description" }, "Toggle friendly fire") - :add_param("force", true, "force") - :set_defaults{ force = function(player) - return player.force - end } - :register(function(player, force) - force.friendly_fire = not force.friendly_fire - game.print{ "expcom-ff.ff", player.name, force.friendly_fire } - return Commands.success - end) diff --git a/exp_legacy/module/modules/commands/help.lua b/exp_legacy/module/modules/commands/help.lua deleted file mode 100644 index 4d62ea58..00000000 --- a/exp_legacy/module/modules/commands/help.lua +++ /dev/null @@ -1,95 +0,0 @@ ---[[-- Commands Module - Help - - Adds a better help command that allows searching of descriotions and names - @commands Help -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Storage = require("modules/exp_util/storage") -require("modules.exp_legacy.config.expcore.command_general_parse") - -local results_per_page = 5 - -local search_cache = {} -Storage.register(search_cache, function(tbl) - search_cache = tbl -end) - ---- Searches for a keyword in all commands you are allowed to use. --- @command chelp --- @tparam string keyword the keyword that will be looked for --- @tparam number page the page of help to view, must be in range of pages -Commands.new_command("search-help", { "expcom-chelp.description" }, "Searches for a keyword in all commands you are allowed to use.") - :add_alias("chelp", "shelp", "commands") - :add_param("keyword", true) - :add_param("page", true, "integer") - :set_defaults{ keyword = "", page = 1 } - :register(function(player, keyword, page) - local player_index = player and player.index or 0 - -- if keyword is a number then treat it as page number - if tonumber(keyword) then - --- @diagnostic disable-next-line: param-type-mismatch - page = math.floor(tonumber(keyword)) - keyword = "" - end - - -- gets a value for pages, might have result in cache - local pages - local found = 0 - - if search_cache[player_index] and search_cache[player_index].keyword == keyword:lower() then - pages = search_cache[player_index].pages - found = search_cache[player_index].found - else - pages = { {} } - local current_page = 1 - local page_count = 0 - local commands = Commands.search(keyword, player) - -- loops other all commands returned by search, includes game commands - for _, command_data in pairs(commands) do - -- if the number of results if greater than the number already added then it moves onto a new page - if page_count >= results_per_page then - page_count = 0 - current_page = current_page + 1 - table.insert(pages, {}) - end - -- adds the new command to the page - page_count = page_count + 1 - found = found + 1 - local alias_format = #command_data.aliases > 0 and { "expcom-chelp.alias", table.concat(command_data.aliases, ", ") } or "" - table.insert(pages[current_page], { - "expcom-chelp.format", - command_data.name, - command_data.description, - command_data.help, - alias_format, - }) - end - - -- adds the result to the cache - search_cache[player_index] = { - keyword = keyword:lower(), - pages = pages, - found = found, - } - end - - -- print the requested page - keyword = keyword == "" and "" or keyword - Commands.print({ "expcom-chelp.title", keyword }, "cyan") - - if pages[page] then - for _, command in pairs(pages[page]) do - Commands.print(command) - end - - Commands.print({ "expcom-chelp.footer", found, page, #pages }, "cyan") - else - Commands.print({ "expcom-chelp.footer", found, page, #pages }, "cyan") - return Commands.error{ "expcom-chelp.out-of-range", page } - end - -- blocks command complete message - return Commands.success - end) - --- way to access global -return search_cache diff --git a/exp_legacy/module/modules/commands/home.lua b/exp_legacy/module/modules/commands/home.lua deleted file mode 100644 index f0bf766f..00000000 --- a/exp_legacy/module/modules/commands/home.lua +++ /dev/null @@ -1,83 +0,0 @@ ---[[-- Commands Module - Home - - Adds a command that allows setting and teleporting to your home position - @commands Home -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Storage = require("modules/exp_util/storage") -require("modules.exp_legacy.config.expcore.command_general_parse") - -local homes = {} -Storage.register(homes, function(tbl) - homes = tbl -end) - -local function teleport(player, position) - local surface = player.physical_surface - local pos = surface.find_non_colliding_position("character", position, 32, 1) - if not position then return false end - if player.driving then player.driving = false end -- kicks a player out a vehicle if in one - player.teleport(pos, surface) - return true -end - -local function floor_pos(position) - return { - x = math.floor(position.x), - y = math.floor(position.y), - } -end - ---- Teleports you to your home location --- @command home -Commands.new_command("home", { "expcom-home.description-home" }, "Teleports you to your home location") - :register(function(player) - local home = homes[player.index] - if not home or not home[1] then - return Commands.error{ "expcom-home.no-home" } - end - local rtn = floor_pos(player.physical_position) - teleport(player, home[1]) - home[2] = rtn - Commands.print{ "expcom-home.return-set", rtn.x, rtn.y } - end) - ---- Sets your home location to your current position --- @command home-set -Commands.new_command("home-set", { "expcom-home.description-home-set" }, "Sets your home location to your current position") - :register(function(player) - local home = homes[player.index] - if not home then - home = {} - homes[player.index] = home - end - local pos = floor_pos(player.physical_position) - home[1] = pos - Commands.print{ "expcom-home.home-set", pos.x, pos.y } - end) - ---- Returns your current home location --- @command home-get -Commands.new_command("home-get", { "expcom-home.description-home-get" }, "Returns your current home location") - :register(function(player) - local home = homes[player.index] - if not home or not home[1] then - return Commands.error{ "expcom-home.no-home" } - end - local pos = home[1] - Commands.print{ "expcom-home.home-get", pos.x, pos.y } - end) - ---- Teleports you to previous location --- @command return -Commands.new_command("return", { "expcom-home.description-return" }, "Teleports you to previous location") - :register(function(player) - local home = homes[player.index] - if not home or not home[2] then - return Commands.error{ "expcom-home.no-return" } - end - local rtn = floor_pos(player.physical_position) - teleport(player, home[2]) - home[2] = rtn - Commands.print{ "expcom-home.return-set", rtn.x, rtn.y } - end) diff --git a/exp_legacy/module/modules/commands/interface.lua b/exp_legacy/module/modules/commands/interface.lua deleted file mode 100644 index 01787747..00000000 --- a/exp_legacy/module/modules/commands/interface.lua +++ /dev/null @@ -1,117 +0,0 @@ ---[[-- Commands Module - Interface - - Adds a command that acts as a direct link to the the active softmod, for debug use - @commands Interface -]] - -local ExpUtil = require("modules/exp_util") -local Storage = require("modules/exp_util/storage") -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands - --- modules that are loaded into the interface env to be accessed -local interface_modules = { - ["Commands"] = Commands, - ["output"] = Commands.print, - ["Group"] = "modules.exp_legacy.expcore.permission_groups", - ["Roles"] = "modules.exp_legacy.expcore.roles", - ["Gui"] = "modules.exp_legacy.expcore.gui", - ["Datastore"] = "modules.exp_legacy.expcore.datastore", - ["External"] = "modules.exp_legacy.expcore.external", -} - --- loads all the modules given in the above table -for key, value in pairs(interface_modules) do - if type(value) == "string" then - interface_modules[key] = ExpUtil.optional_require(value) - end -end - -local interface_env = {} -- used as a persistent sandbox for interface commands -local interface_callbacks = {} -- saves callbacks which can load new values per use -Storage.register(interface_env, function(tbl) - interface_env = tbl -end) - ---- Adds a static module that can be accessed with the interface --- @tparam string name The name that the value is assigned to --- @tparam any value The value that will be accessible in the interface env --- callback param - player: LuaPlayer - the player who used the command -local function add_interface_module(name, value) - interface_modules[name] = value -end - ---- Adds a dynamic value that is calculated when the interface is used --- @tparam string name The name that the value is assigned to --- @tparam function callback The function that will be called to get the value -local function add_interface_callback(name, callback) - if type(callback) == "function" then - interface_callbacks[name] = callback - end -end - ---- Internal, this is a meta function for __index when self[key] is nil -local function get_index(_, key) - if interface_env[key] then - return interface_env[key] - elseif interface_modules[key] then - return interface_modules[key] - elseif _G[key] then - return _G[key] - end -end - ---- Sends an invocation to be ran and returns the result. --- @command interface --- @tparam string invocation the command that will be run -Commands.new_command("interface", { "expcom-interface.description" }, "Sends an invocation to be ran and returns the result.") - :add_param("invocation", false) - :enable_auto_concat() - :set_flag("admin_only") - :register(function(player, invocation) - -- If the invocation has no white space then prepend return to it - if not invocation:find("%s") and not invocation:find("return") then - invocation = "return " .. invocation - end - - -- _env will be the new _ENV that the invocation will run inside of - local _env = setmetatable({}, { - __index = get_index, - __newindex = interface_env, - }) - - -- If the command is ran by a player then load the dynamic values - if player then - for name, callback in pairs(interface_callbacks) do - local _, rtn = pcall(callback, player) - rawset(_env, name, rtn) - end - end - - -- Compile the invocation with the custom _env value - local invocation_func, compile_error = load(invocation, "interface", nil, _env) - if compile_error then return Commands.error(compile_error) end - --- @cast invocation_func -nil - - -- Run the invocation - local success, rtn = pcall(invocation_func) - if not success then - local err = rtn:gsub("%.%.%..-/temp/currently%-playing", "") - return Commands.error(err) - end - return Commands.success(rtn) - end) - --- Adds some basic callbacks for the interface -add_interface_callback("player", function(player) return player end) -add_interface_callback("surface", function(player) return player.surface end) -add_interface_callback("force", function(player) return player.force end) -add_interface_callback("position", function(player) return player.position end) -add_interface_callback("entity", function(player) return player.selected end) -add_interface_callback("tile", function(player) return player.surface.get_tile(player.position) end) - --- Module Return -return { - add_interface_module = add_interface_module, - add_interface_callback = add_interface_callback, - interface_env = interface_env, - clean_stack_trace = function(str) return str:gsub("%.%.%..-/temp/currently%-playing", "") end, -} diff --git a/exp_legacy/module/modules/commands/jail.lua b/exp_legacy/module/modules/commands/jail.lua deleted file mode 100644 index c7e66f83..00000000 --- a/exp_legacy/module/modules/commands/jail.lua +++ /dev/null @@ -1,48 +0,0 @@ ---[[-- Commands Module - Jail - - Adds a commands that allow admins to jail and unjail - @commands Jail -]] - -local ExpUtil = require("modules/exp_util") -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail -local format_player_name = ExpUtil.format_player_name_locale --- @dep expcore.common -require("modules.exp_legacy.config.expcore.command_role_parse") - ---- Puts a player into jail and removes all other roles. --- @command jail --- @tparam LuaPlayer player the player that will be jailed --- @tparam[opt] string reason the reason why the player is being jailed -Commands.new_command("jail", { "expcom-jail.description-jail" }, "Puts a player into jail and removes all other roles.") - :add_param("player", false, "player-role") - :add_param("reason", true) - :enable_auto_concat() - :register(function(player, action_player, reason) - reason = reason or "Non Given." - local action_player_name_color = format_player_name(action_player) - local by_player_name_color = format_player_name(player) - local player_name = player and player.name or "" - if Jail.jail_player(action_player, player_name, reason) then - game.print{ "expcom-jail.give", action_player_name_color, by_player_name_color, reason } - else - return Commands.error{ "expcom-jail.already-jailed", action_player_name_color } - end - end) - ---- Removes a player from jail. --- @command unjail --- @tparam LuaPlayer the player that will be unjailed -Commands.new_command("unjail", { "expcom-jail.description-unjail" }, "Removes a player from jail.") - :add_param("player", false, "player-role") - :add_alias("clear-jail", "remove-jail") - :enable_auto_concat() - :register(function(player, action_player) - local action_player_name_color = format_player_name(action_player) - local by_player_name_color = format_player_name(player) - local player_name = player and player.name or "" - if Jail.unjail_player(action_player, player_name) then - game.print{ "expcom-jail.remove", action_player_name_color, by_player_name_color } - else - return Commands.error{ "expcom-jail.not-jailed", action_player_name_color } - end - end) diff --git a/exp_legacy/module/modules/commands/kill.lua b/exp_legacy/module/modules/commands/kill.lua deleted file mode 100644 index b5892fcc..00000000 --- a/exp_legacy/module/modules/commands/kill.lua +++ /dev/null @@ -1,34 +0,0 @@ ---[[-- Commands Module - Kill - - Adds a command that allows players to kill them selfs and others - @commands Kill -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles -require("modules.exp_legacy.config.expcore.command_general_parse") -require("modules.exp_legacy.config.expcore.command_role_parse") - ---- Kills yourself or another player. --- @command kill --- @tparam[opt=self] LuaPlayer player the player to kill, must be alive to be valid -Commands.new_command("kill", { "expcom-kill.description" }, "Kills yourself or another player.") - :add_param("player", true, "player-role-alive") - :set_defaults{ player = function(player) - -- default is the player unless they are dead - if player.character and player.character.health > 0 then - return player - end - end } - :register(function(player, action_player) - if not action_player then - -- can only be nil if no player given and the user is dead - return Commands.error{ "expcom-kill.already-dead" } - end - if player == action_player then - action_player.character.die() - elseif Roles.player_allowed(player, "command/kill/always") then - action_player.character.die() - else - return Commands.error{ "expcore-commands.unauthorized" } - end - end) diff --git a/exp_legacy/module/modules/commands/last-location.lua b/exp_legacy/module/modules/commands/last-location.lua deleted file mode 100644 index 67a10134..00000000 --- a/exp_legacy/module/modules/commands/last-location.lua +++ /dev/null @@ -1,20 +0,0 @@ ---[[-- Commands Module - Last location - - Adds a command that will return the last location of a player - @commands LastLocation -]] - -local ExpUtil = require("modules/exp_util") -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local format_player_name = ExpUtil.format_player_name_locale --- @dep expcore.common -require("modules.exp_legacy.config.expcore.command_general_parse") - ---- Get the last location of a player. --- @command last-location --- @tparam LuaPlayer player the player that you want a location of -Commands.new_command("last-location", { "expcom-lastlocation.description" }, "Sends you the last location of a player") - :add_alias("location") - :add_param("player", false, "player") - :register(function(_, action_player) - local action_player_name_color = format_player_name(action_player) - return Commands.success{ "expcom-lastlocation.response", action_player_name_color, string.format("%.1f", action_player.physical_position.x), string.format("%.1f", action_player.physical_position.y) } - end) diff --git a/exp_legacy/module/modules/commands/me.lua b/exp_legacy/module/modules/commands/me.lua deleted file mode 100644 index b2591f6a..00000000 --- a/exp_legacy/module/modules/commands/me.lua +++ /dev/null @@ -1,17 +0,0 @@ ---[[-- Commands Module - Me - - Adds a command that adds * around your message in the chat - @commands Me -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands - ---- Sends an action message in the chat --- @command me --- @tparam string action the action that follows your name in chat -Commands.new_command("me", { "expcom-me.description" }, "Sends an action message in the chat") - :add_param("action", false) - :enable_auto_concat() - :register(function(player, action) - local player_name = player and player.name or "" - game.print(string.format("* %s %s *", player_name, action), player.chat_color) - end) diff --git a/exp_legacy/module/modules/commands/pollution.lua b/exp_legacy/module/modules/commands/pollution.lua deleted file mode 100644 index 0704d0bc..00000000 --- a/exp_legacy/module/modules/commands/pollution.lua +++ /dev/null @@ -1,35 +0,0 @@ ---[[-- Commands Module - Pollution Handle - - Adds a command that allows modifying pollution - @commands Pollution Handle -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") - -Commands.new_command("pollution-clear", { "expcom-pol.description-clr" }, "Clear pollution") - :set_flag("admin_only") - :add_alias("pol-clr") - :add_param("surface", true, "surface") - :set_defaults{ surface = function(player) - -- Intentionally left as player.surface to allow use in remote view - return player.surface - end } - :register(function(player, surface) - surface.clear_pollution() - game.print{ "expcom-pol.clr", player.name } - return Commands.success - end) - -Commands.new_command("pollution-off", { "expcom-pol.description-off" }, "Disable pollution") - :set_flag("admin_only") - :add_alias("pol-off") - :register(function(player) - game.map_settings.pollution.enabled = false - - for _, v in pairs(game.surfaces) do - v.clear_pollution() - end - - game.print{ "expcom-pol.off", player.name } - return Commands.success - end) diff --git a/exp_legacy/module/modules/commands/ratio.lua b/exp_legacy/module/modules/commands/ratio.lua deleted file mode 100644 index dc63dfa6..00000000 --- a/exp_legacy/module/modules/commands/ratio.lua +++ /dev/null @@ -1,83 +0,0 @@ -local Commands = require("modules.exp_legacy.expcore.commands") - -local function Modules(moduleInventory) -- returns the multiplier of the modules - local effect1 = moduleInventory.get_item_count("productivity-module") -- type 1 - local effect2 = moduleInventory.get_item_count("productivity-module-2") -- type 2 - local effect3 = moduleInventory.get_item_count("productivity-module-3") -- type 3 - - local multi = effect1 * 4 + effect2 * 6 + effect3 * 10 - return multi / 100 + 1 -end - -local function AmountOfMachines(itemsPerSecond, output) - if (itemsPerSecond) then - return itemsPerSecond / output - end -end - -Commands.new_command("ratio", { "expcom-ratio.description" }, - "This command will give the input and output ratios of the selected machine. Use the parameter for calculating the machines needed for that amount of items per second.") - :add_param("itemsPerSecond", true, "number") - :register(function(player, itemsPerSecond) - local machine = player.selected -- selected machine - - if not machine then -- nil check - return Commands.error{ "expcom-ratio.notSelecting" } - end - - if machine.type ~= "assembling-machine" and machine.type ~= "furnace" then - return Commands.error{ "expcom-ratio.notSelecting" } - end - - local recipe = machine.get_recipe() -- recipe - - if not recipe then -- nil check - return Commands.error{ "expcom-ratio.notSelecting" } - end - - local items = recipe.ingredients -- items in that recipe - local products = recipe.products -- output items - local amountOfMachines - local moduleInventory = machine.get_module_inventory() -- the module Inventory of the machine - local multi = Modules(moduleInventory) -- function for the productively modals - - if itemsPerSecond then - amountOfMachines = math.ceil(AmountOfMachines(itemsPerSecond, 1 / recipe.energy * machine.crafting_speed * products[1].amount * multi)) -- amount of machines - end - - if not amountOfMachines then - amountOfMachines = 1 -- set to 1 to make it not nil - end - - ----------------------------items---------------------------- - for i, item in ipairs(items) do - local sprite -- string to make the icon work either fluid ore item - - if item.type == "item" then - sprite = "expcom-ratio.item-in" - else - sprite = "expcom-ratio.fluid-in" - end - - local ips = item.amount / recipe.energy * machine.crafting_speed * amountOfMachines -- math on the items/fluids per second - Commands.print{ sprite, math.round(ips, 3), item.name } -- full string - end - - ----------------------------products---------------------------- - for i, product in ipairs(products) do - local sprite -- string to make the icon work either fluid ore item - - if product.type == "item" then - sprite = "expcom-ratio.item-out" - else - sprite = "expcom-ratio.fluid-out" - end - - local output = 1 / recipe.energy * machine.crafting_speed * product.amount * multi -- math on the outputs per second - Commands.print{ sprite, math.round(output * amountOfMachines, 3), product.name } -- full string - end - - if amountOfMachines ~= 1 then - Commands.print{ "expcom-ratio.machines", amountOfMachines } - end - end) diff --git a/exp_legacy/module/modules/commands/repair.lua b/exp_legacy/module/modules/commands/repair.lua deleted file mode 100644 index 3e3aad66..00000000 --- a/exp_legacy/module/modules/commands/repair.lua +++ /dev/null @@ -1,54 +0,0 @@ ---[[-- Commands Module - Repair - - Adds a command that allows an admin to repair and revive a large area - @commands Repair -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local config = require("modules.exp_legacy.config.repair") --- @dep config.repair -require("modules.exp_legacy.config.expcore.command_general_parse") - -local max_time_to_live = 4294967295 -- unit32 max ---- Repairs entities on your force around you --- @command repair --- @tparam number range the range to repair stuff in, there is a max limit to this -Commands.new_command("repair", { "expcom-repair.description" }, "Repairs entities on your force around you") - :add_param("range", false, "integer-range", 1, config.max_range) - :register(function(player, range) - local revive_count = 0 - local heal_count = 0 - local range2 = range ^ 2 - -- Intentionally left as player.surface to allow use in remote view - local surface = player.surface - -- Intentionally left as player.position to allow use in remote view - local center = player.position - local area = { { x = center.x - range, y = center.y - range }, { x = center.x + range, y = center.y + range } } - if config.allow_ghost_revive then - local ghosts = surface.find_entities_filtered{ area = area, type = "entity-ghost", force = player.force } - for _, ghost in pairs(ghosts) do - if ghost.valid then - local x = ghost.position.x - center.x - local y = ghost.position.y - center.y - if x ^ 2 + y ^ 2 <= range2 then - if config.allow_blueprint_repair or ghost.time_to_live ~= max_time_to_live then - revive_count = revive_count + 1 - if not config.disallow[ghost.ghost_name] then ghost.revive() end - end - end - end - end - end - if config.allow_heal_entities then - local entities = surface.find_entities_filtered{ area = area, force = player.force } - for _, entity in pairs(entities) do - if entity.valid then - local x = entity.position.x - center.x - local y = entity.position.y - center.y - if entity.health and entity.get_health_ratio() ~= 1 and x ^ 2 + y ^ 2 <= range2 then - heal_count = heal_count + 1 - entity.health = max_time_to_live - end - end - end - end - return Commands.success{ "expcom-repair.result", revive_count, heal_count } - end) diff --git a/exp_legacy/module/modules/commands/reports.lua b/exp_legacy/module/modules/commands/reports.lua deleted file mode 100644 index 5078039d..00000000 --- a/exp_legacy/module/modules/commands/reports.lua +++ /dev/null @@ -1,99 +0,0 @@ ---[[-- Commands Module - Reports - - Adds a commands that allow players to report other players - @commands Reports -]] - -local ExpUtil = require("modules/exp_util") -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Reports = require("modules.exp_legacy.modules.control.reports") --- @dep modules.control.reports -local format_player_name = ExpUtil.format_player_name_locale --- @dep expcore.common -require("modules.exp_legacy.config.expcore.command_general_parse") - ---- Print a message to all players who match the value of admin -local function print_to_players(admin, message) - for _, player in ipairs(game.connected_players) do - if player.admin == admin then - player.print(message) - end - end -end - ---- Reports a player and notifies moderators --- @command report --- @tparam LuaPlayer player the player to report, some players are immune --- @tparam string reason the reason the player is being reported -Commands.new_command("report", { "expcom-report.description-report" }, "Reports a player and notifies moderators") - :add_param("player", false, function(input, player, reject) - input = Commands.parse("player", input, player, reject) - if not input then return end - if Roles.player_has_flag(input, "report-immune") then - return reject{ "expcom-report.player-immune" } - elseif player == input then - return reject{ "expcom-report.self-report" } - else - return input - end - end) - :add_param("reason", false) - :add_alias("report-player") - :enable_auto_concat() - :register(function(player, action_player, reason) - local action_player_name_color = format_player_name(action_player) - local by_player_name_color = format_player_name(player) - if Reports.report_player(action_player, player.name, reason) then - print_to_players(false, { "expcom-report.non-admin", action_player_name_color, reason }) - print_to_players(true, { "expcom-report.admin", action_player_name_color, by_player_name_color, reason }) - else - return Commands.error{ "expcom-report.already-reported" } - end - end) - ---- Gets a list of all reports that a player has on them. If no player then lists all players and the number of reports on them. --- @command get-reports --- @tparam LuaPlayer player the player to get the report for -Commands.new_command("get-reports", { "expcom-report.description-get-reports" }, - "Gets a list of all reports that a player has on them. If no player then lists all players and the number of reports on them.") - :add_param("player", true, "player") - :add_alias("reports", "list-reports") - :register(function(_, player) - if player then - local reports = Reports.get_reports(player) - local player_name_color = format_player_name(player) - Commands.print{ "expcom-report.player-report-title", player_name_color } - for player_name, reason in pairs(reports) do - local by_player_name_color = format_player_name(player_name) - Commands.print{ "expcom-report.list", by_player_name_color, reason } - end - else - local user_reports = Reports.user_reports - Commands.print{ "expcom-report.player-count-title" } - for player_name in pairs(user_reports) do - local player_name_color = format_player_name(player_name) - local report_count = Reports.count_reports(player_name) - Commands.print{ "expcom-report.list", player_name_color, report_count } - end - end - end) - ---- Clears all reports from a player or just the report from one player. --- @command clear-reports --- @tparam LuaPlayer player the player to clear the report(s) from --- @tparam[opt=all] LuaPlayer from-player remove only the report made by this player -Commands.new_command("clear-reports", { "expcom-report.description-clear-reports" }, "Clears all reports from a player or just the report from one player.") - :add_param("player", false, "player") - :add_param("from-player", true, "player") - :register(function(player, action_player, from_player) - if from_player then - if not Reports.remove_report(action_player, from_player.name, player.name) then - return Commands.error{ "expcom-report.not-reported" } - end - else - if not Reports.remove_all(action_player, player.name) then - return Commands.error{ "expcom-report.not-reported" } - end - end - local action_player_name_color = format_player_name(action_player) - local by_player_name_color = format_player_name(player) - game.print{ "expcom-report.removed", action_player_name_color, by_player_name_color } - end) diff --git a/exp_legacy/module/modules/commands/research.lua b/exp_legacy/module/modules/commands/research.lua deleted file mode 100644 index 91bbe1bd..00000000 --- a/exp_legacy/module/modules/commands/research.lua +++ /dev/null @@ -1,45 +0,0 @@ -local Storage = require("modules/exp_util/storage") -local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local config = require("modules.exp_legacy.config.research") --- @dep config.research - -local research = {} -Storage.register(research, function(tbl) - research = tbl -end) - -local function res_queue(force, by_script) - local res_q = force.research_queue - local res = force.technologies["mining-productivity-4"] - - if #res_q < config.queue_amount then - for i = 1, config.queue_amount - #res_q do - force.add_research(res) - - if not (by_script) then - game.print{ "expcom-res.inf-q", res.name, res.level + i } - end - end - end -end - -Commands.new_command("auto-research", { "expcom-res.description-ares" }, "Automatically queue up research") - :add_alias("ares") - :register(function(player) - research.res_queue_enable = not research.res_queue_enable - - if research.res_queue_enable then - res_queue(player.force, true) - end - - game.print{ "expcom-res.res", player.name, research.res_queue_enable } - return Commands.success - end) - -Event.add(defines.events.on_research_finished, function(event) - if research.res_queue_enable then - if event.research.force.rockets_launched > 0 and event.research.force.technologies["mining-productivity-4"].level > 4 then - res_queue(event.research.force, event.by_script) - end - end -end) diff --git a/exp_legacy/module/modules/commands/roles.lua b/exp_legacy/module/modules/commands/roles.lua deleted file mode 100644 index 78937fe5..00000000 --- a/exp_legacy/module/modules/commands/roles.lua +++ /dev/null @@ -1,80 +0,0 @@ ---[[-- Commands Module - Roles - - Adds a commands that allow interaction with the role system - @commands Roles -]] - -local ExpUtil = require("modules/exp_util") -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles -local Colours = require("modules/exp_util/include/color") -local format_player_name, format_color = ExpUtil.format_player_name_locale, ExpUtil.format_rich_text_color - ---- Assigns a role to a player --- @command assign-role --- @tparam LuaPlayer player the player to assign the role to --- @tparam string role the name of the role to assign to the player, supports auto complete after enter -Commands.new_command("assign-role", { "expcom-roles.description-assign-role" }, "Assigns a role to a player") - :add_param("player", false, "player-role") - :add_param("role", false, "role") - :set_flag("admin-only") - :add_alias("rpromote", "assign", "role", "add-role") - :register(function(player, action_player, role) - local player_highest = Roles.get_player_highest_role(player) - - if player_highest.index < role.index then - Roles.assign_player(action_player, role, player.name) - else - return Commands.error{ "expcom-roles.higher-role" } - end - end) - ---- Unassigns a role from a player --- @command unassign-role --- @tparam LuaPlayer player the player to unassign the role from --- @tparam string role the name of the role to unassign from the player, supports auto complete after enter -Commands.new_command("unassign-role", { "expcom-roles.description-unassign-role" }, "Unassigns a role from a player") - :add_param("player", false, "player-role") - :add_param("role", false, "role") - :set_flag("admin-only") - :add_alias("rdemote", "unassign", "rerole", "remove-role") - :register(function(player, action_player, role) - local player_highest = Roles.get_player_highest_role(player) - - if player_highest.index < role.index then - Roles.unassign_player(action_player, role, player.name) - else - return Commands.error{ "expcom-roles.higher-role" } - end - end) - ---- Lists all roles in they correct order --- @command list-roles --- @tparam[opt=all] LuaPlayer player list only the roles which this player has -Commands.new_command("list-roles", { "expcom-roles.description-list-roles" }, "Lists all roles in they correct order") - :add_param("player", true, "player") - :add_alias("lsroles", "roles") - :register(function(_, player) - local roles = Roles.config.order - local message = { "expcom-roles.list" } - - if player then - roles = Roles.get_player_roles(player) - end - - for index, role in pairs(roles) do - role = Roles.get_role_from_any(role) - local colour = role.custom_color or Colours.white - local role_name = format_color(role.name, colour) - if index == 1 then - message = { "expcom-roles.list", role_name } - if player then - local player_name_colour = format_player_name(player) - message = { "expcom-roles.list-player", player_name_colour, role_name } - end - else - message = { "expcom-roles.list-element", message, role_name } - end - end - - return Commands.success(message) - end) diff --git a/exp_legacy/module/modules/commands/search.lua b/exp_legacy/module/modules/commands/search.lua deleted file mode 100644 index 36a7a724..00000000 --- a/exp_legacy/module/modules/commands/search.lua +++ /dev/null @@ -1,170 +0,0 @@ ---[[-- Commands Module - Inventory Search - - Adds commands that will search all players inventories for an item - @commands InventorySearch -]] - -local ExpUtil = require("modules/exp_util") -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local format_number = require("util").format_number --- @dep util -local format_player_name = ExpUtil.format_player_name_locale -require("modules.exp_legacy.config.expcore.command_general_parse") - ---- Input parse for items by name -local function item_parse(input, _, reject) - if input == nil then return end - local lower_input = input:lower():gsub(" ", "-") - - -- Simple Case - internal name is given - local item = prototypes.item[lower_input] - if item then return item end - - -- Second Case - rich text is given - local item_name = input:match("%[item=([0-9a-z-]+)%]") - item = prototypes.item[item_name] - if item then return item end - - -- No item found, we do not attempt to search all prototypes as this will be expensive - return reject{ "expcom-inv-search.reject-item", lower_input } -end - ---- Search all players for this item -local function search_players(players, item) - local head = 1 - local found = {} - - -- Check the item count of all players - for _, player in pairs(players) do - local item_count = player.get_item_count(item.name) - if item_count > 0 then - -- Add the player to the array as they have the item - found[head] = { player = player, count = item_count, online_time = player.online_time } - head = head + 1 - end - end - - return found -end - ---- Custom sort function which only retains 5 greatest values -local function sort_players(players, func) - local sorted = {} - local values = {} - local threshold = nil - - -- Loop over all provided players - for index, player in ipairs(players) do - local value = func(player) - -- Check if the item will make the top 5 elements - if index <= 5 or value > threshold then - local inserted = false - values[player] = value - -- Find where in the top 5 to insert the element - for next_index, next_player in ipairs(sorted) do - if value > values[next_player] then - table.insert(sorted, next_index, player) - inserted = true - break - end - end - - -- Insert the element, this can only be called when index <= 5 - if not inserted then - sorted[#sorted + 1] = player - end - -- Update the threshold - if sorted[6] then - threshold = values[sorted[5]] - values[sorted[6]] = nil - sorted[6] = nil - else - threshold = values[sorted[#sorted]] - end - end - end - - return sorted -end - -local display_players_time_format = ExpUtil.format_time_factory_locale{ format = "short", hours = true, minutes = true } - ---- Display to the player the top players which were found -local function display_players(player, players, item) - player.print{ "expcom-inv-search.results-heading", item.name } - for index, data in ipairs(players) do - local player_name_color = format_player_name(data.player) - local amount = format_number(data.count) - local time = display_players_time_format(data.online_time) - player.print{ "expcom-inv-search.results-item", index, player_name_color, amount, time } - end -end - ---- Return the amount of an item a player has -local function amount_sort(data) - return data.count -end - ---- Get a list of players sorted by the quantity of an item in their inventory --- @command search-amount --- @tparam LuaItemPrototype item The item to search for in players inventories -Commands.new_command("search-amount", { "expcom-inv-search.description-ia" }, "Display players sorted by the quantity of an item held") - :add_alias("ia") - :add_param("item", false, item_parse) - :enable_auto_concat() - :register(function(player, item) - local players = search_players(game.players, item) - if #players == 0 then return { "expcom-inv-search.results-none", item.name } end - local top_players = sort_players(players, amount_sort) - display_players(player, top_players, item) - end) - ---- Return the index of the player, higher means they joined more recently -local function recent_sort(data) - return data.player.index -end - ---- Get a list of players who have the given item, sorted by how recently they joined --- @command search-recent --- @tparam LuaItemPrototype item The item to search for in players inventories -Commands.new_command("search-recent", { "expcom-inv-search.description-ir" }, "Display players who hold an item sorted by join time") - :add_alias("ir") - :add_param("item", false, item_parse) - :enable_auto_concat() - :register(function(player, item) - local players = search_players(game.players, item) - if #players == 0 then return { "expcom-inv-search.results-none", item.name } end - local top_players = sort_players(players, recent_sort) - display_players(player, top_players, item) - end) - ---- Return the the amount of an item a player has divided by their playtime -local function combined_sort(data) - return data.count / data.online_time -end - ---- Get a list of players sorted by quantity held and play time --- @command search --- @tparam LuaItemPrototype item The item to search for in players inventories -Commands.new_command("search", { "expcom-inv-search.description-i" }, "Display players sorted by the quantity of an item held and playtime") - :add_alias("i") - :add_param("item", false, item_parse) - :enable_auto_concat() - :register(function(player, item) - local players = search_players(game.players, item) - if #players == 0 then return { "expcom-inv-search.results-none", item.name } end - local top_players = sort_players(players, combined_sort) - display_players(player, top_players, item) - end) - ---- Get a list of online players sorted by quantity held and play time --- @command search-online --- @tparam LuaItemPrototype item The item to search for in players inventories -Commands.new_command("search-online", { "expcom-inv-search.description-io" }, "Display online players sorted by the quantity of an item held and playtime") - :add_alias("io") - :add_param("item", false, item_parse) - :enable_auto_concat() - :register(function(player, item) - local players = search_players(game.connected_players, item) - if #players == 0 then return { "expcom-inv-search.results-none", item.name } end - local top_players = sort_players(players, combined_sort) - display_players(player, top_players, item) - end) diff --git a/exp_legacy/module/modules/commands/spawn.lua b/exp_legacy/module/modules/commands/spawn.lua deleted file mode 100644 index b9016ee6..00000000 --- a/exp_legacy/module/modules/commands/spawn.lua +++ /dev/null @@ -1,66 +0,0 @@ ---[[-- Commands Module - Spawn - - Adds a command that allows players to teleport to their spawn point - @commands Spawn -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles - -local function teleport(player) - local surface = player.surface - local spawn = player.force.get_spawn_position(surface) - local position = surface.find_non_colliding_position("character", spawn, 32, 1) - -- return false if no new position - if not position then - return false - end - if player.vehicle then - -- Teleport the entity - local entity = player.vehicle - local goto_position = surface.find_non_colliding_position(entity.name, position, 32, 1) - -- Surface teleport can only be done for players and cars at the moment. (with surface as an peramitor it gives this error) - if entity.type == "car" then - entity.teleport(goto_position, surface) - elseif surface.index == entity.surface.index then - -- Try teleport the entity - if not entity.teleport(goto_position) then - player.driving = false - player.teleport(position, surface) - end - end - else - -- Teleport the player - player.teleport(position, surface) - end - - return true -end - ---- Teleport to spawn --- @command go-to-spawn --- @tparam[opt=self] LuaPlayer player the player to teleport to their spawn point -Commands.new_command("go-to-spawn", { "expcom-spawn.description" }, "Teleport to spawn") - :add_param("player", true, "player-role-alive") - :set_defaults{ - player = function(player) - if player.connected and player.character and player.character.health > 0 then - return player - end - end, - } - :add_alias("spawn", "tp-spawn") - :register(function(player, action_player) - if not action_player then - return Commands.error{ "expcom-spawn.unavailable" } - elseif action_player == player then - if not teleport(player) then - return Commands.error{ "expcom-spawn.unavailable" } - end - elseif Roles.player_allowed(player, "command/go-to-spawn/always") then - if not teleport(action_player) then - return Commands.error{ "expcom-spawn.unavailable" } - end - else - return Commands.error{ "expcore-commands.unauthorized" } - end - end) diff --git a/exp_legacy/module/modules/commands/spectate.lua b/exp_legacy/module/modules/commands/spectate.lua deleted file mode 100644 index d0f2770f..00000000 --- a/exp_legacy/module/modules/commands/spectate.lua +++ /dev/null @@ -1,33 +0,0 @@ ---[[-- Commands Module - Spectate - - Adds commands relating to spectate and follow - @commands Spectate -]] - -local Spectate = require("modules.exp_legacy.modules.control.spectate") --- @dep modules.control.spectate -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") - ---- Toggles spectator mode for the caller --- @command spectate -Commands.new_command("spectate", { "expcom-spectate.description-spectate" }, "Toggles spectator mode") - :register(function(player) - if Spectate.is_spectating(player) then - Spectate.stop_spectate(player) - else - Spectate.start_spectate(player) - end - end) - ---- Enters follow mode for the caller, following the given player. --- @command follow --- @tparam LuaPlayer player The player that will be followed -Commands.new_command("follow", { "expcom-spectate.description-follow" }, "Start following a player in spectator") - :add_alias("f") - :add_param("player", false, "player-online") - :register(function(player, action_player) - if player == action_player then - return Commands.error{ "expcom-spectate.follow-self" } - else - Spectate.start_follow(player, action_player) - end - end) diff --git a/exp_legacy/module/modules/commands/speed.lua b/exp_legacy/module/modules/commands/speed.lua deleted file mode 100644 index 06c7c560..00000000 --- a/exp_legacy/module/modules/commands/speed.lua +++ /dev/null @@ -1,16 +0,0 @@ ---[[-- Commands Module - Set game speed - - Adds a command that allows changing game speed - @commands Set game speed -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") - -Commands.new_command("game-speed", { "expcom-speed.description" }, "Set game speed") - :add_param("amount", "number-range", 0.2, 8) - :set_flag("admin_only") - :register(function(player, amount) - game.speed = math.round(amount, 3) - game.print{ "expcom-speed.result", player.name, string.format("%.3f", amount) } - return Commands.success - end) diff --git a/exp_legacy/module/modules/commands/surface-clearing.lua b/exp_legacy/module/modules/commands/surface-clearing.lua deleted file mode 100644 index 67b1f25e..00000000 --- a/exp_legacy/module/modules/commands/surface-clearing.lua +++ /dev/null @@ -1,41 +0,0 @@ ---[[-- Commands Module - Clear Item On Ground - - Adds a command that clear item on ground so blueprint can deploy safely - @commands Clear Item On Ground -]] - -local ExpUtil = require("modules/exp_util") -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") - -Commands.new_command("clear-item-on-ground", { "expcom-surface-clearing.description-ci" }, "Clear Item On Ground") - :add_param("range", false, "integer-range", 1, 1000) - :register(function(player, range) - local items = {} --- @type LuaItemStack[] - -- Intentionally left as player.position to allow use in remote view - local entities = player.surface.find_entities_filtered{ position = player.position, radius = range, name = "item-on-ground" } - for _, e in pairs(entities) do - if e.stack then - items[#items + 1] = e.stack - end - end - - ExpUtil.move_items_to_surface{ - items = items, - surface = player.surface, - allow_creation = true, - name = "iron-chest", - } - - return Commands.success - end) - -Commands.new_command("clear-blueprint", { "expcom-surface-clearing.description-cb" }, "Clear Blueprint") - :add_param("range", false, "integer-range", 1, 1000) - :register(function(player, range) - -- Intentionally left as player.position to allow use in remote view - for _, e in pairs(player.surface.find_entities_filtered{ position = player.position, radius = range, type = "entity-ghost" }) do - e.destroy() - end - - return Commands.success - end) diff --git a/exp_legacy/module/modules/commands/teleport.lua b/exp_legacy/module/modules/commands/teleport.lua deleted file mode 100644 index 90b59378..00000000 --- a/exp_legacy/module/modules/commands/teleport.lua +++ /dev/null @@ -1,93 +0,0 @@ ---[[-- Commands Module - Teleport - - Adds a command that allows players to teleport to other players - @commands Teleport -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") - -local function teleport(from_player, to_player) - local surface = to_player.physical_surface - local position = surface.find_non_colliding_position("character", to_player.physical_position, 32, 1) - - -- return false if no new position - if not position then - return false - end - - if from_player.vehicle then - -- Teleport the entity - local entity = from_player.vehicle - local goto_position = surface.find_non_colliding_position(entity.name, position, 32, 1) - - -- Surface teleport can only be done for players and cars at the moment. (with surface as an peramitor it gives this error) - if entity.type == "car" then - entity.teleport(goto_position, surface) - elseif surface.index == entity.surface.index then - -- Try teleport the entity - if not entity.teleport(goto_position) then - from_player.driving = false - from_player.teleport(position, surface) - end - end - else - -- Teleport the player - from_player.teleport(position, surface) - end - return true -end - ---- Teleports a player to another player. --- @command teleport --- @tparam LuaPlayer from_player the player that will be teleported, must be alive --- @tparam LuaPlayer to_player the player to teleport to, must be online (if dead goes to where they died) -Commands.new_command("teleport", { "expcom-tp.description-tp" }, "Teleports a player to another player.") - :add_param("from_player", false, "player-alive") - :add_param("to_player", false, "player-online") - :add_alias("tp") - :set_flag("admin_only") - :register(function(_, from_player, to_player) - if from_player.index == to_player.index then - -- return if attempting to teleport to self - return Commands.error{ "expcom-tp.to-self" } - end - if not teleport(from_player, to_player) then - -- return if the teleport failed - return Commands.error{ "expcom-tp.no-position-found" } - end - end) - ---- Teleports a player to you. --- @command bring --- @tparam LuaPlayer player the player that will be teleported, must be alive -Commands.new_command("bring", { "expcom-tp.description-bring" }, "Teleports a player to you.") - :add_param("player", false, "player-alive") - :set_flag("admin_only") - :register(function(player, from_player) - if from_player.index == player.index then - -- return if attempting to teleport to self - return Commands.error{ "expcom-tp.to-self" } - end - if not teleport(from_player, player) then - -- return if the teleport failed - return Commands.error{ "expcom-tp.no-position-found" } - end - from_player.print("Come here my friend") - end) - ---- Teleports you to a player. --- @command goto --- @tparam LuaPlayer player the player to teleport to, must be online (if dead goes to where they died) -Commands.new_command("goto", { "expcom-tp.description-goto" }, "Teleports you to a player.") - :add_param("player", false, "player-online") - :add_alias("tp-me", "tpme") - :register(function(player, to_player) - if to_player.index == player.index then - -- return if attempting to teleport to self - return Commands.error{ "expcom-tp.to-self" } - end - if not teleport(player, to_player) then - -- return if the teleport failed - return Commands.error{ "expcom-tp.no-position-found" } - end - end) diff --git a/exp_legacy/module/modules/commands/train.lua b/exp_legacy/module/modules/commands/train.lua deleted file mode 100644 index db51fea7..00000000 --- a/exp_legacy/module/modules/commands/train.lua +++ /dev/null @@ -1,23 +0,0 @@ ---[[-- Commands Module - Set Automatic Train - - Adds a command that set all train back to automatic - @commands Set Automatic Train -]] - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") -local format_number = require("util").format_number - -Commands.new_command("set-trains-to-automatic", { "expcom-train.description" }, "Set All Trains to Automatic") - :register(function(player) - local count = 0 - - for _, v in pairs(player.force.get_trains()) do - if v.manual_mode then - count = count + 1 - v.manual_mode = false - end - end - - game.print{ "expcom-train.manual-result", player.name, format_number(count) } - return Commands.success - end) diff --git a/exp_legacy/module/modules/commands/vlayer.lua b/exp_legacy/module/modules/commands/vlayer.lua deleted file mode 100644 index 885b9ade..00000000 --- a/exp_legacy/module/modules/commands/vlayer.lua +++ /dev/null @@ -1,15 +0,0 @@ ---- Adds a virtual layer to store power to save space. --- @commands Vlayer - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") -local vlayer = require("modules.exp_legacy.modules.control.vlayer") - -Commands.new_command("vlayer-info", { "vlayer.description-vi" }, "Vlayer Info") - :register(function(_) - local c = vlayer.get_circuits() - - for k, v in pairs(c) do - Commands.print(v .. " : " .. k) - end - end) diff --git a/exp_legacy/module/modules/commands/warnings.lua b/exp_legacy/module/modules/commands/warnings.lua deleted file mode 100644 index b2f9dd16..00000000 --- a/exp_legacy/module/modules/commands/warnings.lua +++ /dev/null @@ -1,77 +0,0 @@ ---[[-- Commands Module - Warnings - - Adds a commands that allow admins to warn other players - @commands Warnings -]] - -local ExpUtil = require("modules/exp_util") -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local Warnings = require("modules.exp_legacy.modules.control.warnings") --- @dep modules.control.warnings -local format_player_name = ExpUtil.format_player_name_locale -local config = require("modules.exp_legacy.config.warnings") --- @dep config.warnings -require("modules.exp_legacy.config.expcore.command_role_parse") - ---- Gives a warning to a player; may lead to automatic script action. --- @command give-warning --- @tparam LuaPlayer player the player the will recive a warning --- @tparam string reason the reason the player is being given a warning -Commands.new_command("give-warning", { "expcom-warnings.description-give" }, "Gives a warning to a player; may lead to automatic script action.") - :add_param("player", false, "player-role") - :add_param("reason", false) - :add_alias("warn") - :enable_auto_concat() - :register(function(player, action_player, reason) - Warnings.add_warning(action_player, player.name, reason) - local action_player_name_color = format_player_name(action_player) - local by_player_name_color = format_player_name(player) - game.print{ "expcom-warnings.received", action_player_name_color, by_player_name_color, reason } - end) - ---- Gets the number of warnings a player has. If no player then lists all players and the number of warnings they have. --- @command get-warnings --- @tparam[opt=list] LuaPlayer player the player to get the warning for, if nil all players are listed -Commands.new_command("get-warnings", { "expcom-warnings.description-get" }, "Gets the number of warnings a player has. If no player then lists all players and the number of warnings they have.") - :add_param("player", true, "player") - :add_alias("warnings", "list-warnings") - :register(function(_, player) - if player then - local warnings = Warnings.get_warnings(player) - local script_warnings = Warnings.get_script_warnings(player) - local player_name_color = format_player_name(player) - Commands.print{ "expcom-warnings.player", player_name_color, #warnings, #script_warnings, config.temp_warning_limit } - for _, warning in ipairs(warnings) do - Commands.print{ "expcom-warnings.player-detail", format_player_name(warning.by_player_name), warning.reason } - end - else - local rtn = {} - local user_script_warnings = Warnings.user_script_warnings - for player_name, warnings in pairs(Warnings.user_warnings:get_all()) do - rtn[player_name] = { #warnings, 0 } - end - - for player_name, warnings in pairs(user_script_warnings) do - if not rtn[player_name] then - rtn[player_name] = { 0, 0 } - end - rtn[player_name][2] = #warnings - end - - Commands.print{ "expcom-warnings.list-title" } - for player_name, warnings in pairs(rtn) do - local player_name_color = format_player_name(player_name) - Commands.print{ "expcom-warnings.list", player_name_color, warnings[1], warnings[2], config.temp_warning_limit } - end - end - end) - ---- Clears all warnings (and script warnings) from a player --- @command clear-warnings --- @tparam LuaPlayer player the player to clear the warnings from -Commands.new_command("clear-warnings", { "expcom-warnings.description-clear" }, "Clears all warnings (and script warnings) from a player") - :add_param("player", false, "player") - :register(function(player, action_player) - Warnings.clear_warnings(action_player, player.name) - Warnings.clear_script_warnings(action_player) - local action_player_name_color = format_player_name(action_player) - local by_player_name_color = format_player_name(player) - game.print{ "expcom-warnings.cleared", action_player_name_color, by_player_name_color } - end) diff --git a/exp_legacy/module/modules/commands/waterfill.lua b/exp_legacy/module/modules/commands/waterfill.lua deleted file mode 100644 index 137843d1..00000000 --- a/exp_legacy/module/modules/commands/waterfill.lua +++ /dev/null @@ -1,80 +0,0 @@ ---- Adds a waterfill --- @commands Waterfill - -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") -local Selection = require("modules.exp_legacy.modules.control.selection") --- @dep modules.control.selection -local SelectionConvertArea = "ConvertArea" - ---- Align an aabb to the grid by expanding it -local function aabb_align_expand(aabb) - return { - left_top = { x = math.floor(aabb.left_top.x), y = math.floor(aabb.left_top.y) }, - right_bottom = { x = math.ceil(aabb.right_bottom.x), y = math.ceil(aabb.right_bottom.y) }, - } -end - -Commands.new_command("waterfill", { "expcom-waterfill.description" }, "Change tile to water") - :register(function(player) - local inv = player.get_main_inventory() - - if (inv.get_item_count("cliff-explosives")) == 0 then - return player.print{ "expcom-waterfill.waterfill-cliff" } - end - - if Selection.is_selecting(player, SelectionConvertArea) then - Selection.stop(player) - else - Selection.start(player, SelectionConvertArea) - return Commands.success{ "expcom-waterfill.entered-area-selection" } - end - - return Commands.success - end) - ---- When an area is selected to add protection to the area -Selection.on_selection(SelectionConvertArea, function(event) - local area = aabb_align_expand(event.area) - local player = game.players[event.player_index] - - if not player then - return - end - - local entities = event.surface.find_entities_filtered{ area = area, name = "steel-chest" } - - if #entities == 0 then - player.print("No steel chest found") - return - end - - local tiles_to_make = {} - local inv = player.get_main_inventory() - - if not inv then - return - end - - local clf_exp = inv.get_item_count("cliff-explosives") - - for _, entity in pairs(entities) do - if clf_exp >= 1 then - if entity.get_inventory(defines.inventory.chest).is_empty() then - -- Intentionally left as player.position to allow use in report view - if (math.floor(player.position.x) ~= math.floor(entity.position.x)) or (math.floor(player.position.y) ~= math.floor(entity.position.y)) then - table.insert(tiles_to_make, { name = "water-mud", position = entity.position }) - entity.destroy() - else - player.print{ "expcom-waterfill.waterfill-distance" } - end - end - - clf_exp = clf_exp - 1 - inv.remove{ name = "cliff-explosives", count = 1 } - else - break - end - end - - event.surface.set_tiles(tiles_to_make) -end) diff --git a/exp_legacy/module/modules/control/selection.lua b/exp_legacy/module/modules/control/selection.lua index 21c8ddd7..20c709b2 100644 --- a/exp_legacy/module/modules/control/selection.lua +++ b/exp_legacy/module/modules/control/selection.lua @@ -123,8 +123,8 @@ function Selection.is_selecting(player, selection_name) end --- Filter on_player_selected_area to this custom selection, appends the selection arguments --- @tparam string selection_name The name of the selection to listen for --- @tparam function handler The event handler +-- @param string selection_name The name of the selection to listen for +-- @param function handler The event handler function Selection.on_selection(selection_name, handler) Event.add(defines.events.on_player_selected_area, function(event) local selection = selections[event.player_index] diff --git a/exp_legacy/module/modules/control/warps.lua b/exp_legacy/module/modules/control/warps.lua index 3707fe0d..b6cad0a9 100644 --- a/exp_legacy/module/modules/control/warps.lua +++ b/exp_legacy/module/modules/control/warps.lua @@ -31,9 +31,11 @@ WrapData:set_serializer(function(raw_key) return raw_key.warp_id end) local Warps = {} +--- @class ExpScenario_Warps.force_warps: { spawn: string, [number]: string } + -- Storage lookup table for force name to task ids local force_warps = { _uid = 1 } ---- @cast force_warps table +--- @cast force_warps table Storage.register(force_warps, function(tbl) force_warps = tbl end) @@ -61,7 +63,7 @@ WrapData:on_update(function(warp_id, warp, old_warp) local warp_ids = force_warps[force_name] local spawn_id = warp_ids.spawn - local warp_names = {} + local warp_names = {} --- @type table for _, next_warp_id in pairs(warp_ids) do local next_warp = WrapData:get(next_warp_id) if next_warp_id ~= spawn_id then @@ -71,6 +73,7 @@ WrapData:on_update(function(warp_id, warp, old_warp) -- Sort the warp names in alphabetical order local new_warp_ids = table.get_values(table.key_sort(warp_names)) + --- @cast new_warp_ids ExpScenario_Warps.force_warps table.insert(new_warp_ids, 1, spawn_id) new_warp_ids.spawn = spawn_id force_warps[force_name] = new_warp_ids diff --git a/exp_legacy/module/modules/data/bonus.lua b/exp_legacy/module/modules/data/bonus.lua index 3ace723d..6ebf2a34 100644 --- a/exp_legacy/module/modules/data/bonus.lua +++ b/exp_legacy/module/modules/data/bonus.lua @@ -6,8 +6,7 @@ local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event local config = require("modules.exp_legacy.config.bonus") --- @dep config.bonuses -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") +local Commands = require("modules/exp_commands") -- Stores the bonus for the player local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data @@ -47,19 +46,16 @@ PlayerBonus:on_update(function(player_name, player_bonus) end) --- Changes the amount of bonus you receive --- @command bonus --- @tparam number amount range 0-10 the increase for your bonus -Commands.new_command("bonus", "Changes the amount of bonus you receive") - :add_param("amount", "integer-range", 0, 10) +Commands.new("bonus", { "bonus.description" }) + :optional("amount", { "bonus.arg-amount" }, Commands.types.integer_range(0, 10)) :register(function(player, amount) - if not Roles.player_allowed(player, "command/bonus") then - Commands.print{ "expcom-bonus.perm", 1 } - return + --- @cast amount number? + if amount then + PlayerBonus:set(player, amount) + return Commands.status.success{ "bonus.set", amount } + else + return Commands.status.success{ "bonus.get", PlayerBonus:get(player) } end - - PlayerBonus:set(player, amount) - - Commands.print{ "expcom-bonus.set", amount } end) --- When a player respawns re-apply bonus diff --git a/exp_legacy/module/modules/data/greetings.lua b/exp_legacy/module/modules/data/greetings.lua index fd157a95..e8eade90 100644 --- a/exp_legacy/module/modules/data/greetings.lua +++ b/exp_legacy/module/modules/data/greetings.lua @@ -2,8 +2,7 @@ -- @data Greetings local config = require("modules.exp_legacy.config.join_messages") --- @dep config.join_messages -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -require("modules.exp_legacy.config.expcore.command_general_parse") +local Commands = require("modules/exp_commands") --- Stores the join message that the player have local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data @@ -24,20 +23,23 @@ CustomMessages:on_load(function(player_name, player_message) end) --- Set your custom join message --- @command join-message --- @tparam string message The custom join message that will be used -Commands.new_command("join-message", "Sets your custom join message") - :add_param("message", false, "string-max-length", 255) - :enable_auto_concat() +Commands.new("set-join-message", { "join-message.description-add" }) + :optional("message", false, Commands.types.string_max_length(255)) + :enable_auto_concatenation() + :add_aliases{ "join-message" } :register(function(player, message) - if not player then return end - CustomMessages:set(player, message) - return { "join-message.message-set" } + --- @cast message string? + if message then + CustomMessages:set(player, message) + return Commands.status.success{ "join-message.message-set" } + else + return Commands.status.success{ "join-message.message-get", CustomMessages:get(player) } + end end) -Commands.new_command("join-message-clear", "Clear your join message") +--- Removes your custom join message +Commands.new("remove-join-message", { "join-message.description-remove" }) :register(function(player) - if not player then return end CustomMessages:remove(player) - return { "join-message.message-cleared" } + return Commands.status.success{ "join-message.message-cleared" } end) diff --git a/exp_legacy/module/modules/data/personal-logistic.lua b/exp_legacy/module/modules/data/personal-logistic.lua index 53345dfd..731578c5 100644 --- a/exp_legacy/module/modules/data/personal-logistic.lua +++ b/exp_legacy/module/modules/data/personal-logistic.lua @@ -1,4 +1,4 @@ -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands +local Commands = require("modules/exp_commands") local config = require("modules.exp_legacy.config.personal_logistic") --- @dep config.personal-logistic local function pl(type, target, amount) @@ -66,21 +66,20 @@ local function pl(type, target, amount) end end -Commands.new_command("personal-logistic", "Set Personal Logistic (-1 to cancel all) (Select spidertron to edit spidertron)") - :add_param("amount", "integer-range", -1, 10) - :add_alias("pl") +Commands.new("personal-logistic", "Set Personal Logistic (-1 to cancel all) (Select spidertron to edit spidertron)") + :argument("amount", "", Commands.types.integer_range(-1, 10)) + :add_aliases{ "pl" } :register(function(player, amount) + --- @cast amount number if player.force.technologies["logistic-robotics"].researched then if player.selected ~= nil then if player.selected.name == "spidertron" then pl("s", player.selected, amount / 10) - return Commands.success end else pl("p", player, amount / 10) - return Commands.success end else - player.print("Personal Logistic not researched") + return Commands.status.error("Personal Logistic not researched") end end) diff --git a/exp_legacy/module/modules/data/quickbar.lua b/exp_legacy/module/modules/data/quickbar.lua index b32b596e..6a6b38f9 100644 --- a/exp_legacy/module/modules/data/quickbar.lua +++ b/exp_legacy/module/modules/data/quickbar.lua @@ -3,7 +3,7 @@ @data Quickbar ]] -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands +local Commands = require("modules/exp_commands") local config = require("modules.exp_legacy.config.preset_player_quickbar") --- @dep config.preset_player_quickbar --- Stores the quickbar filters for a player @@ -32,7 +32,7 @@ PlayerFilters:on_load(function(player_name, filters) end end) -local ignoredItems = { +local ignored_items = { ["blueprint"] = true, ["blueprint-book"] = true, ["deconstruction-planner"] = true, @@ -41,9 +41,8 @@ local ignoredItems = { } --- Saves your quickbar preset to the script-output folder --- @command save-quickbar -Commands.new_command("save-quickbar", "Saves your Quickbar preset items to file") - :add_alias("save-toolbar") +Commands.new("save-quickbar", "Saves your Quickbar preset items to file") + :add_aliases{ "save-toolbar" } :register(function(player) local filters = {} @@ -51,7 +50,7 @@ Commands.new_command("save-quickbar", "Saves your Quickbar preset items to file" local slot = player.get_quick_bar_slot(i) -- Need to filter out blueprint and blueprint books because the slot is a LuaItemPrototype and does not contain a way to export blueprint data if slot ~= nil then - local ignored = ignoredItems[slot.name] + local ignored = ignored_items[slot.name] if ignored ~= true then filters[i] = slot.name end @@ -64,5 +63,5 @@ Commands.new_command("save-quickbar", "Saves your Quickbar preset items to file" PlayerFilters:remove(player) end - return { "quickbar.saved" } + return Commands.status.success{ "quickbar.saved" } end) diff --git a/exp_legacy/module/modules/data/tag.lua b/exp_legacy/module/modules/data/tag.lua index 1d251e6a..89329ad0 100644 --- a/exp_legacy/module/modules/data/tag.lua +++ b/exp_legacy/module/modules/data/tag.lua @@ -3,11 +3,8 @@ @data Tag ]] -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands +local Commands = require("modules/exp_commands") local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles -require("modules.exp_legacy.config.expcore.command_general_parse") -require("modules.exp_legacy.config.expcore.command_role_parse") -require("modules.exp_legacy.config.expcore.command_color_parse") --- Stores the tag for a player local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data @@ -47,42 +44,39 @@ PlayerTagColors:on_update(function(player_name, player_tag_color) end) --- Sets your player tag. --- @command tag --- @tparam string tag the tag that will be after the name, there is a max length -Commands.new_command("tag", "Sets your player tag.") - :add_param("tag", false, "string-max-length", 20) - :enable_auto_concat() +Commands.new("tag", "Sets your player tag.") + :argument("tag", "", Commands.types.string_max_length(20)) + :enable_auto_concatenation() :register(function(player, tag) + --- @cast tag string PlayerTags:set(player, tag) end) --- Sets your player tag color. --- @command tag --- @tparam string color name. -Commands.new_command("tag-color", "Sets your player tag color.") - :add_param("color", false, "color") - :enable_auto_concat() +Commands.new("tag-color", "Sets your player tag color.") + :argument("color", "", Commands.types.color) + :enable_auto_concatenation() :register(function(player, color) + --- @cast color Color PlayerTagColors:set(player, color) end) --- Clears your tag. Or another player if you are admin. --- @command tag-clear --- @tparam[opt=self] LuaPlayer player the player to remove the tag from, nil will apply to self -Commands.new_command("tag-clear", "Clears your tag. Or another player if you are admin.") - :add_param("player", true, "player-role") - :set_defaults{ player = function(player) - return player -- default is the user using the command - end } - :register(function(player, action_player) - if action_player.index == player.index then - -- no player given so removes your tag - PlayerTags:remove(action_player) +Commands.new("tag-clear", "Clears your tag. Or another player if you are admin.") + :optional("player", "", Commands.types.lower_role_player) + :defaults{ + player = function(player) return player end + } + :register(function(player, other_player) + --- @cast other_player LuaPlayer + if other_player == player then + -- No player given so removes your tag + PlayerTags:remove(other_player) elseif Roles.player_allowed(player, "command/clear-tag/always") then - -- player given and user is admin so clears that player's tag - PlayerTags:remove(action_player) + -- Player given and user is admin so clears that player's tag + PlayerTags:remove(other_player) else - -- user is not admin and tried to clear another users tag - return Commands.error{ "expcore-commands.unauthorized" } + -- User is not admin and tried to clear another users tag + return Commands.status.unauthorised() end end) diff --git a/exp_legacy/module/modules/factorio-control.lua b/exp_legacy/module/modules/factorio-control.lua index 7bd45a51..7c3bf844 100644 --- a/exp_legacy/module/modules/factorio-control.lua +++ b/exp_legacy/module/modules/factorio-control.lua @@ -42,6 +42,7 @@ end Event.add(defines.events.on_player_created, function(event) local player = game.players[event.player_index] + --- @diagnostic disable-next-line param-type-mismatch util.insert_safe(player, global.created_items) local r = global.chart_distance or 200 @@ -65,6 +66,7 @@ end) Event.add(defines.events.on_player_respawned, function(event) local player = game.players[event.player_index] + --- @diagnostic disable-next-line param-type-mismatch util.insert_safe(player, global.respawn_items) if use_silo_script then silo_script.on_event(event) diff --git a/exp_legacy/module/modules/graftorio/require.lua b/exp_legacy/module/modules/graftorio/require.lua index 0b5c5943..aa584e54 100644 --- a/exp_legacy/module/modules/graftorio/require.lua +++ b/exp_legacy/module/modules/graftorio/require.lua @@ -1,4 +1,4 @@ -local Commands = require("modules.exp_legacy.expcore.commands") +local Commands = require("modules/exp_commands") local config = require("modules.exp_legacy.config.graftorio") local statics = require("modules.exp_legacy.modules.graftorio.statics") local general = require("modules.exp_legacy.modules.graftorio.general") @@ -10,8 +10,8 @@ if config.modules.forcestats then forcestats = require("modules.exp_legacy.modules.graftorio.forcestats") end -Commands.new_command("collectdata", "Collect data for RCON usage") - :add_param("location", true) +Commands.new("collectdata", "Collect data for RCON usage") + :optional("location", "", Commands.types.string) -- Not sure what this is for, i didn't write this :register(function() -- this must be first as it overwrites the stats -- also makes the .other table for all forces @@ -24,6 +24,5 @@ Commands.new_command("collectdata", "Collect data for RCON usage") forcestats.collect_production() forcestats.collect_loginet() end - rcon.print(table_to_json(general.data.output)) - return Commands.success() + return Commands.status.success(table_to_json(general.data.output)) end) diff --git a/exp_legacy/module/modules/gui/debug/main_view.lua b/exp_legacy/module/modules/gui/debug/main_view.lua index 349ec282..393bdade 100644 --- a/exp_legacy/module/modules/gui/debug/main_view.lua +++ b/exp_legacy/module/modules/gui/debug/main_view.lua @@ -17,7 +17,7 @@ local main_frame_name = Gui.uid_name() local close_name = Gui.uid_name() local tab_name = Gui.uid_name() -function Public.open_dubug(player) +function Public.open_debug(player) for i = 1, #pages do local page = pages[i] local callback = page.on_open_debug diff --git a/exp_legacy/module/modules/gui/debug/redmew_global_view.lua b/exp_legacy/module/modules/gui/debug/redmew_global_view.lua index 10349dd8..ae42c326 100644 --- a/exp_legacy/module/modules/gui/debug/redmew_global_view.lua +++ b/exp_legacy/module/modules/gui/debug/redmew_global_view.lua @@ -24,7 +24,8 @@ function Public.show(container) local left_panel_style = left_panel.style left_panel_style.width = 300 - for token_id in pairs(Storage.registered) do + --- @diagnostic disable-next-line invisible + for token_id in pairs(Storage._registered) do local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = token_id } Gui.set_data(header, token_id) end diff --git a/exp_legacy/module/modules/gui/module.lua b/exp_legacy/module/modules/gui/module.lua index 14d450f4..b9f09594 100644 --- a/exp_legacy/module/modules/gui/module.lua +++ b/exp_legacy/module/modules/gui/module.lua @@ -60,9 +60,10 @@ local elem_filter = { } local function clear_module(player, area, machine) - -- Intentionally left as player.surface to allow use in remote view - for _, entity in pairs(player.surface.find_entities_filtered{ area = area, name = machine, force = player.force }) do - for _, r in pairs(player.surface.find_entities_filtered{ position = entity.position, name = "item-request-proxy", force = player.force }) do + local force = player.force + local surface = player.surface -- Allow remote view + for _, entity in pairs(surface.find_entities_filtered{ area = area, name = machine, force = force }) do + for _, r in pairs(surface.find_entities_filtered{ position = entity.position, name = "item-request-proxy", force = force }) do if r then r.destroy{ raise_destroy = true } end @@ -75,7 +76,7 @@ local function clear_module(player, area, machine) if m_current_module_content then for k, m in pairs(m_current_module_content) do - player.surface.spill_item_stack(entity.bounding_box.left_top, { name = k, count = m }, true, player.force, false) + surface.spill_item_stack(entity.bounding_box.left_top, { name = k, count = m }, true, force, false) end end diff --git a/exp_legacy/module/modules/gui/production.lua b/exp_legacy/module/modules/gui/production.lua index a4bc0447..5b3cf828 100644 --- a/exp_legacy/module/modules/gui/production.lua +++ b/exp_legacy/module/modules/gui/production.lua @@ -129,8 +129,7 @@ end) Event.on_nth_tick(60, function() for _, player in pairs(game.connected_players) do local frame = Gui.get_left_element(player, production_container) - -- Intentionally left as player.surface to allow use in remote view - local stat = player.force.get_item_production_statistics(player.surface) + local stat = player.force.get_item_production_statistics(player.surface) -- Allow remote view local precision_value = precision[frame.container["production_st"].disp.table["production_0_e"].selected_index] local table = frame.container["production_st"].disp.table diff --git a/exp_legacy/module/modules/gui/research.lua b/exp_legacy/module/modules/gui/research.lua index 6e54b534..3f141ee2 100644 --- a/exp_legacy/module/modules/gui/research.lua +++ b/exp_legacy/module/modules/gui/research.lua @@ -107,12 +107,12 @@ local function research_notification(event) end else if not (event.by_script) then - game.print{ "expcom-res.inf", research_time_format(game.tick), event.research.name, event.research.level - 1 } + game.print{ "research.inf", research_time_format(game.tick), event.research.name, event.research.level - 1 } end end else if not (event.by_script) then - game.print{ "expcom-res.msg", research_time_format(game.tick), event.research.name } + game.print{ "research.msg", research_time_format(game.tick), event.research.name } end if config.bonus_inventory.enabled then @@ -139,7 +139,7 @@ local function research_gui_update() local res_i = res_n + i - 3 if res["disp"][res_i] then - res_disp[i]["name"] = { "expcom-res.res-name", res["disp"][res_i]["raw_name"], prototypes.technology[res["disp"][res_i]["raw_name"]].localised_name } + res_disp[i]["name"] = { "research.res-name", res["disp"][res_i]["raw_name"], prototypes.technology[res["disp"][res_i]["raw_name"]].localised_name } if research.time[res_i] == 0 then res_disp[i]["target"] = res["disp"][res_i].target_disp @@ -237,10 +237,10 @@ local research_data_set = local res_disp = research_gui_update() research_data_group(disp, 0) - disp["research_0_name"].caption = { "expcom-res.name" } - disp["research_0_target"].caption = { "expcom-res.target" } - disp["research_0_attempt"].caption = { "expcom-res.attempt" } - disp["research_0_difference"].caption = { "expcom-res.difference" } + disp["research_0_name"].caption = { "research.name" } + disp["research_0_target"].caption = { "research.target" } + disp["research_0_attempt"].caption = { "research.attempt" } + disp["research_0_difference"].caption = { "research.difference" } for i = 1, 8, 1 do research_data_group(disp, i) @@ -269,7 +269,7 @@ local research_container = :static_name(Gui.unique_static_name) :add_to_left_flow() -Gui.left_toolbar_button("item/space-science-pack", { "expcom-res.main-tooltip" }, research_container, function(player) +Gui.left_toolbar_button("item/space-science-pack", { "research.main-tooltip" }, research_container, function(player) return Roles.player_allowed(player, "gui/research") end) diff --git a/exp_legacy/module/modules/gui/server-ups.lua b/exp_legacy/module/modules/gui/server-ups.lua index 14e00c3b..8c049d87 100644 --- a/exp_legacy/module/modules/gui/server-ups.lua +++ b/exp_legacy/module/modules/gui/server-ups.lua @@ -6,8 +6,8 @@ local Gui = require("modules.exp_legacy.expcore.gui") --- @dep expcore.gui local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands local External = require("modules.exp_legacy.expcore.external") --- @dep expcore.external +local Commands = require("modules/exp_commands") --- Stores the visible state of server ups local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data @@ -34,19 +34,19 @@ local server_ups = UsesServerUps:on_load(function(player_name, visible) local player = game.players[player_name] local label = player.gui.screen[server_ups.name] + --- @diagnostic disable-next-line undefined-field if not External.valid() or not global.ext.var.server_ups then visible = false end label.visible = visible end) --- Toggles if the server ups is visbile --- @command server-ups -Commands.new_command("server-ups", "Toggle the server UPS display") - :add_alias("sups", "ups") +Commands.new("server-ups", { "server-ups.description" }) + :add_aliases{ "sups", "ups" } :register(function(player) local label = player.gui.screen[server_ups.name] if not External.valid() then label.visible = false - return Commands.error{ "expcom-server-ups.no-ext" } + return Commands.status.error{ "server-ups.no-ext" } end label.visible = not label.visible UsesServerUps:set(player, label.visible) diff --git a/exp_scenario/index.ts b/exp_scenario/index.ts index ca4edef1..d6e85fcc 100644 --- a/exp_scenario/index.ts +++ b/exp_scenario/index.ts @@ -25,9 +25,6 @@ export const plugin: lib.PluginDeclaration = { instanceEntrypoint: "./dist/node/instance", messages: [ - Messages.PluginExampleEvent, - Messages.PluginExampleRequest, - Messages.ExampleSubscribableUpdate, ], webEntrypoint: "./web", diff --git a/exp_scenario/module/commands/authorities.lua b/exp_scenario/module/commands/_authorities.lua similarity index 69% rename from exp_scenario/module/commands/authorities.lua rename to exp_scenario/module/commands/_authorities.lua index 6843d6fe..8c0dfa47 100644 --- a/exp_scenario/module/commands/authorities.lua +++ b/exp_scenario/module/commands/_authorities.lua @@ -1,15 +1,19 @@ +--[[-- Command Authorities - Roles +Adds a permission authority for exp roles +]] local Commands = require("modules/exp_commands") local add, allow, deny = Commands.add_permission_authority, Commands.status.success, Commands.status.unauthorised local Roles = require("modules/exp_legacy/expcore/roles") +local player_allowed = Roles.player_allowed local authorities = {} --- If a command has the flag "character_only" then the command can only be used outside of remote view authorities.exp_permission = add(function(player, command) - if not Roles.player_allowed(player, command.flags.exp_permission or ("command/" .. command)) then + if not player_allowed(player, command.flags.exp_permission or ("command/" .. command)) then return deny{ "exp-commands-authorities_role.deny" } else return allow() diff --git a/exp_scenario/module/commands/_rcon.lua b/exp_scenario/module/commands/_rcon.lua new file mode 100644 index 00000000..e29ecb11 --- /dev/null +++ b/exp_scenario/module/commands/_rcon.lua @@ -0,0 +1,12 @@ +--[[-- Command Rcon - ExpCore +Adds rcon interfaces for the legacy exp core +]] + +local Commands = require("modules/exp_commands") +local add_static, add_dynamic = Commands.add_rcon_static, Commands.add_rcon_dynamic + +add_static("Group", require("modules.exp_legacy.expcore.permission_groups")) +add_static("Roles", require("modules.exp_legacy.expcore.roles")) +add_static("Gui", require("modules.exp_legacy.expcore.gui")) +add_static("Datastore", require("modules.exp_legacy.expcore.datastore")) +add_static("External", require("modules.exp_legacy.expcore.external")) diff --git a/exp_scenario/module/commands/types.lua b/exp_scenario/module/commands/_types.lua similarity index 83% rename from exp_scenario/module/commands/types.lua rename to exp_scenario/module/commands/_types.lua index ae035b32..58e1d549 100644 --- a/exp_scenario/module/commands/types.lua +++ b/exp_scenario/module/commands/_types.lua @@ -16,20 +16,13 @@ local valid, invalid = Commands.status.success, Commands.status.invalid_input local Roles = require("modules.exp_legacy.expcore.roles") local highest_role = Roles.get_player_highest_role -local key_of_roles = Commands.types.key_of(Roles.config.roles) -local types = {} +local types = {} --- @class Commands._types --- A role defined by exp roles ---- @type Commands.InputParser -types.role = - add("role", function(input, player) - local _, status, rtn = parse(input, player, key_of_roles) - return status, rtn - end) +types.role = add("role", Commands.types.key_of(Roles.config.roles)) --- A role which is lower than the players highest role ---- @type Commands.InputParser types.lower_role = add("lower_role", function(input, player) local success, status, result = parse(input, player, types.role) @@ -45,7 +38,6 @@ types.lower_role = end) --- A player who is of a lower role than the executing player ---- @type Commands.InputParser types.lower_role_player = add("lower_role_player", function(input, player) local success, status, result = parse(input, player, Commands.types.player) @@ -62,9 +54,8 @@ types.lower_role_player = end) --- A player who is of a lower role than the executing player ---- @type Commands.InputParser types.lower_role_player_online = - add("lower_role_player", function(input, player) + add("lower_role_player_online", function(input, player) local success, status, result = parse(input, player, Commands.types.player_online) if not success then return status, result end --- @cast result LuaPlayer @@ -80,7 +71,7 @@ types.lower_role_player_online = --- A player who is of a lower role than the executing player types.lower_role_player_alive = - add("lower_role_player", function(input, player) + add("lower_role_player_alive", function(input, player) local success, status, result = parse(input, player, Commands.types.player_alive) if not success then return status, result end --- @cast result LuaPlayer diff --git a/exp_scenario/module/commands/admin_chat.lua b/exp_scenario/module/commands/admin_chat.lua new file mode 100644 index 00000000..56dc263a --- /dev/null +++ b/exp_scenario/module/commands/admin_chat.lua @@ -0,0 +1,22 @@ +--[[-- Commands - Admin Chat +Adds a command that allows admins to talk in a private chat +]] + +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale + +--- Sends a message in chat that only admins can see +Commands.new("admin-chat", { "exp-commands_admin-chat.description" }) + :argument("message", { "exp-commands_admin-chat.arg-message" }, Commands.types.string) + :enable_auto_concatenation() + :add_aliases{ "ac" } + :add_flags{ "admin_only" } + :register(function(player, message) + --- @cast message string + local player_name = format_player_name(player) + for _, next_player in ipairs(game.connected_players) do + if next_player.admin then + next_player.print{ "exp-commands_admin-chat.format", player_name, message } + end + end + end) diff --git a/exp_scenario/module/commands/artillery.lua b/exp_scenario/module/commands/artillery.lua new file mode 100644 index 00000000..72f3f19a --- /dev/null +++ b/exp_scenario/module/commands/artillery.lua @@ -0,0 +1,96 @@ +--[[-- Commands - Artillery +Adds a command that helps shoot artillery +]] + +local AABB = require("modules/exp_util/aabb") +local Commands = require("modules/exp_commands") +local Selection = require("modules.exp_legacy.modules.control.selection") --- @dep modules.control.selection +local SelectionName = "ExpCommand_Artillery" + +local floor = math.floor +local abs = math.abs + +--- @param player LuaPlayer +--- @param area BoundingBox +--- @return boolean +local function location_break(player, area) + local surface = player.surface -- Allow remote view + local is_charted = player.force.is_chunk_charted + if is_charted(surface, { x = floor(area.left_top.x / 32), y = floor(area.left_top.y / 32) }) then + return true + elseif is_charted(surface, { x = floor(area.left_top.x / 32), y = floor(area.right_bottom.y / 32) }) then + return true + elseif is_charted(surface, { x = floor(area.right_bottom.x / 32), y = floor(area.left_top.y / 32) }) then + return true + elseif is_charted(surface, { x = floor(area.right_bottom.x / 32), y = floor(area.right_bottom.y / 32) }) then + return true + else + return false + end +end + +--- Toggle player selection mode for artillery +Commands.new("artillery", { "exp-commands_artillery.description" }) + :register(function(player) + if Selection.is_selecting(player, SelectionName) then + Selection.stop(player) + return Commands.status.success{ "exp-commands_artillery.exit" } + else + Selection.start(player, SelectionName) + return Commands.status.success{ "exp-commands_artillery.enter" } + end + end) + +--- when an area is selected to add protection to the area +Selection.on_selection(SelectionName, function(event) + --- @cast event EventData.on_player_selected_area + local area = AABB.expand(event.area) + local player = game.players[event.player_index] + local surface = event.surface + + if not (player.cheat_mode or location_break(player, event.area)) then + player.print{ "exp-commands_artillery.invalid_area" } + return + end + + local entities = surface.find_entities_filtered{ + area = area, + type = { "unit-spawner", "turret" }, + force = "enemy" + } + + local count = 0 + local hits = {} --- @type MapPosition[] + for _, entity in ipairs(entities) do + local skip = false + + for _, pos in ipairs(hits) do + local x = abs(entity.position.x - pos.x) + local y = abs(entity.position.y - pos.y) + if x * x + y * y < 36 then + skip = true + break + end + end + + if not skip then + surface.create_entity{ + name = "artillery-flare", + position = entity.position, + force = player.force, + life_time = 240, + movement = { 0, 0 }, + height = 0, + vertical_speed = 0, + frame_speed = 0 + } + + count = count + 1 + hits[count] = entity.position + + if count > 400 then + break + end + end + end +end) diff --git a/exp_scenario/module/commands/bot_queue.lua b/exp_scenario/module/commands/bot_queue.lua new file mode 100644 index 00000000..44977d96 --- /dev/null +++ b/exp_scenario/module/commands/bot_queue.lua @@ -0,0 +1,28 @@ +--[[-- Commands - Bot queue +Adds a command that allows viewing and changing the construction queue limits +]] + +local Commands = require("modules/exp_commands") + +--- Get / Set the current values for the bot queue +Commands.new("bot-queue", { "exp-commands_bot-queue.description" }) + :optional("amount", { "exp-commands_bot-queue.arg-amount" }, Commands.types.integer_range(1, 20)) + :add_flags{ "admin_only" } + :register(function(player, amount) + if amount then + player.force.max_successful_attempts_per_tick_per_construction_queue = 3 * amount + player.force.max_failed_attempts_per_tick_per_construction_queue = 5 * amount + game.print{ + "exp-commands_bot-queue.set", + player.force.max_successful_attempts_per_tick_per_construction_queue, + player.force.max_failed_attempts_per_tick_per_construction_queue, + } + return Commands.status.success() + end + + return Commands.status.success{ + "exp-commands_bot-queue.get", + player.force.max_successful_attempts_per_tick_per_construction_queue, + player.force.max_failed_attempts_per_tick_per_construction_queue, + } + end) diff --git a/exp_scenario/module/commands/cheat.lua b/exp_scenario/module/commands/cheat.lua new file mode 100644 index 00000000..ab0e4183 --- /dev/null +++ b/exp_scenario/module/commands/cheat.lua @@ -0,0 +1,132 @@ +--[[-- Commands - Cheats +Adds commands for cheating such as unlocking all technology or settings always day +]] + +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale + +--- Toggles cheat mode for your player, or another player. +Commands.new("set-cheat-mode", { "exp-commands_cheat.description-cheat-mode" }) + :optional("state", { "exp-commands_cheat.arg-state" }, Commands.types.boolean) + :optional("player", { "exp-commands_cheat.arg-player" }, Commands.types.player) + :add_aliases{ "cheat-mode", "toggle-cheat-mode" } + :add_flags{ "admin_only" } + :defaults{ + player = function(player) return player end, + } + :register(function(player, state, other_player) + --- @cast state boolean? + --- @cast player LuaPlayer + if state == nil then + other_player.cheat_mode = not other_player.cheat_mode + else + other_player.cheat_mode = state + end + return Commands.status.success{ "exp-commands_cheat.cheat-mode", other_player.cheat_mode } + end) + +--- Toggle always day for your surface, or another +Commands.new("set-always-day", { "exp-commands_cheat.description-always-day" }) + :optional("state", { "exp-commands_cheat.arg-state" }, Commands.types.boolean) + :optional("surface", { "exp-commands_cheat.arg-surface" }, Commands.types.surface) + :add_aliases{ "always-day", "toggle-always-day" } + :add_flags{ "admin_only" } + :defaults{ + surface = function(player) return player.surface end + } + :register(function(player, state, surface) + --- @cast state boolean? + --- @cast surface LuaSurface + if state == nil then + surface.always_day = not surface.always_day + else + surface.always_day = state + end + game.print{ "exp-commands_cheat.always-day", format_player_name(player), surface.localised_name, surface.always_day } + end) + +--- Toggles friendly fire for your force or another +Commands.new("set-friendly-fire", { "exp-commands_cheat.description-friendly-fire" }) + :optional("state", { "exp-commands_cheat.arg-state" }, Commands.types.boolean) + :optional("force", { "exp-commands_cheat.arg-force-friendly-fire" }, Commands.types.force) + :add_aliases{ "friendly-fire", "toggle-friendly-fire" } + :add_flags{ "admin_only" } + :defaults{ + force = function(player) return player.force end + } + :register(function(player, state, force) + --- @cast state boolean? + --- @cast force LuaForce + if state == nil then + force.friendly_fire = not force.friendly_fire + else + force.friendly_fire = state + end + game.print{ "exp-commands_cheat.friendly-fire", format_player_name(player), force.name, force.friendly_fire } + end) + +--- Research all technology on your force, or another force. +Commands.new("research-all", { "exp-commands_cheat.description-research-all" }) + :optional("force", { "exp-commands_cheat.arg-force-research" }, Commands.types.force) + :add_flags{ "admin_only" } + :defaults{ + force = function(player) return player.force end + } + :register(function(player, force) + --- @cast force LuaForce + force.research_all_technologies() + game.print{ "exp-commands_cheat.research-all", format_player_name(player), force.name } + return Commands.status.success() + end) + +--- Clear all pollution from your surface or another +Commands.new("clear-pollution", { "exp-commands_cheat.description-clear-pollution" }) + :optional("surface", { "exp-commands_cheat.arg-surface" }, Commands.types.surface) + :add_flags{ "admin_only" } + :defaults{ + surface = function(player) return player.surface end -- Allow remote view + } + :register(function(player, surface) + --- @cast surface LuaSurface + surface.clear_pollution() + game.print{ "exp-commands_cheat.clear-pollution", format_player_name(player), surface.localised_name } + end) + +--- Toggles pollution being enabled in the game +Commands.new("set-pollution-enabled", { "exp-commands_cheat.description-pollution-enabled" }) + :optional("state", { "exp-commands_cheat.arg-state" }, Commands.types.boolean) + :add_aliases{ "disable-pollution", "toggle-pollution-enabled" } + :add_flags{ "admin_only" } + :register(function(player, state) + --- @cast state boolean? + if state == nil then + game.map_settings.pollution.enabled = not game.map_settings.pollution.enabled + else + game.map_settings.pollution.enabled = state + end + + if game.map_settings.pollution.enabled == false then + for _, surface in pairs(game.surfaces) do + surface.clear_pollution() + end + end + + game.print{ "exp-commands_cheat.pollution-enabled", format_player_name(player), game.map_settings.pollution.enabled } + end) + +--- Set or get the game speed +Commands.new("set-game-speed", { "exp-commands_cheat.description-game-speed" }) + :optional("amount", { "exp-commands_cheat.arg-amount" }, Commands.types.number_range(0.2, 10)) + :add_aliases{ "game-speed" } + :add_flags{ "admin_only" } + :register(function(player, amount) + --- @cast amount number? + if amount then + game.speed = math.round(amount, 3) + local player_name = format_player_name(player) + game.print{ "exp-commands_cheat.game-speed-set", player_name, game.speed } + return Commands.status.success() + else + return Commands.status.success{ "exp-commands_cheat.game-speed-get", game.speed } + end + end) diff --git a/exp_scenario/module/commands/clear_inventory.lua b/exp_scenario/module/commands/clear_inventory.lua new file mode 100644 index 00000000..9a37fc84 --- /dev/null +++ b/exp_scenario/module/commands/clear_inventory.lua @@ -0,0 +1,26 @@ +--[[-- Commands - Clear Inventory +Adds a command that allows admins to clear people's inventory +]] + +local ExpUtil = require("modules/exp_util") +local transfer_inventory = ExpUtil.transfer_inventory_to_surface + +local Commands = require("modules/exp_commands") + +--- Clears a players inventory +Commands.new("clear-inventory", { "exp-commands_clear-inventory.description" }) + :argument("player", { "exp-commands_clear-inventory.arg-player" }, Commands.types.lower_role_player) + :add_flags{ "admin_only" } + :register(function(player, other_player) + local inventory = other_player.get_main_inventory() + if not inventory then + return Commands.status.error{ "expcore-commands.reject-player-alive" } + end + + transfer_inventory{ + inventory = inventory, + surface = game.planets.nauvis.surface, + name = "iron-chest", + allow_creation = true, + } + end) diff --git a/exp_scenario/module/commands/connect.lua b/exp_scenario/module/commands/connect.lua new file mode 100644 index 00000000..fc97ac8c --- /dev/null +++ b/exp_scenario/module/commands/connect.lua @@ -0,0 +1,111 @@ +--[[-- Commands - Connect +Adds a commands that allows you to request a player move to another server +]] + +local Async = require("modules/exp_util/async") +local Commands = require("modules/exp_commands") + +local External = require("modules.exp_legacy.expcore.external") --- @dep expcore.external +local request_connection_async = Async.register(External.request_connection) + +local concat = table.concat + +--- Convert a server name into a server id, is not an Commands.InputParser because it does not accept addresses +--- @param server string +--- @return boolean, LocalisedString # True for success +local function get_server_id(server) + local servers = External.get_servers_filtered(server) + local current_server = External.get_current_server() + local current_version = current_server.version + + local server_names_before, server_names = {}, {} + local server_count_before, server_count = 0, 0 + for next_server_id, server_details in pairs(servers) do + server_count_before = server_count_before + 1 + server_names_before[server_count_before] = server_details.name + if server_details.version == current_version then + server_count = server_count + 1 + server_names[server_count] = server_details.name + else + servers[next_server_id] = nil + end + end + + if server_count > 1 then + return false, { "exp-commands_connect.too-many-matching", concat(server_names, ", ") } + elseif server_count == 1 then + local server_id, server_details = next(servers) + local status = External.get_server_status(server_id) + if server_id == current_server.id then + return false, { "exp-commands_connect.same-server", server_details.name } + elseif status == "Offline" then + return false, { "exp-commands_connect.offline", server_details.name } + end + return true, server_id + elseif server_count_before > 0 then + return false, { "exp-commands_connect.wrong-version", concat(server_names_before, ", ") } + else + return false, { "exp-commands_connect.none-matching" } + end +end + +--- Connect to a different server +Commands.new("connect", { "exp-commands_connect.description" }) + :argument("server", { "exp-commands_connect.arg-server" }, Commands.types.string) + :optional("is-address", { "exp-commands_connect.is-address" }, Commands.types.boolean) + :add_aliases{ "join" } + :register(function(player, server, is_address) + --- @cast server string + --- @cast is_address boolean? + if not is_address and External.valid() then + local success, result = get_server_id(server) + if not success then + return Commands.status.invalid_input(result) + end + server = result + end + + request_connection_async(player, server, true) + end) + +--- Connect another player to a different server +Commands.new("connect-player", { "exp-commands_connect.description-player" }) + :argument("player", { "exp-commands_connect.arg-player" }, Commands.types.player_online) + :argument("server", { "exp-commands_connect.arg-server" }, Commands.types.string) + :optional("is-address", { "exp-commands_connect.is-address" }, Commands.types.boolean) + :add_flags{ "admin_only" } + :register(function(player, other_player, server, is_address) + --- @cast other_player LuaPlayer + --- @cast server string + --- @cast is_address boolean? + if not is_address and External.valid() then + local success, result = get_server_id(server) + if not success then + return Commands.status.invalid_input(result) + end + server = result + end + + request_connection_async(other_player, server) + end) + +--- Connect all players to a different server +Commands.new("connect-all", { "exp-commands_connect.description-all" }) + :argument("server", { "exp-commands_connect.arg-server" }, Commands.types.string) + :optional("is-address", { "exp-commands_connect.is-address" }, Commands.types.boolean) + :add_flags{ "admin_only" } + :register(function(player, server, is_address) + --- @cast server string + --- @cast is_address boolean? + if not is_address and External.valid() then + local success, result = get_server_id(server) + if not success then + return Commands.status.invalid_input(result) + end + server = result + end + + for _, next_player in pairs(game.connected_players) do + request_connection_async(next_player, server) + end + end) diff --git a/exp_scenario/module/commands/debug.lua b/exp_scenario/module/commands/debug.lua new file mode 100644 index 00000000..a30d202e --- /dev/null +++ b/exp_scenario/module/commands/debug.lua @@ -0,0 +1,10 @@ +--[[-- Commands - Debug +Adds a command that opens the debug frame +]] + +local DebugView = require("modules.exp_legacy.modules.gui.debug.main_view") --- @dep modules.gui.debug.main_view +local Commands = require("modules/exp_commands") + +--- Opens the debug gui. +Commands.new("debug", { "exp-commands_debug.description" }) + :register(DebugView.open_debug) diff --git a/exp_scenario/module/commands/enemy.lua b/exp_scenario/module/commands/enemy.lua new file mode 100644 index 00000000..adf0377d --- /dev/null +++ b/exp_scenario/module/commands/enemy.lua @@ -0,0 +1,30 @@ +--[[-- Commands - Enemy +Adds a commands of handling the enemy force, such as killing all or disabling them +]] + +local Commands = require("modules/exp_commands") + +--- Kill all enemies +Commands.new("kill-enemies", { "exp-commands_enemy.description-kill" }) + :add_aliases{ "kill-biters" } + :add_flags{ "admin_only" } + :register(function(player) + game.forces["enemy"].kill_all_units() + game.print{ "exp-commands_enemy.kill", player.name } + end) + +--- Remove all enemies on a surface +Commands.new("remove-enemies", { "exp-commands_enemy.description-remove" }) + :optional("surface", { "exp-commands_enemy.arg-surface" }, Commands.types.surface) + :add_aliases{ "remove-biters" } + :add_flags{ "admin_only" } + :defaults{ + surface = function(player) return player.surface end + } + :register(function(player, surface) + for _, entity in pairs(surface.find_entities_filtered{ force = "enemy" }) do + entity.destroy() + end + -- surface.map_gen_settings.autoplace_controls["enemy-base"].size = "none" -- TODO make this work for SA + game.print{ "exp-commands_enemy.remove", player.name } + end) diff --git a/exp_scenario/module/commands/home.lua b/exp_scenario/module/commands/home.lua new file mode 100644 index 00000000..ebf9e0d8 --- /dev/null +++ b/exp_scenario/module/commands/home.lua @@ -0,0 +1,116 @@ +--[[-- Commands - Home +Adds a command that allows setting and teleporting to your home position +]] + +local ExpUtil = require("modules/exp_util") +local teleport = ExpUtil.teleport_player + +local Commands = require("modules/exp_commands") +local Storage = require("modules/exp_util/storage") + +--- @type table> +local homes = {} -- homes[player_index][surface_index] = { home_pos, return_pos } +Storage.register(homes, function(tbl) + homes = tbl +end) + +--- Align a position to the grid +--- @param position MapPosition The position to align +--- @return MapPosition, MapPosition +local function align_to_grid(position) + return { + x = math.floor(position.x) + math.sign(position.x) * 0.5, + y = math.floor(position.y) + math.sign(position.x) * 0.5, + }, { + x = math.floor(position.x), + y = math.floor(position.y), + } +end + +--- Teleports you to your home location on the current surface +Commands.new("home", { "exp-commands_home.description-home" }) + :add_flags{ "character_only" } + :register(function(player) + local surface = player.surface + + local player_homes = homes[player.index] + if not player_homes then + return Commands.status.error{ "exp-commands_home.no-home", surface.localised_name } + end + + local player_home = player_homes[surface.index] + if not player_home or not player_home[1] then + return Commands.status.error{ "exp-commands_home.no-home", surface.localised_name } + end + + local return_position, floor_position = align_to_grid(player.position) + teleport(player, surface, player_home[1]) + player_home[2] = return_position + return Commands.status.success{ "exp-commands_home.return-set", surface.localised_name, floor_position.x, floor_position.y } + end) + +--- Teleports you to your previous location on the current surface +Commands.new("return", { "exp-commands_home.description-return" }) + :add_flags{ "character_only" } + :register(function(player) + local surface = player.surface + + local player_homes = homes[player.index] + if not player_homes then + return Commands.status.error{ "exp-commands_home.no-return", surface.localised_name } + end + + local player_home = player_homes[surface.index] + if not player_home or not player_home[2] then + return Commands.status.error{ "exp-commands_home.no-return", surface.localised_name } + end + + local return_position, floor_position = align_to_grid(player.position) + teleport(player, surface, player_home[2]) + player_home[2] = return_position + return Commands.status.success{ "exp-commands_home.return-set", surface.localised_name, floor_position.x, floor_position.y } + end) + +--- Sets your home location on your current surface to your current position +Commands.new("set-home", { "exp-commands_home.description-set" }) + :add_flags{ "character_only" } + :register(function(player) + local home_position, floor_position = align_to_grid(player.position) + local surface = player.surface + + local player_homes = homes[player.index] + if not player_homes then + homes[player.index] = { + [surface.index] = { home_position, nil } + } + return Commands.status.success{ "exp-commands_home.home-set", surface.localised_name, floor_position.x, floor_position.y } + end + + local player_home = player_homes[surface.index] + if not player_home then + player_homes[surface.index] = { home_position, nil } + return Commands.status.success{ "exp-commands_home.home-set", surface.localised_name, floor_position.x, floor_position.y } + end + + player_home[1] = home_position + return Commands.status.success{ "exp-commands_home.home-set", surface.localised_name, floor_position.x, floor_position.y } + end) + +--- Gets your home location on your current surface, is allowed in remote view +Commands.new("get-home", { "exp-commands_home.description-get" }) + :register(function(player) + local surface = player.surface + + local player_homes = homes[player.index] + if not player_homes then + return Commands.status.error{ "exp-commands_home.no-home", surface.localised_name } + end + + local player_home = player_homes[surface.index] + if not player_home or not player_home[1] then + return Commands.status.error{ "exp-commands_home.no-home", surface.localised_name } + end + + local _, floor_position = align_to_grid(player_home[1]) + return Commands.status.success{ "exp-commands_home.home-get", surface.localised_name, floor_position.x, floor_position.y } + end) diff --git a/exp_scenario/module/commands/jail.lua b/exp_scenario/module/commands/jail.lua new file mode 100644 index 00000000..95c78aee --- /dev/null +++ b/exp_scenario/module/commands/jail.lua @@ -0,0 +1,43 @@ +--[[-- Commands - Jail +Adds a commands that allow admins to jail and unjail +]] + +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale + +local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail + +--- Puts a player into jail and removes all other roles. +Commands.new("jail", { "exp-commands_jail.description" }) + :argument("player", { "exp-commands_jail.arg-player" }, Commands.types.lower_role_player) + :optional("reason", { "exp-commands_jail.arg-reason" }, Commands.types.string) + :enable_auto_concatenation() + :register(function(player, other_player, reason) + --- @cast other_player LuaPlayer + --- @cast reason string? + if not reason then + reason = "None Given." + end + + local player_name = format_player_name(player) + local other_player_name = format_player_name(other_player) + if Jail.jail_player(other_player, player.name, reason) then + game.print{ "exp-commands_jail.jailed", other_player_name, player_name, reason } + else + return Commands.status.error{ "exp-commands_jail.already-jailed", other_player_name } + end + end) + +--- Removes a player from jail and restores their old roles. +Commands.new("unjail", { "exp-commands_unjail.description" }) + :argument("player", { "exp-commands_unjail.arg-player" }, Commands.types.lower_role_player) + :register(function(player, other_player) + --- @cast other_player LuaPlayer + local player_name = format_player_name(player) + local other_player_name = format_player_name(other_player) + if Jail.unjail_player(other_player, player.name) then + game.print{ "exp-commands_unjail.unjailed", other_player_name, player_name } + else + return Commands.status.error{ "exp-commands_unjail.not-jailed", other_player_name } + end + end) diff --git a/exp_scenario/module/commands/kill.lua b/exp_scenario/module/commands/kill.lua new file mode 100644 index 00000000..2ab239bd --- /dev/null +++ b/exp_scenario/module/commands/kill.lua @@ -0,0 +1,32 @@ +--[[-- Commands - Kill +Adds a command that allows players to kill themselves and others +]] + +local Commands = require("modules/exp_commands") + +local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles +local highest_role = Roles.get_player_highest_role + +--- Kills yourself or another player. +Commands.new("kill", { "exp-commands_kill.description" }) + :optional("player", { "exp-commands_kill.arg-player" }, Commands.types.lower_role_player_alive) + :defaults{ + player = function(player) + return player.character and player.character.health > 0 and player or nil + end + } + :register(function(player, other_player) + --- @cast other_player LuaPlayer? + if other_player == nil then + -- Can only be nil if the target is the player and they are already dead + return Commands.status.error{ "exp-commands_kill.already-dead" } + elseif other_player == player then + -- You can always kill yourself + other_player.character.die() + elseif highest_role(other_player).index < highest_role(player).index then + -- Can kill lower role players + other_player.character.die() + else + return Commands.status.unauthorised{ "exp-commands_kill.lower-role" } + end + end) diff --git a/exp_scenario/module/commands/lawnmower.lua b/exp_scenario/module/commands/lawnmower.lua new file mode 100644 index 00000000..e002f21b --- /dev/null +++ b/exp_scenario/module/commands/lawnmower.lua @@ -0,0 +1,52 @@ +--[[-- Commands - Lawnmower +Adds a command that clean up biter corpse and nuclear hole +]] + +local Commands = require("modules/exp_commands") +local config = require("modules.exp_legacy.config.lawnmower") --- @dep config.lawnmower + +Commands.new("lawnmower", { "exp-commands_lawnmower.description" }) + :argument("range", { "exp-commands_lawnmower.arg-range" }, Commands.types.integer_range(1, 200)) + :register(function(player, range) + --- @cast range number + local surface = player.surface + + -- Intentionally left as player.position to allow use in remote view + local entities = surface.find_entities_filtered{ position = player.position, radius = range, type = "corpse" } + for _, entity in pairs(entities) do + if (entity.name ~= "transport-caution-corpse" and entity.name ~= "invisible-transport-caution-corpse") then + entity.destroy() + end + end + + local replace_tiles = {} + local tiles = surface.find_tiles_filtered{ position = player.position, radius = range, name = { "nuclear-ground" } } + for i, tile in pairs(tiles) do + replace_tiles[i] = { name = "grass-1", position = tile.position } + end + + surface.set_tiles(replace_tiles) + surface.destroy_decoratives{ position = player.position, radius = range } + end) + +--- @param event EventData.on_built_entity | EventData.on_robot_built_entity | EventData.script_raised_built | EventData.script_raised_revive +local function destroy_decoratives(event) + local entity = event.entity + if entity.type ~= "entity-ghost" and entity.type ~= "tile-ghost" and entity.prototype.selectable_in_game then + entity.surface.destroy_decoratives{ area = entity.selection_box } + end +end + +local e = defines.events +local events = {} + +if config.destroy_decoratives then + events[e.on_built_entity] = destroy_decoratives + events[e.on_robot_built_entity] = destroy_decoratives + events[e.script_raised_built] = destroy_decoratives + events[e.script_raised_revive] = destroy_decoratives +end + +return { + events = events +} diff --git a/exp_scenario/module/commands/locate.lua b/exp_scenario/module/commands/locate.lua new file mode 100644 index 00000000..e5f55167 --- /dev/null +++ b/exp_scenario/module/commands/locate.lua @@ -0,0 +1,40 @@ +--[[-- Commands - Locate +Adds a command that will return the last location of a player +]] + +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale + +local format = string.format + +--- Open remote view at a players last location +Commands.new("locate", { "exp-commands_locate.description" }) + :add_aliases{ "last-location", "find" } + :argument("player", { "exp-commands_locate.arg-player" }, Commands.types.player) + :optional("remote", { "exp-commands_locate.arg-remote" }, Commands.types.boolean) + :register(function(player, other_player, remote) + --- @cast other_player LuaPlayer + --- @cast remote boolean? + local surface = other_player.physical_surface + local position = other_player.physical_position + if remote and other_player.controller_type == defines.controllers.remote then + surface = other_player.surface + position = other_player.position + end + + if player.index > 0 then + -- This check allows rcon to use the command + player.set_controller{ + type = defines.controllers.remote, + surface = surface, + position = position, + } + end + + return Commands.status.success{ + "exp-commands_locate.response", + format_player_name(other_player), + format("%.1f", position.x), + format("%.1f", position.y), + } + end) diff --git a/exp_scenario/module/commands/me.lua b/exp_scenario/module/commands/me.lua new file mode 100644 index 00000000..6dee97dd --- /dev/null +++ b/exp_scenario/module/commands/me.lua @@ -0,0 +1,14 @@ +--[[-- Commands - Me +Adds a command that adds * around your message in the chat +]] + +local Commands = require("modules/exp_commands") +local format_text = Commands.format_rich_text_color_locale + +--- Sends an action message in the chat +Commands.new("me", { "exp-commands_me.description" }) + :argument("action", { "exp-commands_me.arg-action" }, Commands.types.string) + :enable_auto_concatenation() + :register(function(player, action) + game.print(format_text({ "exp-commands_me.response", player.name, action, }, player.chat_color)) + end) diff --git a/exp_legacy/module/modules/commands/protection.lua b/exp_scenario/module/commands/protected_entities.lua similarity index 50% rename from exp_legacy/module/modules/commands/protection.lua rename to exp_scenario/module/commands/protected_entities.lua index b8311da1..97a9f0ee 100644 --- a/exp_legacy/module/modules/commands/protection.lua +++ b/exp_scenario/module/commands/protected_entities.lua @@ -1,63 +1,56 @@ ---[[-- Commands Module - Protection - - Adds commands that can add and remove protection - @commands Protection +--[[-- Commands - Protection +Adds commands that can add and remove protection ]] -local ExpUtil = require("modules/exp_util") -local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event local Storage = require("modules/exp_util/storage") + +local AABB = require("modules/exp_util/aabb") +local contains_area = AABB.contains_area +local expand_area = AABB.expand + +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale + local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local format_player_name = ExpUtil.format_player_name_locale --- @dep expcore.common -local EntityProtection = require("modules.exp_legacy.modules.control.protection") --- @dep modules.control.protection local Selection = require("modules.exp_legacy.modules.control.selection") --- @dep modules.control.selection +local EntityProtection = require("modules.exp_legacy.modules.control.protection") --- @dep modules.control.protection -local SelectionProtectEntity = "ProtectEntity" -local SelectionProtectArea = "ProtectArea" +local format_string = string.format +local floor = math.floor -local renders = {} -- Stores all renders for a player +local SelectionName_Entity = "ExpCommand_ProtectEntity" +local SelectionName_Area = "ExpCommand_ProtectArea" + +local renders = {} --- @type table> Stores all renders for a player Storage.register({ renders = renders, }, function(tbl) renders = tbl.renders end) ---- Test if a point is inside an aabb -local function aabb_point_enclosed(point, aabb) - return point.x >= aabb.left_top.x and point.y >= aabb.left_top.y - and point.x <= aabb.right_bottom.x and point.y <= aabb.right_bottom.y -end - ---- Test if an aabb is inside another aabb -local function aabb_area_enclosed(aabb_one, aabb_two) - return aabb_point_enclosed(aabb_one.left_top, aabb_two) - and aabb_point_enclosed(aabb_one.right_bottom, aabb_two) -end - ---- Align an aabb to the grid by expanding it -local function aabb_align_expand(aabb) - return { - left_top = { x = math.floor(aabb.left_top.x), y = math.floor(aabb.left_top.y) }, - right_bottom = { x = math.ceil(aabb.right_bottom.x), y = math.ceil(aabb.right_bottom.y) }, - } -end - --- Get the key used in protected_entities +--- @param entity LuaEntity +--- @return string local function get_entity_key(entity) - return string.format("%i,%i", math.floor(entity.position.x), math.floor(entity.position.y)) + return format_string("%i,%i", floor(entity.position.x), floor(entity.position.y)) end --- Get the key used in protected_areas +--- TODO expose this from EntityProtection +--- @param area BoundingBox +--- @return string local function get_area_key(area) - return string.format("%i,%i", math.floor(area.left_top.x), math.floor(area.left_top.y)) + return format_string("%i,%i", floor(area.left_top.x), floor(area.left_top.y)) end --- Show a protected entity to a player +--- @param player LuaPlayer +--- @param entity LuaEntity local function show_protected_entity(player, entity) local key = get_entity_key(entity) if renders[player.index][key] then return end local rb = entity.selection_box.right_bottom - local render_id = rendering.draw_sprite{ + renders[player.index][key] = rendering.draw_sprite{ sprite = "utility/notification", target = entity, target_offset = { @@ -69,14 +62,16 @@ local function show_protected_entity(player, entity) surface = entity.surface, players = { player }, } - renders[player.index][key] = render_id end --- Show a protected area to a player +--- @param player LuaPlayer +--- @param surface LuaSurface +--- @param area BoundingBox local function show_protected_area(player, surface, area) local key = get_area_key(area) if renders[player.index][key] then return end - local render_id = rendering.draw_rectangle{ + renders[player.index][key] = rendering.draw_rectangle{ color = { 1, 1, 0, 0.5 }, filled = false, width = 3, @@ -85,101 +80,108 @@ local function show_protected_area(player, surface, area) surface = surface, players = { player }, } - renders[player.index][key] = render_id end --- Remove a render object for a player +--- @param player LuaPlayer +--- @param key string local function remove_render(player, key) - local render = renders[player.index][key] --[[@as LuaRenderObject]] + local render = renders[player.index][key] if render and render.valid then render.destroy() end renders[player.index][key] = nil end --- Toggles entity protection selection --- @command protect-entity -Commands.new_command("protect-entity", { "expcom-protection.description-pe" }, "Toggles entity protection selection, hold shift to remove protection") - :add_alias("pe") +Commands.new("protect-entity", { "exp-commands_protection.description-entity" }) + :add_aliases{ "pe" } :register(function(player) - if Selection.is_selecting(player, SelectionProtectEntity) then + if Selection.is_selecting(player, SelectionName_Entity) then Selection.stop(player) + return Commands.status.success{ "exp-commands_protection.exit-entity" } else - Selection.start(player, SelectionProtectEntity) - return Commands.success{ "expcom-protection.entered-entity-selection" } + Selection.start(player, SelectionName_Entity) + return Commands.status.success{ "exp-commands_protection.enter-entity" } end end) --- Toggles area protection selection --- @command protect-area -Commands.new_command("protect-area", { "expcom-protection.description-pa" }, "Toggles area protection selection, hold shift to remove protection") - :add_alias("pa") +Commands.new("protect-area", { "exp-commands_protection.description-area" }) + :add_aliases{ "pa" } :register(function(player) - if Selection.is_selecting(player, SelectionProtectArea) then + if Selection.is_selecting(player, SelectionName_Entity) then Selection.stop(player) + return Commands.status.success{ "exp-commands_protection.exit-area" } else - Selection.start(player, SelectionProtectArea) - return Commands.success{ "expcom-protection.entered-area-selection" } + Selection.start(player, SelectionName_Entity) + return Commands.status.success{ "exp-commands_protection.enter-area" } end end) --- When an area is selected to add protection to entities -Selection.on_selection(SelectionProtectEntity, function(event) +Selection.on_selection(SelectionName_Entity, function(event) + --- @cast event EventData.on_player_selected_area local player = game.players[event.player_index] for _, entity in ipairs(event.entities) do EntityProtection.add_entity(entity) show_protected_entity(player, entity) end - player.print{ "expcom-protection.protected-entities", #event.entities } + player.print({ "exp-commands_protection.protected-entities", #event.entities }, Commands.print_settings.default) end) --- When an area is selected to remove protection from entities -Selection.on_alt_selection(SelectionProtectEntity, function(event) +Selection.on_alt_selection(SelectionName_Entity, function(event) + --- @cast event EventData.on_player_alt_selected_area local player = game.players[event.player_index] for _, entity in ipairs(event.entities) do EntityProtection.remove_entity(entity) remove_render(player, get_entity_key(entity)) end - player.print{ "expcom-protection.unprotected-entities", #event.entities } + player.print({ "exp-commands_protection.unprotected-entities", #event.entities }, Commands.print_settings.default) end) --- When an area is selected to add protection to the area -Selection.on_selection(SelectionProtectArea, function(event) - local area = aabb_align_expand(event.area) +Selection.on_selection(SelectionName_Area, function(event) + --- @cast event EventData.on_player_selected_area + local surface = event.surface + local area = expand_area(event.area) local areas = EntityProtection.get_areas(event.surface) local player = game.players[event.player_index] for _, next_area in pairs(areas) do - if aabb_area_enclosed(area, next_area) then - return player.print{ "expcom-protection.already-protected" } + if contains_area(next_area, area) then + return player.print({ "exp-commands_protection.already-protected" }, Commands.print_settings.error) end end - EntityProtection.add_area(event.surface, area) - show_protected_area(player, event.surface, area) - player.print{ "expcom-protection.protected-area" } + EntityProtection.add_area(surface, area) + show_protected_area(player, surface, area) + player.print({ "exp-commands_protection.protected-area" }, Commands.print_settings.default) end) --- When an area is selected to remove protection from the area -Selection.on_alt_selection(SelectionProtectArea, function(event) - local area = aabb_align_expand(event.area) - local areas = EntityProtection.get_areas(event.surface) +Selection.on_alt_selection(SelectionName_Area, function(event) + --- @cast event EventData.on_player_alt_selected_area + local surface = event.surface + local area = expand_area(event.area) + local areas = EntityProtection.get_areas(surface) local player = game.players[event.player_index] for _, next_area in pairs(areas) do - if aabb_area_enclosed(next_area, area) then - EntityProtection.remove_area(event.surface, next_area) - player.print{ "expcom-protection.unprotected-area" } + if contains_area(area, next_area) then + EntityProtection.remove_area(surface, next_area) + player.print({ "exp-commands_protection.unprotected-area" }, Commands.print_settings.default) remove_render(player, get_area_key(next_area)) end end end) --- When selection starts show all protected entities and protected areas -Event.add(Selection.events.on_player_selection_start, function(event) - if event.selection ~= SelectionProtectEntity and event.selection ~= SelectionProtectArea then return end +local function on_player_selection_start(event) + if event.selection ~= SelectionName_Entity and event.selection ~= SelectionName_Area then return end local player = game.players[event.player_index] - -- Intentionally left as player.surface to allow use in remote view - local surface = player.surface + local surface = player.surface -- Allow remote view renders[player.index] = {} + -- Show protected entities local entities = EntityProtection.get_entities(surface) for _, entity in pairs(entities) do @@ -192,31 +194,46 @@ Event.add(Selection.events.on_player_selection_start, function(event) show_protected_entity(player, entity) end end + -- Show always protected entities by type if #EntityProtection.protected_entity_types > 0 then for _, entity in pairs(surface.find_entities_filtered{ type = EntityProtection.protected_entity_types, force = player.force }) do show_protected_entity(player, entity) end end + -- Show protected areas local areas = EntityProtection.get_areas(surface) for _, area in pairs(areas) do show_protected_area(player, surface, area) end -end) +end --- When selection ends hide protected entities and protected areas -Event.add(Selection.events.on_player_selection_end, function(event) - if event.selection ~= SelectionProtectEntity and event.selection ~= SelectionProtectArea then return end +local function on_player_selection_end(event) + if event.selection ~= SelectionName_Entity and event.selection ~= SelectionName_Area then return end for _, render in pairs(renders[event.player_index]) do if render.valid then render.destroy() end end renders[event.player_index] = nil -end) +end --- When there is a repeat offence print it in chat -Event.add(EntityProtection.events.on_repeat_violation, function(event) - local player_name = format_player_name(event.player_index) - Roles.print_to_roles_higher("Regular", { "expcom-protection.repeat-offence", player_name, event.entity.localised_name, event.entity.position.x, event.entity.position.y }) -end) +local function on_repeat_violation(event) + Roles.print_to_roles_higher("Regular", { + "exp-commands_protection.repeat-offence", + format_player_name(event.player_index), + event.entity.localised_name, + event.entity.position.x, + event.entity.position.y + }) +end + +return { + events = { + [Selection.events.on_player_selection_start] = on_player_selection_start, + [Selection.events.on_player_selection_end] = on_player_selection_end, + [EntityProtection.events.on_repeat_violation] = on_repeat_violation, + } +} diff --git a/exp_scenario/module/commands/protected_tags.lua b/exp_scenario/module/commands/protected_tags.lua new file mode 100644 index 00000000..51be3610 --- /dev/null +++ b/exp_scenario/module/commands/protected_tags.lua @@ -0,0 +1,112 @@ +--[[-- Commands - Protected Tags +Adds a command that creates chart tags which can only be edited by admins +]] + +local Commands = require("modules/exp_commands") +local Storage = require("modules/exp_util/storage") + +--- Storage variables +local active_players = {} --- @type table Stores all players in in protected mode +local map_tags = {} --- @type table Stores all protected map tags + +Storage.register({ + active_players = active_players, + map_tags = map_tags, +}, function(tbl) + active_players = tbl.active_players + map_tags = tbl.map_tags +end) + +--- Toggle admin marker mode, can only be applied to yourself +local cmd_protected_tag = + Commands.new("protected-tag", { "exp-commands_protected-tags.description" }) + :add_aliases{ "ptag" } + :add_flags{ "admin_only" } + :register(function(player) + if active_players[player.index] then + active_players[player.index] = nil + return Commands.status.success{ "exp-commands_protected-tags.exit" } + else + active_players[player.index] = true + return Commands.status.success{ "exp-commands_protected-tags.enter" } + end + end) + +--- When a player leaves the game, remove them from the active list +--- @param event EventData.on_player_left_game +local function on_player_left_game(event) + active_players[event.player_index] = nil +end + +--- Add a chart tag as protected if the player is in protected mode +--- @param event EventData.on_chart_tag_added +local function on_chart_tag_added(event) + if not event.player_index then return end + if not active_players[event.player_index] then return end + + local tag = event.tag + local player = game.players[event.player_index] + map_tags[tag.force.name .. tag.tag_number] = true + player.print{ "exp-commands_protected-tags.create" } +end + +--- Stop a tag from being edited or removed +--- @param event EventData.on_chart_tag_modified | EventData.on_chart_tag_removed +local function on_chart_tag_removed_or_modified(event) + local tag = event.tag + if not event.player_index then return end + if not map_tags[tag.force.name .. tag.tag_number] then return end + local player = game.players[event.player_index] + + -- Check if the player is in protected mode, and inform them that it was protected + if active_players[event.player_index] then + player.print{ "exp-commands_protected-tags.edit" } + return + end + + -- Check how the changes need to be reverted + if event.name == defines.events.on_chart_tag_modified then + -- Tag was modified, revert the changes + tag.text = event.old_text + tag.icon = event.old_icon + tag.surface = event.old_surface + tag.position = event.old_position + if event.old_player_index then + tag.last_user = game.players[event.old_player_index] + else + tag.last_user = nil + end + + else + -- Tag was removed, recreate the tag + local new_tag = + tag.force.add_chart_tag(tag.surface, { + last_user = tag.last_user, + position = tag.position, + icon = tag.icon, + text = tag.text, + }) + + --- @cast new_tag -nil + map_tags[tag.force.name .. tag.tag_number] = nil + map_tags[new_tag.force.name .. new_tag.tag_number] = true + end + + if Commands.player_has_permission(player, cmd_protected_tag) then + -- Player is not in protected mode, but has access to the command + player.print({ "exp-commands_protected-tags.revert-has-access", cmd_protected_tag.name }, Commands.print_settings.error) + else + --- Player does not have access to protected mode + player.print({ "exp-commands_protected-tags.revert-no-access" }, Commands.print_settings.error) + end +end + +local e = defines.events +return { + events = { + [e.on_chart_tag_added] = on_chart_tag_added, + [e.on_player_left_game] = on_player_left_game, + [e.on_chart_tag_modified] = on_chart_tag_removed_or_modified, + [e.on_chart_tag_removed] = on_chart_tag_removed_or_modified, + } +} diff --git a/exp_legacy/module/modules/commands/rainbow.lua b/exp_scenario/module/commands/rainbow.lua similarity index 52% rename from exp_legacy/module/modules/commands/rainbow.lua rename to exp_scenario/module/commands/rainbow.lua index adad6c11..48580da0 100644 --- a/exp_legacy/module/modules/commands/rainbow.lua +++ b/exp_scenario/module/commands/rainbow.lua @@ -1,12 +1,15 @@ ---[[-- Commands Module - Rainbow - - Adds a command that prints your message in rainbow font - @commands Rainbow +--[[-- Commands - Rainbow +Adds a command that prints your message in rainbow font ]] -local ExpUtil = require("modules/exp_util") -local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands -local format_chat_colour = ExpUtil.format_rich_text_color --- @dep expcore.common +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale +local format_text = Commands.format_rich_text_color +--- Wraps one component into the next +--- @param c1 number +--- @param c2 number +--- @return number, number local function step_component(c1, c2) if c1 < 0 then return 0, c2 + c1 @@ -17,6 +20,9 @@ local function step_component(c1, c2) end end +--- Wraps all components of a colour ensuring it remains valid +--- @param color Color +--- @return Color local function step_color(color) color.r, color.g = step_component(color.r, color.g) color.g, color.b = step_component(color.g, color.b) @@ -25,6 +31,10 @@ local function step_color(color) return color end +--- Get the next colour in the rainbow by the given step +--- @param color Color +--- @param step number +--- @return Color local function next_color(color, step) step = step or 0.1 local new_color = { r = 0, g = 0, b = 0 } @@ -42,22 +52,21 @@ local function next_color(color, step) end --- Sends an rainbow message in the chat --- @command rainbow --- @tparam string message the message that will be printed in chat -Commands.new_command("rainbow", { "expcom-rainbow.description" }, "Sends an rainbow message in the chat") - :add_param("message", false) - :enable_auto_concat() +Commands.new("rainbow", { "exp-commands_rainbow" }) + :argument("message", { "exp-commands_rainbow.arg-message" }, Commands.types.string) + :enable_auto_concatenation() :register(function(player, message) - local player_name = player and player.name or "" - local player_color = player and player.color or nil local color_step = 3 / message:len() if color_step > 1 then color_step = 1 end local current_color = { r = 1, g = 0, b = 0 } - local output = format_chat_colour(player_name .. ": ", player_color) - output = output .. message:gsub("%S", function(letter) - local rtn = format_chat_colour(letter, current_color) - current_color = next_color(current_color, color_step) - return rtn - end) - game.print(output) + + game.print{ + "exp-commands_rainbow.response", + format_player_name(player), + message:gsub("%S", function(letter) + local rtn = format_text(letter, current_color) + current_color = next_color(current_color, color_step) + return rtn + end) + } end) diff --git a/exp_scenario/module/commands/ratio.lua b/exp_scenario/module/commands/ratio.lua new file mode 100644 index 00000000..fffaefd1 --- /dev/null +++ b/exp_scenario/module/commands/ratio.lua @@ -0,0 +1,54 @@ +--[[-- Commands - Ratio +Adds a command to calculate the number of machines needed to fulfil a desired production +]] + +local Commands = require("modules/exp_commands") + +Commands.new("ratio", { "exp-command_ratio.description" }) + :optional("items-per-second", { "exp-command_ratio.arg-items-per-second" }, Commands.types.number) + :register(function(player, items_per_second) + --- @cast items_per_second number? + + local machine = player.selected + if not machine then + return Commands.status.error{ "exp-command_ratio.not-selecting" } + end + + if machine.type ~= "assembling-machine" and machine.type ~= "furnace" then + return Commands.status.error{ "exp-command_ratio.not-selecting" } + end + + local recipe = machine.get_recipe() + if not recipe then + return Commands.status.error{ "exp-command_ratio.not-selecting" } + end + + local products = recipe.products + local ingredients = recipe.ingredients + local crafts_per_second = machine.crafting_speed * machine.productivity_bonus / recipe.energy + + local amount_of_machines = 1 + if items_per_second then + amount_of_machines = math.ceil(products[1].amount * crafts_per_second) + end + + for _, ingredient in ipairs(ingredients) do + Commands.print{ + ingredient.type == "item" and "exp-command_ratio.item-out" or "exp-command_ratio.fluid-out", + math.round(ingredient.amount * crafts_per_second, 3), + ingredient.name + } + end + + for i, product in ipairs(products) do + Commands.print{ + product.type == "item" and "exp-command_ratio.item-out" or "exp-command_ratio.fluid-out", + math.round(product.amount * crafts_per_second, 3), + product.name + } + end + + if amount_of_machines ~= 1 then + Commands.print{ "exp-command_ratio.machine-count", amount_of_machines } + end + end) diff --git a/exp_scenario/module/commands/repair.lua b/exp_scenario/module/commands/repair.lua new file mode 100644 index 00000000..6f82c67b --- /dev/null +++ b/exp_scenario/module/commands/repair.lua @@ -0,0 +1,60 @@ +--[[-- Commands - Repair +Adds a command that allows an admin to repair and revive a large area +]] + +local Commands = require("modules/exp_commands") +local config = require("modules.exp_legacy.config.repair") --- @dep config.repair + +local huge = math.huge + +--- Repairs entities on your force around you +Commands.new("repair", { "exp-commands_repair.description" }) + :argument("range", { "exp-commands_repair.arg-range" }, Commands.types.integer_range(1, config.max_range)) + :register(function(player, range) + --- @cast range number + local force = player.force + local surface = player.surface -- Allow remote view + local position = player.position -- Allow remote view + local response = { "" } --- @type LocalisedString + + if config.allow_ghost_revive then + local revive_count = 0 + local entities = surface.find_entities_filtered{ + type = "entity-ghost", + position = position, + radius = range, + force = force, + } + + for _, entity in ipairs(entities) do + -- TODO test for ghost not being a blueprint, https://forums.factorio.com/viewtopic.php?f=28&t=119736 + if not config.disallow[entity.ghost_name] and (config.allow_blueprint_repair or true) then + revive_count = revive_count + 1 + entity.silent_revive() + end + end + + response[#response + 1] = { "exp-commands_repair.response-revive", revive_count } + end + + if config.allow_heal_entities then + local healed_count = 0 + local entities = surface.find_entities_filtered{ + position = position, + radius = range, + force = force, + } + + for _, entity in ipairs(entities) do + if entity.health and entity.get_health_ratio() ~= 1 then + healed_count = healed_count + 1 + entity.health = huge + end + end + + response[#response + 1] = { "exp-commands_repair.response-heal", healed_count } + end + + return Commands.status.success(response) + end) + diff --git a/exp_scenario/module/commands/reports.lua b/exp_scenario/module/commands/reports.lua new file mode 100644 index 00000000..e0f845aa --- /dev/null +++ b/exp_scenario/module/commands/reports.lua @@ -0,0 +1,107 @@ +--[[-- Commands - Reports +Adds a commands that allow players to report other players +]] + +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale +local parse_input = Commands.parse_input + +local Roles = require("modules.exp_legacy.expcore.roles") +local player_has_flag = Roles.player_has_flag + +local Reports = require("modules.exp_legacy.modules.control.reports") --- @dep modules.control.reports + +--- @type Commands.InputParser +local function reportable_player(input, player) + local success, status, result = parse_input(input, player, Commands.types.player) + if not success then return status, result end + --- @cast result LuaPlayer + + if player_has_flag(input, "report-immune") then + return Commands.status.invalid_input{ "exp-commands_reports.player-immune" } + elseif player == input then + return Commands.status.invalid_input{ "exp-commands_reports.self-report" } + else + return Commands.status.success(result) + end +end + +--- Reports a player and notifies admins +Commands.new("create-report", { "exp-commands_reports.description-create" }) + :argument("player", { "exp-commands_reports.arg-player-create" }, reportable_player) + :argument("reason", { "exp-commands_reports.arg-reason" }, Commands.types.string) + :enable_auto_concatenation() + :add_aliases{ "report" } + :register(function(player, other_player, reason) + --- @cast other_player LuaPlayer + --- @cast reason string + local player_name = format_player_name(player) + local other_player_name = format_player_name(other_player) + if Reports.report_player(other_player, player.name, reason) then + local user_message = { "exp-commands_reports.response", other_player_name, reason } + local admin_message = { "exp-commands_reports.response-admin", other_player_name, player_name, reason } + for _, player in ipairs(game.connected_players) do + if player.admin then + player.print(admin_message) + else + player.print(user_message) + end + end + else + return Commands.status.invalid_input{ "exp-commands_reports.already-reported" } + end + end) + +--- Gets a list of all reports that a player has on them. If no player then lists all players and the number of reports on them. +Commands.new("get-reports", { "exp-commands_reports.description-get" }) + :optional("player", { "exp-commands_reports.arg-player-get" }, Commands.types.player) + :add_aliases{ "reports" } + :add_flags{ "admin_only" } + :register(function(player, other_player) + --- @cast other_player LuaPlayer? + if other_player then + local reports = Reports.get_reports(other_player) + local other_player_name = format_player_name(other_player) + Commands.print{ "exp-commands_reports.player-title", other_player_name, #reports } + for by_player_name, reason in pairs(reports) do + local by_player_name_formatted = format_player_name(by_player_name) + Commands.print{ "exp-commands_reports.list-element", by_player_name_formatted, reason } + end + else + local reports = Reports.user_reports + Commands.print{ "exp-commands_reports.reports-title" } + for player_name in pairs(reports) do + local player_name_formatted = format_player_name(player_name) + local report_count = Reports.count_reports(player_name) + Commands.print{ "exp-commands_reports.list-element", player_name_formatted, report_count } + end + end + end) + +--- Clears all reports from a player or just the report from one player. +Commands.new("clear-reports", { "exp-commands_reports.description-clear" }) + :argument("player", { "exp-commands_reports.arg-player-clear" }, Commands.types.player) + :optional("from-player", { "exp-commands_reports.arg-from-player" }, Commands.types.player) + :add_flags{ "admin_only" } + :register(function(player, other_player, from_player) + --- @cast other_player LuaPlayer + --- @cast from_player LuaPlayer? + local player_name = format_player_name(player) + local other_player_name = format_player_name(other_player) + if from_player then + if not Reports.remove_report(other_player, from_player.name, player.name) then + local from_player_name = format_player_name(other_player) + return Commands.status.invalid_input{ "exp-commands_reports.not-reported-by", from_player_name } + else + game.print{ "exp-commands_reports.removed", other_player_name, player_name } + return Commands.status.success() + end + else + if not Reports.remove_all(other_player, player.name) then + return Commands.status.invalid_input{ "exp-commands_reports.not-reported" } + else + game.print{ "exp-commands_reports.removed-all", other_player_name, player_name } + return Commands.status.success() + end + end + end) diff --git a/exp_scenario/module/commands/research.lua b/exp_scenario/module/commands/research.lua new file mode 100644 index 00000000..5052e628 --- /dev/null +++ b/exp_scenario/module/commands/research.lua @@ -0,0 +1,71 @@ +--[[-- Commands - Research +Adds a command to enable automatic research queueing +]] + +local Storage = require("modules/exp_util/storage") +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale + +local config = require("modules.exp_legacy.config.research") --- @dep config.research + +local research = { + res_queue_enable = false +} + +Storage.register(research, function(tbl) + research = tbl +end) + +--- @param force LuaForce +--- @param silent boolean True when no message should be printed +local function res_queue(force, silent) + local res_q = force.research_queue + local res = force.technologies["mining-productivity-4"] + + if #res_q < config.queue_amount then + for i = 1, config.queue_amount - #res_q do + force.add_research(res) + + if not silent then + game.print{ "exp-commands_research.queue", res.name, res.level + i } + end + end + end +end + +--- Sets the auto research state +Commands.new("set-auto-research", { "exp-commands_research.description" }) + :optional("state", { "exp-commands_research.arg-state" }, Commands.types.boolean) + :add_aliases{ "auto-research" } + :register(function(player, state) + --- @cast state boolean? + if state == nil then + research.res_queue_enable = not research.res_queue_enable + else + research.res_queue_enable = state + end + + if research.res_queue_enable then + res_queue(player.force --[[@as LuaForce]], true) + end + + local player_name = format_player_name(player) + game.print{ "exp-commands_research.auto-research", player_name, research.res_queue_enable } + end) + +--- @param event EventData.on_research_finished +local function on_research_finished(event) + if not research.res_queue_enable then return end + + local force = event.research.force + if force.rockets_launched > 0 and force.technologies["mining-productivity-4"].level > 4 then + res_queue(force, event.by_script) + end +end + +local e = defines.events +return { + events = { + [e.on_research_finished] = on_research_finished, + } +} diff --git a/exp_scenario/module/commands/roles.lua b/exp_scenario/module/commands/roles.lua new file mode 100644 index 00000000..7f519bf3 --- /dev/null +++ b/exp_scenario/module/commands/roles.lua @@ -0,0 +1,63 @@ +--[[-- Commands - Roles +Adds a commands that allow interaction with the role system +]] + +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale +local format_text = Commands.format_rich_text_color_locale + +local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles +local get_roles_ordered = Roles.get_roles_ordered +local get_player_roles = Roles.get_player_roles + +--- Assigns a role to a player +Commands.new("assign-role", { "exp-commands_roles.description-assign" }) + :argument("player", { "exp-commands_roles.arg-player-assign" }, Commands.types.lower_role_player) + :argument("role", { "exp-commands_roles.arg-role-assign" }, Commands.types.lower_role) + :add_aliases{ "assign" } + :add_flags{ "admin_only" } + :register(function(player, other_player, role) + --- @cast other_player LuaPlayer + --- @cast role any -- TODO + Roles.assign_player(other_player, role, player.name) + end) + +--- Unassigns a role to a player +Commands.new("unassign-role", { "exp-commands_roles.description-unassign" }) + :argument("player", { "exp-commands_roles.arg-player-unassign" }, Commands.types.lower_role_player) + :argument("role", { "exp-commands_roles.arg-role-unassign" }, Commands.types.lower_role) + :add_aliases{ "unassign" } + :add_flags{ "admin_only" } + :register(function(player, other_player, role) + --- @cast other_player LuaPlayer + --- @cast role any -- TODO + Roles.unassign_player(other_player, role, player.name) + end) + +--- Lists all roles in they correct order +Commands.new("get-role", { "exp-commands_roles.description-get" }) + :optional("player", { "exp-commands_roles.arg-player-get" }, Commands.types.player) + :add_aliases{ "roles" } + :add_flags{ "admin_only" } + :register(function(player, other_player) + --- @cast other_player LuaPlayer? + local roles = get_roles_ordered() + local roles_formatted = { "" } --- @type LocalisedString + local response = { "exp-commands_roles.list-roles", roles_formatted } + if other_player then + roles = get_player_roles(other_player) + response[1] = "exp-commands_roles.list-player" + response[3] = format_player_name(other_player) + end + + for index, role in ipairs(roles) do + local role_name = format_text(role.name, role.custom_color or Commands.color.white) + roles_formatted[index + 1] = { "exp-commands_roles.list-element", role_name } + end + + local last = #roles_formatted + --- @diagnostic disable-next-line nil-check + roles_formatted[last] = roles_formatted[last][2] + + return Commands.status.success(response) + end) diff --git a/exp_scenario/module/commands/search.lua b/exp_scenario/module/commands/search.lua new file mode 100644 index 00000000..e0869067 --- /dev/null +++ b/exp_scenario/module/commands/search.lua @@ -0,0 +1,181 @@ +--[[-- Commands - Inventory Search +Adds commands that will search all players inventories for an item +]] + +local ExpUtil = require("modules/exp_util") + +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale + +local format_number = require("util").format_number + +--- A player who is of a lower role than the executing player +--- @type Commands.InputParser +local function parse_item(input, player) + -- First Case - internal name is given + -- Second Case - rich text is given + local item_name = input:lower():gsub(" ", "-") + local item = prototypes.item[item_name] or prototypes.item[input:match("%[item=([0-9a-z-]+)%]")] + if item then + return Commands.status.success(item) + end + + -- No item found, we do not attempt to search all prototypes as this will be expensive + return Commands.status.invalid_input{ "exp-commands_search.invalid-item", item_name } +end + +--- @class SearchResult: { player: LuaPlayer, count: number, online_time: number } + +--- Search all players for this item +--- @param players LuaPlayer[] Players to search +--- @param item LuaItemPrototype Item to find +--- @return SearchResult[] +local function search_players(players, item) + local found = {} --- @type SearchResult[] + local head = 1 + + -- Check the item count of all players + for _, player in pairs(players) do + local item_count = player.get_item_count(item.name) + if item_count > 0 then + -- Add the player to the array as they have the item + found[head] = { player = player, count = item_count, online_time = player.online_time } + head = head + 1 + end + end + + return found +end + +--- @alias SortFunction fun(result: SearchResult): number + +--- Custom sort function which only retains 5 greatest values +--- @param results SearchResult[] Players to sort +--- @param func SortFunction Function to calculate value, higher better +--- @return SearchResult[] # Top 5 results +local function sort_results(results, func) + local sorted = {} + local values = {} + local threshold = 0 + + -- Loop over all provided players + for index, result in ipairs(results) do + local value = func(result) + -- Check if the item will make the top 5 elements + if index <= 5 or value > threshold then + local inserted = false + values[result] = value + + -- Find where in the top 5 to insert the element + for next_index, next_result in ipairs(sorted) do + if value > values[next_result] then + table.insert(sorted, next_index, result) + inserted = true + break + end + end + + -- Update the threshold, clean up the tables, and insert if needed + if sorted[6] then + threshold = values[sorted[5]] + values[sorted[6]] = nil + sorted[6] = nil + elseif not inserted then + -- index <= 5 so insert at the end + sorted[#sorted + 1] = result + threshold = value + end + end + end + + return sorted +end + +local display_players_time_format = ExpUtil.format_time_factory_locale{ format = "short", hours = true, minutes = true } + +--- Display to the player the top players which were found +--- @param results SearchResult[] +--- @param item LuaItemPrototype +--- @return LocalisedString +local function format_response(results, item) + if #results == 0 then + return { "exp-commands_search.no-results", item.name } + end + + local response = { "", { "exp-commands_search.title", item.name } } --- @type LocalisedString + for index, data in ipairs(results) do + response[index + 2] = { + "exp-commands_search.result", + index, + format_player_name(data.player), + format_number(data.count, false), + display_players_time_format(data.online_time), + } + end + + return response +end + +--- Return the the amount of an item a player has divided by their playtime +local function combined_sort(data) + return data.count / data.online_time +end + +--- Get a list of players sorted by quantity held and play time +Commands.new("search", { "exp-commands_search.description-search" }) + :argument("item", { "exp-commands_search.arg-item" }, parse_item) + :enable_auto_concatenation() + :add_aliases{ "s" } + :register(function(player, item) + --- @cast item LuaItemPrototype + local results = search_players(game.players, item) + local sorted = sort_results(results, combined_sort) + return Commands.status.success(format_response(sorted, item)) + end) + +--- Get a list of online players sorted by quantity held and play time +Commands.new("search-online", { "exp-commands_search.description-online" }) + :argument("item", { "exp-commands_search.arg-item" }, parse_item) + :enable_auto_concatenation() + :add_aliases{ "so" } + :register(function(player, item) + --- @cast item LuaItemPrototype + local results = search_players(game.connected_players, item) + local sorted = sort_results(results, combined_sort) + return Commands.status.success(format_response(sorted, item)) + end) + +--- Return the amount of an item a player has +--- @type SortFunction +local function sort_by_count(data) + return data.count +end + +--- Get a list of players sorted by the quantity of an item in their inventory +Commands.new("search-amount", { "exp-commands_search.description-amount" }) + :argument("item", { "exp-commands_search.arg-item" }, parse_item) + :enable_auto_concatenation() + :add_aliases{ "sa" } -- cant use /sc + :register(function(player, item) + --- @cast item LuaItemPrototype + local results = search_players(game.players, item) + local sorted = sort_results(results, sort_by_count) + return Commands.status.success(format_response(sorted, item)) + end) + +--- Return the index of the player, higher means they joined more recently +local function sort_by_recent(data) + return data.player.index +end + +--- Get a list of players who have the given item, sorted by how recently they joined +Commands.new("search-recent", { "exp-commands_search.description-recent" }) + :argument("item", { "exp-commands_search.arg-item" }, parse_item) + :enable_auto_concatenation() + :add_aliases{ "sr" } -- cant use /sc + :register(function(player, item) + --- @cast item LuaItemPrototype + local results = search_players(game.players, item) + local sorted = sort_results(results, sort_by_recent) + return Commands.status.success(format_response(sorted, item)) + end) diff --git a/exp_scenario/module/commands/spectate.lua b/exp_scenario/module/commands/spectate.lua new file mode 100644 index 00000000..48733940 --- /dev/null +++ b/exp_scenario/module/commands/spectate.lua @@ -0,0 +1,29 @@ +--[[-- Commands - Spectate +Adds commands relating to spectate and follow +]] + +local Commands = require("modules/exp_commands") +local Spectate = require("modules.exp_legacy.modules.control.spectate") --- @dep modules.control.spectate + +--- Toggles spectator mode for the caller +Commands.new("spectate", { "exp-commands_spectate.description-spectate" }) + :register(function(player) + if Spectate.is_spectating(player) then + Spectate.stop_spectate(player) + else + Spectate.start_spectate(player) + end + end) + +--- Enters follow mode for the caller, following the given player. +Commands.new("follow", { "exp-commands_spectate.description-follow" }) + :argument("player", { "exp-command_spectate.arg-player" }, Commands.types.player_online) + :add_aliases{ "f" } + :register(function(player, other_player) + --- @cast other_player LuaPlayer + if player == other_player then + return Commands.status.invalid_input{ "exp-command_spectate.follow-self" } + else + Spectate.start_follow(player, other_player) + end + end) diff --git a/exp_scenario/module/commands/surface.lua b/exp_scenario/module/commands/surface.lua new file mode 100644 index 00000000..95392d57 --- /dev/null +++ b/exp_scenario/module/commands/surface.lua @@ -0,0 +1,89 @@ +--[[-- Commands - Clear Item On Ground +Adds a command that clear item on ground so blueprint can deploy safely +]] + +local ExpUtil = require("modules/exp_util") +local move_items = ExpUtil.move_items_to_surface + +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale + +--- @param surface LuaSurface +--- @return LuaItemStack[] +local function get_ground_items(surface) + local items = {} --- @type LuaItemStack[] + local entities = surface.find_entities_filtered{ name = "item-on-ground" } + for index, entity in ipairs(entities) do + items[index] = entity.stack + end + return items +end + +--- Clear all items on the ground, optional to select a single surface +Commands.new("clear-ground-items", { "exp-commands_surface.description-items" }) + :optional("surface", { "exp-commands_surface.arg-surface" }, Commands.types.surface) + :register(function(player, surface) + --- @cast surface LuaSurface? + local player_name = format_player_name(player) + if surface then + move_items{ + surface = surface, + items = get_ground_items(surface), + allow_creation = true, + name = "iron-chest", + } + game.print{ "exp-commands_surface.items-surface", player_name, surface.localised_name } + else + for _, surface in pairs(game.surfaces) do + move_items{ + surface = surface, + items = get_ground_items(surface), + allow_creation = true, + name = "iron-chest", + } + end + game.print{ "exp-commands_surface.items-all", player_name } + end + end) + +--- Clear all blueprints, optional to select a single surface +Commands.new("clear-blueprints", { "exp-commands_surface.description-blueprints" }) + :optional("surface", { "exp-commands_surface.arg-surface" }, Commands.types.surface) + :register(function(player, surface) + --- @cast surface LuaSurface? + local player_name = format_player_name(player) + if surface then + local entities = surface.find_entities_filtered{ type = "entity-ghost" } + for _, entity in ipairs(entities) do + entity.destroy() + end + game.print{ "exp-commands_surface.blueprint-surface", player_name, surface.localised_name } + else + for _, surface in pairs(game.surfaces) do + local entities = surface.find_entities_filtered{ type = "entity-ghost" } + for _, entity in ipairs(entities) do + entity.destroy() + end + end + game.print{ "exp-commands_surface.blueprint-all", player_name } + end + end) + +--- Clear all blueprints in a radius around you +Commands.new("clear-blueprints-radius", { "exp-commands_surface.description-radius" }) + :argument("radius", { "exp-commands_surface.arg-radius" }, Commands.types.number_range(1, 1000)) + :register(function(player, radius) + --- @cast radius number + local player_name = format_player_name(player) + local entities = player.surface.find_entities_filtered{ + type = "entity-ghost", + position = player.position, + radius = radius, + } + + for _, entity in ipairs(entities) do + entity.destroy() + end + + game.print{ "exp-commands_surface.blueprint-radius", player_name, radius, player.surface.localised_name } + end) diff --git a/exp_scenario/module/commands/teleport.lua b/exp_scenario/module/commands/teleport.lua new file mode 100644 index 00000000..e22443e8 --- /dev/null +++ b/exp_scenario/module/commands/teleport.lua @@ -0,0 +1,84 @@ +--[[-- Commands - Teleport +Adds a command that allows players to teleport to other players and spawn +]] + +local ExpUtil = require("modules/exp_util") +local teleport_player = ExpUtil.teleport_player + +local Commands = require("modules/exp_commands") + +local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles +local player_allowed = Roles.player_allowed + +--- Teleports a player to another player. +Commands.new("teleport", { "exp-commands_teleport.description-teleport" }) + :argument("player", { "exp-commands_teleport.arg-player-teleport" }, Commands.types.player_alive) + :optional("target", { "exp-commands_teleport.arg-player-to" }, Commands.types.player_alive) + :add_aliases{ "tp" } + :add_flags{ "admin_only" } + :register(function(player, other_player, target_player) + --- @cast other_player LuaPlayer + --- @cast target_player LuaPlayer? + if target_player == nil then + -- When no player is given, then instead behave like /goto + if not teleport_player(player, other_player.physical_surface, other_player.physical_position) then + return Commands.status.error{ "exp-commands_teleport.unavailable" } + end + elseif other_player == target_player then + return Commands.status.invalid_input{ "exp-commands_teleport.same-player" } + elseif not teleport_player(other_player, target_player.physical_surface, target_player.physical_position) then + return Commands.status.error{ "exp-commands_teleport.unavailable" } + end + end) + +--- Teleports a player to you. +Commands.new("bring", { "exp-commands_teleport.description-bring" }) + :argument("player", { "exp-commands_teleport.arg-player-from" }, Commands.types.player_alive) + :add_flags{ "admin_only" } + :register(function(player, other_player) + --- @cast other_player LuaPlayer + if player == other_player then + return Commands.status.invalid_input{ "exp-commands_teleport.same-player" } + elseif not teleport_player(other_player, player.physical_surface, player.physical_position) then + return Commands.status.error{ "exp-commands_teleport.unavailable" } + end + end) + +--- Teleports you to a player. +Commands.new("goto", { "exp-commands_teleport.description-goto" }) + :argument("player", { "exp-commands_teleport.arg-player-to" }, Commands.types.player_alive) + :add_flags{ "admin_only" } + :register(function(player, other_player) + --- @cast other_player LuaPlayer + if player == other_player then + return Commands.status.invalid_input{ "exp-commands_teleport.same-player" } + elseif not teleport_player(player, other_player.physical_surface, other_player.physical_position) then + return Commands.status.error{ "exp-commands_teleport.unavailable" } + end + end) + +--- Teleport to spawn +Commands.new("spawn", { "exp-commands_teleport.description-spawn" }) + :optional("player", { "exp-commands_teleport.arg-player-spawn" }, Commands.types.player_alive) + :defaults{ + player = function(player) + if player.character and player.character.health > 0 then + return player + end + end, + } + :register(function(player, other_player) + if not other_player then + return Commands.status.error{ "exp-commands_teleport.unavailable" } + elseif other_player == player then + if not teleport_player(player, game.surfaces.nauvis, { 0, 0 }, "dismount") then + return Commands.status.error{ "exp-commands_teleport.unavailable" } + end + elseif player_allowed(player, "command/spawn/always") then + if not teleport_player(other_player, game.surfaces.nauvis, { 0, 0 }, "dismount") then + return Commands.status.error{ "exp-commands_teleport.unavailable" } + end + else + return Commands.status.unauthorised() + end + end) diff --git a/exp_scenario/module/commands/trains.lua b/exp_scenario/module/commands/trains.lua new file mode 100644 index 00000000..a0f76430 --- /dev/null +++ b/exp_scenario/module/commands/trains.lua @@ -0,0 +1,29 @@ +--[[-- Commands - Set Automatic Train +Adds a command that set all train back to automatic +]] + +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale + +local format_number = require("util").format_number + +--- Set all trains to automatic +Commands.new("set-trains-to-automatic", { "exp-commands_trains.description" }) + :optional("surface", { "exp-commands_trains.arg-surface" }, Commands.types.surface) + :optional("force", { "exp-commands_trains.arg-force" }, Commands.types.force) + :register(function(player, surface, force) + --- @cast surface LuaSurface? + --- @cast force LuaForce? + local trains = game.train_manager.get_trains{ + has_passenger = false, + is_manual = true, + surface = surface, + force = force, + } + + for _, train in ipairs(trains) do + train.manual_mode = false + end + + game.print{ "exp-commands_trains.response", format_player_name(player), format_number(#trains, false) } + end) diff --git a/exp_scenario/module/commands/vlayer.lua b/exp_scenario/module/commands/vlayer.lua new file mode 100644 index 00000000..4a21f13f --- /dev/null +++ b/exp_scenario/module/commands/vlayer.lua @@ -0,0 +1,18 @@ +--[[-- Commands - VLayer +Adds a virtual layer to store power to save space. +]] + +local Commands = require("modules/exp_commands") +local vlayer = require("modules.exp_legacy.modules.control.vlayer") + +--- Print all vlayer information +Commands.new("vlayer-info", { "exp-commands_vlayer.description" }) + :register(function(player) + local index = 3 + local response = { "", "exp-commands_vlayer.title" } --- @type LocalisedString + for title, value in pairs(vlayer.get_circuits()) do + response[index] = { "exp-commands_vlayer.result", title, value } + index = index + 1 + end + return Commands.status.success(response) + end) diff --git a/exp_scenario/module/commands/warnings.lua b/exp_scenario/module/commands/warnings.lua new file mode 100644 index 00000000..bcc8c38d --- /dev/null +++ b/exp_scenario/module/commands/warnings.lua @@ -0,0 +1,96 @@ +--[[-- Commands - Warnings +Adds a commands that allow admins to warn other players +]] + +local Commands = require("modules/exp_commands") +local format_player_name = Commands.format_player_name_locale + +local Warnings = require("modules.exp_legacy.modules.control.warnings") --- @dep modules.control.warnings +local config = require("modules.exp_legacy.config.warnings") --- @dep config.warnings + +--- Gives a warning to a player; may lead to automatic script action. +Commands.new("create-warning", { "exp-commands_warnings.description-create" }) + :argument("player", { "exp-commands_warnings.arg-player-create" }, Commands.types.lower_role_player) + :argument("reason", { "exp-commands_warnings.arg-reason" }, Commands.types.string) + :enable_auto_concatenation() + :add_aliases{ "warn" } + :add_flags{ "admin_only" } + :register(function(player, other_player, reason) + --- @cast other_player LuaPlayer + --- @cast reason string + Warnings.add_warning(other_player, player.name, reason) + local player_name = format_player_name(player) + local other_player_name = format_player_name(other_player) + game.print{ "exp-commands_warnings.create", other_player_name, player_name, reason } + end) + +--- Gets a list of all warnings that a player has on them. If no player then lists all players and the number of warnings on them. +Commands.new("get-warnings", { "exp-commands_warnings.description-get" }) + :optional("player", { "exp-commands_warnings.arg-player-get" }, Commands.types.player) + :add_aliases{ "warnings" } + :add_flags{ "admin_only" } + :register(function(player, other_player) + --- @cast other_player LuaPlayer? + if other_player then + local warnings = Warnings.get_warnings(player) + local script_warnings = Warnings.get_script_warnings(player) + local other_player_name = format_player_name(other_player) + Commands.print{ "exp-commands_warnings.player-title", other_player_name, #warnings, #script_warnings, config.temp_warning_limit } + for _, warning in pairs(warnings) do + local by_player_name_formatted = format_player_name(warning.by_player_name) + Commands.print{ "exp-commands_warnings.list-element-player", by_player_name_formatted, warning.reason } + end + else + local warnings = Warnings.user_warnings:get_all() + local script_warnings = Warnings.user_script_warnings + Commands.print{ "exp-commands_warnings.warnings-title" } + for player_name, player_warnings in pairs(warnings) do + local player_name_formatted = format_player_name(player_name) + local script_warning_count = script_warnings[player_name] and #script_warnings[player_name] or 0 + Commands.print{ "exp-commands_warnings.list-element", player_name_formatted, #player_warnings, script_warning_count, config.temp_warning_limit } + end + for player_name, player_warnings in pairs(script_warnings) do + if not warnings[player_name] then + local player_name_formatted = format_player_name(player_name) + Commands.print{ "exp-commands_warnings.list-element", player_name_formatted, 0, #player_warnings, config.temp_warning_limit } + end + end + end + end) + +--- Clears all warnings from a player +Commands.new("clear-warnings", { "exp-commands_warnings.description-clear" }) + :argument("player", { "exp-commands_warnings.arg-player-clear" }, Commands.types.player) + :add_flags{ "admin_only" } + :register(function(player, other_player) + --- @cast other_player LuaPlayer + Warnings.clear_warnings(other_player, player.name) + Warnings.clear_script_warnings(other_player) + local player_name = format_player_name(player) + local other_player_name = format_player_name(other_player) + game.print{ "exp-commands_warnings.cleared", other_player_name, player_name } + end) + +--- Clears all script warnings from a player +Commands.new("clear-script-warnings", { "exp-commands_warnings.description-clear-script" }) + :argument("player", { "exp-commands_warnings.arg-player-clear" }, Commands.types.player) + :add_flags{ "admin_only" } + :register(function(player, other_player) + --- @cast other_player LuaPlayer + Warnings.clear_script_warnings(other_player) + local player_name = format_player_name(player) + local other_player_name = format_player_name(other_player) + game.print{ "exp-commands_warnings.cleared-script", other_player_name, player_name } + end) + +--- Clears the last warning that was given to a player +Commands.new("clear-last-warnings", { "exp-commands_warnings.description-clear-last" }) + :argument("player", { "exp-commands_warnings.arg-player-clear" }, Commands.types.player) + :add_flags{ "admin_only" } + :register(function(player, other_player) + --- @cast other_player LuaPlayer + Warnings.remove_warning(other_player, player.name) + local player_name = format_player_name(player) + local other_player_name = format_player_name(other_player) + game.print{ "exp-commands_warnings.cleared-last", other_player_name, player_name } + end) diff --git a/exp_scenario/module/commands/waterfill.lua b/exp_scenario/module/commands/waterfill.lua new file mode 100644 index 00000000..4fe3cb8f --- /dev/null +++ b/exp_scenario/module/commands/waterfill.lua @@ -0,0 +1,69 @@ +--[[-- Commands - Waterfill +Adds a command that places shallow water +]] + +local AABB = require("modules/exp_util/aabb") +local Commands = require("modules/exp_commands") +local Selection = require("modules.exp_legacy.modules.control.selection") --- @dep modules.control.selection +local SelectionName = "ExpCommand_Waterfill" + +--- Toggle player selection mode for artillery +Commands.new("waterfill", { "exp-commands_waterfill.description" }) + :register(function(player) + if Selection.is_selecting(player, SelectionName) then + Selection.stop(player) + return Commands.status.success{ "exp-commands_waterfill.exit" } + elseif player.get_item_count("cliff-explosives") == 0 then + return Commands.status.error{ "exp-commands_waterfill.requires-explosives" } + else + Selection.start(player, SelectionName) + return Commands.status.success{ "exp-commands_waterfill.enter" } + end + end) + +--- When an area is selected to be converted to water +Selection.on_selection(SelectionName, function(event) + --- @cast event EventData.on_player_selected_area + local area = AABB.expand(event.area) + local player = game.players[event.player_index] + local surface = event.surface + + if surface.planet and surface.planet ~= game.planets.nauvis then + player.print({ "exp-cods_waterfill.nauvis-only" }, Commands.print_settings.error) + return + end + + local area_size = (area.right_bottom.x - area.left_top.x) * (area.right_bottom.y - area.left_top.y) + if area_size > 1000 then + player.print({ "exp-cods_waterfill.area-too-large", 1000, area_size }, Commands.print_settings.error) + return + end + + local item_count = player.get_item_count("cliff-explosives") + if item_count < area_size then + player.print({ "exp-cods_waterfill.too-few-explosives", area_size, item_count }, Commands.print_settings.error) + return + end + + local tile_count = 0 + local tiles_to_make = {} + for x = area.left_top.x, area.right_bottom.x do + for y = area.left_top.y, area.right_bottom.y do + tile_count = tile_count + 1 + tiles_to_make[tile_count] = { + name = "water-mud", + position = { x, y }, + } + end + end + + surface.set_tiles(tiles_to_make, true, "abort_on_collision", true, false, player, 0) + local remaining_tiles = surface.count_tiles_filtered{ area = area, name = "water-mud" } + player.remove_item{ name = "cliff-explosives", count = tile_count - remaining_tiles } + + if remaining_tiles > 0 then + player.print({ "exp-cods_waterfill.part-complete", tile_count, remaining_tiles }, Commands.print_settings.default) + else + player.print({ "exp-cods_waterfill.complete", tile_count }, Commands.print_settings.default) + end +end) diff --git a/exp_scenario/module/control.lua b/exp_scenario/module/control.lua index f1c07e02..797908a6 100644 --- a/exp_scenario/module/control.lua +++ b/exp_scenario/module/control.lua @@ -1,9 +1,43 @@ +local event_handler = require("event_handler") + +--- @type fun(lib: { on_init: fun(), on_load: fun(), events: { [defines.events]: fun(event: EventData) } }) +local add = event_handler.add_lib --- Command Extensions -require("modules.exp_scenario/commands/types") -require("modules.exp_scenario/commands/authorities") +require("modules.exp_scenario/commands/_authorities") +require("modules.exp_scenario/commands/_rcon") +require("modules.exp_scenario/commands/_types") + +--- Commands with events +add(require("modules/exp_scenario/commands/protected_entities")) +add(require("modules/exp_scenario/commands/protected_tags")) +add(require("modules/exp_scenario/commands/research")) --- Commands require("modules/exp_scenario/commands/admin_chat") +require("modules/exp_scenario/commands/artillery") require("modules/exp_scenario/commands/bot_queues") require("modules/exp_scenario/commands/cheat") +require("modules/exp_scenario/commands/clear_inventory") +require("modules/exp_scenario/commands/connect") +require("modules/exp_scenario/commands/debug") +require("modules/exp_scenario/commands/enemy") +require("modules/exp_scenario/commands/home") +require("modules/exp_scenario/commands/jail") +require("modules/exp_scenario/commands/kill") +require("modules/exp_scenario/commands/lawnmower") +require("modules/exp_scenario/commands/locate") +require("modules/exp_scenario/commands/me") +require("modules/exp_scenario/commands/rainbow") +require("modules/exp_scenario/commands/ratio") +require("modules/exp_scenario/commands/repair") +require("modules/exp_scenario/commands/reports") +require("modules/exp_scenario/commands/roles") +require("modules/exp_scenario/commands/search") +require("modules/exp_scenario/commands/spectate") +require("modules/exp_scenario/commands/surface") +require("modules/exp_scenario/commands/teleport") +require("modules/exp_scenario/commands/trains") +require("modules/exp_scenario/commands/vlayer") +require("modules/exp_scenario/commands/warnings") +require("modules/exp_scenario/commands/waterfill") diff --git a/exp_scenario/module/locale/en.cfg b/exp_scenario/module/locale/en.cfg index 66e44310..ce8b8d50 100644 --- a/exp_scenario/module/locale/en.cfg +++ b/exp_scenario/module/locale/en.cfg @@ -1,6 +1,282 @@ [exp-commands-authorities_role] -deny=Unauthorized, Access is denied due to missing permissions +deny=Unauthorized, Access is denied due to missing permissions. [exp-commands-parse_role] lower-role=Role is higher than your highest. lower-role-player=Player has a higher role. + +[exp-commands_admin-chat] +description=Sends a message in chat that only admins can see. +arg-message=The message to send. +format=[AC] __1__: __2__ + +[exp-commands_artillery] +description=Automaticly select enemy target with artillery. +invalid-area=The selected area is not valid. +enter=Entered artillery selection mode. +exit=Existed artillery selection mode. + +[exp-commands_bot-queue] +description-get=Get / Set the construction bot queue limits. +arg-amount=Multiple of default value to set the queues to. +get=Bot queue is __1__ successful attempts and __2__ failed attempts. +set=__1__ set the bot queue to __2__ successful attempts and __3__ failed attempts. + +[exp-commands_cheat] +description-cheat-mode=Set cheat mode for your player, or another player. +description-always-day=Set always day for your current surface, or another surface. +description-friendly-fire=Set friendly fire for your force, or another force. +description-research-all=Research all technology for your force, or another force. +description-clear-pollution=Clear pollution from your current surface, or another surface. +description-pollution-enabled=Set polution enabled state for this game. +description=game-speed=Set or get the current game speed. +arg-state=State to set, default is to toggle the current value. +arg-player=Player to toggle cheat mode for. +arg-force-friendly-fire=Force to research all technology for. +arg-force-research=Force to research all technology for. +arg-surface=Surface to toggle always day for. +arg-amount=Amount to set, returns the current value if not given. +cheat-mode=Cheat mode is now __1__ +always-day=__1__ has toggled always day on __2__ surface to __3__. +friendly-fire=__1__ set friendly fire for __2__ to __3__. +research-all=__1__ has enabled all technology for __2__ force. +clear-pollution=__1__ has cleared pollution from __2__. +pollution-enabled=__1__ has set the polution enabled state to __2__. +game-speed-set=__1__ has set the game speed to __2__. +game-speed-get=The current game speed is __1__. + +[exp-commands_clear-inventory] +description=Clears a players inventory, all items will be moved to the spawn point. +arg-player=Player to clear the inventory of. + +[exp-commands_connect] +description=Connect to another server. +description-player=Connect a player to a different server. +description-all=Connect all players to another server. +arg-player=Player to connect to another server. +arg-server=Server name or address to connect to. +arg-is-address=True when the input should be read as an address. +too-many-matching=Multiple server were found with the given name: __1__ +wrong-version=Servers were found but are on a different version: __1__ +same-server=You are already connected to the server: __1__ +offline=You cannot connect as the server is currently offline: __1__ +none-matching=No servers were found with that name, if you used an address please append true to the end of your command. + +[expcom-debug] +description=Opens the debug gui. + +[exp-commands_enemy] +description-kill=Kill all enemy units. +description-remove=Remove all enemy spawners. +arg-surface=Surface to remove spawners from. + +[exp-commands_home] +description-home=Teleports you to your home location. +description-return=Teleports you to previous location. +description-get=Returns your current home location. +description-set=Sets your home location to your current position. +no-home=You have no home set on __1__. +no-return=You can't return when /home has not been used on __1__. +home-get=Your home point on __1__ is at x: __2__ y: __3__ +home-set=Your home point on __1__ has been set to x: __2__ y: __3__ +return-set=Your return point on __1__ has been set to x: __1__ y: __2__ + +[exp-commands_jail] +description=Puts a player into jail and removes all other roles. +arg-player=Player to jail. +arg-reason=Reason to jail the player. +jailed=__1__ was jailed by __2__. Reason: __3__ +already-jailed=__1__ is already jailed. + +[exp-commands_unjail] +description=Puts a player into jail and removes all other roles. +arg-player=Player to unjail. +unjailed=__1__ was unjailed by __2__. +not-jailed=__1__ is not currently jailed. + +[exp-commands_kill] +description=Kills yourself or another player. +arg-player=Player to kill. +already-dead=You are already dead. +lower-role=You must have a higher role than the target. + +[exp-commands_lawnmower] +description=Clean up biter corpse, decoratives and nuclear hole. +arg-range=Range to clean up. + +[exp-commands_locate] +description=Opens remote view at the location of the player's last location. +arg-player=Player to locate. +arg-remote=If true opens at the location of the player's remote view. +response=Last location of __1__ was [gps=__2__,__3__] + +[exp-commands_me] +description=Sends an action message in the chat. +arg-action=Action you want to perform. +response=* __1__ __2__ * + +[expcom-protection] +description-entity=Toggles entity protection selection, hold shift to remove protection +description-area=Toggles area protection selection, hold shift to remove protection +enter-entity-selection=Entered entity selection, select entites to protect, hold shift to remove protection. +enter-area-selection=Entered area selection, select areas to protect, hold shift to remove protection. +exit-entity=Exited entity protection selection. +exit-area=Exited area protect selection. +protected-entities=__1__ entities have been protected. +unprotected-entities=__1__ entities have been unprotected. +already-protected=This area is already protected. +protected-area=This area is now protected. +unprotected-area=This area is now unprotected. +repeat-offence=__1__ has removed __2__ at [gps=__3__,__4__] + +[exp-commands_protected-tags] +description=Toggles protected tag mode, edit and create protected map tags. +exit=You have left protected tag mode, any new tags will not be protected. +enter=You have entered protected tag mode, any new tags will be protected. +create=You have placed a protected tag. +edit=You have edited a protected tag. +revert-has-access=This tag is protected, use /__1__ to modify or remove. +revert-no-access=This tag is protected, you can not modify or remove it. + +[exp-commands_rainbow] +description=Sends an rainbow message in the chat +arg-message=Message to send in chat. +response=__1__: __2__ + +[exp-commands_ratio] +description=This command will give the input and output ratios of the selected machine. Use the parameter for calculating the machines needed for that amount of items per second. +arg-items-per-second=Target items per second, defaults to output of a single machine. +not-selecting=Please select an entity with a recipe. +item-in=You need __1__ per second of [item=__2__]. +fluid-in=You need __1__ per second of [fluid=__2__]. +item-out=This will result in: __1__ [item=__2__] per second. +fluid-out=This will result in: __1__ [fluid=__2__] per second. +machine-count=And you will need __1__ machines (with the same speed as this one) for this. + +[exp-commands_repair] +description=Repairs entities on your force around you. +arg-range=Range to repair entities within. +# Intentional space left on the two lines below so they can be joined together. +response-revive=__1__ entities were revived. +response-heal=__1__ entities were healed. + +[exp-commands_reports] +description-create=Reports a player and notifies moderators +description-get=Gets a list of all reports that a player has on them. If no player then lists all players and the number of reports on them. +description-clear=Clears all reports from a player or just the report from one player. +arg-player-create=Player you want to report. +arg-player-get=Player to get the reports of. +arg-player-clear=Player to clear the reports of. +arg-reason=Reason you want to report this player. +arg-from-player=Only remove the report from this player. +player-immune=This player can not be reported. +self-report=You cannot report yourself. +response=__1__ was reported for __2__. +response-admin=__1__ was reported by __2__ for __3__. +already-reported=You can only report a player once, you can ask a moderator to clear this report. +not-reported=The player had no reports on them. +not-reported-by=The player had no reports on them from __1__. +reports-title=The following players have reports against them: +player-title=__1__ has __2__ __plural_for_parameter__2__{1=report|rest=reports}__ against them: +list-element=__1__: __2__ +removed-all=__1__ has has all of their reports removed by __2__. +removed=__1__ has a report removed by __2__. + +[exp-commands_research] +description-ares=Sets research to be automatically queued. +arg-state=State to set, default is to toggle. +auto-research=__1__ set auto research to __2__ +queue=[color=255, 255, 255] Research added to queue - [technology=__1__] - __2__[/color] + +[exp-commands_roles] +description-assign-role=Assigns a role to a player. +description-unassign-role=Unassigns a role from a player. +description-get=Get all roles that a player has, if no player provided it lists all roles. +arg-player-assign=Player to assign the role to. +arg-player-unassign=Player to unassign the role from. +arg-player-get=Player to get the roles of. +arg-role-assign=Role to assign to the player. +arg-role-unassign=Role to unasign from the player. +list-roles=All roles: __1__ +list-player=__2__ has: __1__ +list-element=__1__, + +[exp-commands_search] +description-search=Display players sorted by the quantity of an item held and playtime. +description-online=Display online players sorted by the quantity of an item held and playtime. +description-amount=Display players sorted by the quantity of an item held. +description-recent=Display players who hold an item sorted by join time. +invalid-item=No item was found with internal name __1__; try using rich text selection. +no-results=No players have [item=__1__] +title=Players found with [item=__1__]: +result=\n__1__) __2__ has __3__ items. (__4__) + +[exp-commands_spectate] +description-spectate=Toggles spectator mode. +description-follow=Start following a player in spectator. +arg-player=Player to start following. +follow-self=You can not follow yourself. + +[exp-commands_surface] +description-items=Clear all items on the ground. +description-blueprints=Clear all blueprints. +description-radius=Clear all blueprints in an radius around you. +arg-surface=Surface to clear on, default all. +arg-radis=Radius to clear. +items-surface=__1__ cleared all items on the ground of __2__. +items-all=__1__ cleared all items on the ground for all surfaces. +blueprints-surface=__1__ cleared all blueprints on __2__. +blueprints-all=__1__ cleared all blueprints for all surfaces. +blueprints-radius=__1__ cleared all blueprints in a __2__ radius around them on __3__. + +[exp-commands_trains] +description=Set All Trains to Automatic, does not effect trains with passengers. +arg-force=Force to set the trains for, default all. +arg-surface=Surface to set the trains for, default all. +response=__1__ set __2__ trains into automatic mode. + +[exp-commands_teleport] +description-teleport=Teleports a player to another player. +description-bring=Teleports a player to you. +description-goto=Teleports you to a player. +description-spawn=Teleport to spawn +arg-player-teleport=Player to teleport, if target is not given then you are teleported to this player. +arg-player-from=Player to teleported. +arg-player-to=Player who is the target. +unavailable=They was a problem teleporting you, likely no position found, please try again later. +same-player=Player can not be teleported to themselves. + +[exp-commands_vlayer] +description=Print all vlayer information. +title=VLayer Information: +result=__1__: __2__ + +[exp-commands_warnings] +description-create=Gives a warning to a player; may lead to automatic script action. +description-get=Gets the number of warnings a player has. If no player then lists all players and the number of warnings they have. +description-clear=Clears all warnings (and script warnings) from a player. +description-clear-script=Clears all script warnings from a player. +description-clear-last=Clears the last warning from a player. +arg-player-create=Player to give the warning to. +arg-player-get=Player to get the warning of, if not given all players are returned. +arg-player=clear=Player to clear the warnings of. +arg-reason=Reason the user is receiving a warning. +create=__1__ received a warning from __2__ for __3__. +player-title=__1__ has __2__ warnings and __3__/__4__ script warnings. +list-element-player=__1__: __2__ +warnings-title=The following players have warnings aginst them (and script warnings): +list-element=__1__: __2__ (__3__/__4__) +cleared=__1__ had all their warnings cleared by __2__. +cleared-script=__1__ had all their script warnings cleared by __2__. +cleared-last=__1__ had their last warning cleared by __2__. + +[exp-commands_waterfill] +description=Replace tiles with shallow water. +requires-explosives=__ITEM__cliff-explosives__ are required to create water. +enter=Entered waterfill selection mode, select the area to fill with water. +exit=Exited water fill seclection mode. +nauvis-only=Can only waterfill on Nauvis, this may change in the future. +area-too-large=Selected area is too large, must be less than __1__ tiles, selected __2__. +too-few-explosives=Requires __1__ __ITEM__cliff-explosives__ you have __2__. +part-complete=__1__ tiles were filled with water, but entities are blocking __2__ tiles. +complete=__1__ tiles were filled with water.